matplotlib - 黑白色图(带破折号,点等)

eud*_*xos 34 matplotlib color-mapping

我使用matplotlib创建2d线图.出于发布的目的,我想将这些图分为黑白(不是灰度),我正在努力寻找一种非侵入性的解决方案.

Gnuplot会自动改变不同线条的划线模式,与matplotlib类似吗?

Yan*_*ann 48

下面我提供了将彩色线转换为具有独特风格的黑线的功能.我的快速测试显示,经过7行,颜色重复.如果情况并非如此(我犯了一个错误),则需要对COLORMAP提供的例程中的"常量" 进行微调.

这是例程和示例:

import matplotlib.pyplot as plt
import numpy as np

def setAxLinesBW(ax):
    """
    Take each Line2D in the axes, ax, and convert the line style to be 
    suitable for black and white viewing.
    """
    MARKERSIZE = 3

    COLORMAP = {
        'b': {'marker': None, 'dash': (None,None)},
        'g': {'marker': None, 'dash': [5,5]},
        'r': {'marker': None, 'dash': [5,3,1,3]},
        'c': {'marker': None, 'dash': [1,3]},
        'm': {'marker': None, 'dash': [5,2,5,2,5,10]},
        'y': {'marker': None, 'dash': [5,3,1,2,1,10]},
        'k': {'marker': 'o', 'dash': (None,None)} #[1,2,1,10]}
        }


    lines_to_adjust = ax.get_lines()
    try:
        lines_to_adjust += ax.get_legend().get_lines()
    except AttributeError:
        pass

    for line in lines_to_adjust:
        origColor = line.get_color()
        line.set_color('black')
        line.set_dashes(COLORMAP[origColor]['dash'])
        line.set_marker(COLORMAP[origColor]['marker'])
        line.set_markersize(MARKERSIZE)

def setFigLinesBW(fig):
    """
    Take each axes in the figure, and for each line in the axes, make the
    line viewable in black and white.
    """
    for ax in fig.get_axes():
        setAxLinesBW(ax)

xval = np.arange(100)*.01

fig = plt.figure()
ax = fig.add_subplot(211)

ax.plot(xval,np.cos(2*np.pi*xval))
ax.plot(xval,np.cos(3*np.pi*xval))
ax.plot(xval,np.cos(4*np.pi*xval))
ax.plot(xval,np.cos(5*np.pi*xval))
ax.plot(xval,np.cos(6*np.pi*xval))
ax.plot(xval,np.cos(7*np.pi*xval))
ax.plot(xval,np.cos(8*np.pi*xval))

ax = fig.add_subplot(212)
ax.plot(xval,np.cos(2*np.pi*xval))
ax.plot(xval,np.cos(3*np.pi*xval))
ax.plot(xval,np.cos(4*np.pi*xval))
ax.plot(xval,np.cos(5*np.pi*xval))
ax.plot(xval,np.cos(6*np.pi*xval))
ax.plot(xval,np.cos(7*np.pi*xval))
ax.plot(xval,np.cos(8*np.pi*xval))

fig.savefig("colorDemo.png")
setFigLinesBW(fig)
fig.savefig("bwDemo.png")
Run Code Online (Sandbox Code Playgroud)

这提供了以下两个图:第一个颜色: 在此输入图像描述 然后是黑白的: 在此输入图像描述

您可以调整每种颜色转换为样式的方式.如果您只想使用短划线样式( - .与 - 相对于您想要的任何模式),请将COLORMAP相应的"标记"值设置为None并调整"破折号"模式,反之亦然.

例如,字典中的最后一种颜色是'k'(黑色); 最初我只有一个虚线图案[1,2,1,10],对应于一个显示的像素,两个没有,一个显示,10个没有,这是一个点 - 点 - 空间图案.然后我评论说,将短划线设置为(无,无),这是一种非常正式的实线说法,并为圆圈添加了标记"o".

我还设置了一个'常量'MARKERSIZE,它将设置每个标记的大小,因为我发现默认大小有点大.

当你的线条已经有一个破折号或标记模式时,这显然无法处理,但你可以使用这些例程作为构建更复杂的转换器的起点.例如,如果原始绘图有红色实线和红色虚线,它们都会变成带有这些例程的黑色点划线.使用它们时要记住的一些事项.

  • ``for line in ax.get_lines()+ ax.get_legend().get_lines():``将循环更改为上面的行以更改图例. (3认同)
  • 当没有图例时,`ax.get_legend()`在matplotlib 1.3.1中返回`None`,这使我上面的例子失败了.不过,快速修复后很棒,谢谢! (2认同)

gbo*_*ffi 8

TL; DR

import matplotlib.pyplot as plt
from cycler import cycler
monochrome = (cycler('color', ['k']) * cycler('marker', ['', '.']) *
              cycler('linestyle', ['-', '--', ':', '=.']))
plt.rc('axes', prop_cycle=monochrome)
Run Code Online (Sandbox Code Playgroud)

扩展答案

较新的matplotlib版本引入了一个新的rcParams,即axes.prop_cycle

In [1]: import matplotlib.pyplot as plt

In [2]: plt.rcParams['axes.prop_cycle']
Out[2]: cycler('color', ['b', 'g', 'r', 'c', 'm', 'y', 'k'])
Run Code Online (Sandbox Code Playgroud)

对于precanned风格,可通过plt.style.use(...)或者with plt.style.context(...):,将prop_cycle等同于传统和过时 axes.color_cycle

In [3]: plt.rcParams['axes.color_cycle']
/.../__init__.py:892: UserWarning: axes.color_cycle is deprecated and replaced with axes.prop_cycle; please use the latter.
  warnings.warn(self.msg_depr % (key, alt_key))
Out[3]: ['b', 'g', 'r', 'c', 'm', 'y', 'k']
Run Code Online (Sandbox Code Playgroud)

但是该cycler对象具有更多的可能性,特别是复合体cycler可以由更简单的复合体组成,指的是不同的属性,使用+*分别表示拉链和笛卡尔积.

这里我们导入cycler辅助函数,我们定义3个cycler引用不同属性的简单函数,最后使用笛卡尔积来构造它们

In [4]: from cycler import cycler
In [5]: color_c = cycler('color', ['k'])
In [6]: style_c = cycler('linestyle', ['-', '--', ':', '-.'])
In [7]: markr_c = cycler('marker', ['', '.', 'o'])
In [8]: c_cms = color_c * markr_c * style_c
In [9]: c_csm = color_c * style_c * markr_c
Run Code Online (Sandbox Code Playgroud)

这里我们有两个不同的(?)复合体cycler,是的,它们是不同的,因为这个操作是非交换的,看看

In [10]: for d in c_csm: print('\t'.join(d[k] for k in d))
-               k
-       .       k
-       o       k
--              k
--      .       k
--      o       k
:               k
:       .       k
:       o       k
-.              k
-.      .       k
-.      o       k

In [11]: for d in c_cms: print('\t'.join(d[k] for k in d))
-               k
--              k
:               k
-.              k
-       .       k
--      .       k
:       .       k
-.      .       k
-       o       k
--      o       k
:       o       k
-.      o       k
Run Code Online (Sandbox Code Playgroud)

更快变化的元素周期是产品中的最后一个,等等,如果我们想要线条样式中的某个顺序,这很重要.

如何使用cyclers 的组成?通过的手段plt.rc,或者修改的等价方式rcParamsmatplotlib.例如,

In [12]: %matplotlib
Using matplotlib backend: Qt4Agg
In [13]: import numpy as np
In [14]: x = np.linspace(0, 8, 101)
In [15]: y = np.cos(np.arange(7)+x[:,None])
In [16]: plt.rc('axes', prop_cycle=c_cms)
In [17]: plt.plot(x, y);
In [18]: plt.grid();
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

当然这仅仅是一个例子,OP可以混合和匹配不同的属性,以实现最令人愉悦的视觉输出.

PS我忘记提到这种方法会自动处理图例框中的线条样本, 在此输入图像描述