【问题标题】:matplotlib - black & white colormap (with dashes, dots etc)matplotlib - 黑白颜色图(带有破折号、圆点等)
【发布时间】:2011-11-13 13:26:50
【问题描述】:

我正在使用 matplotlib 创建二维线图。出于发布的目的,我希望这些图是黑白的(不是灰度),我正在努力寻找一种非侵入性的解决方案。

Gnuplot 自动改变不同线条的虚线模式,matplotlib 是否可以实现类似的功能?

【问题讨论】:

    标签: matplotlib color-mapping


    【解决方案1】:

    下面我提供了将彩色线条转换为具有独特风格的黑色线条的功能。我的快速测试表明,在 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")
    

    这提供了以下两个图: 颜色第一: 然后是黑白的:

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

    例如,字典中的最后一个颜色是'k'(黑色);最初我只有一个虚线图案[1,2,1,10],对应显示一个像素,两个不显示,一个显示,10 个不显示,这是一个点-点-空间图案。然后我将其注释掉,将破折号设置为(无,无),这是一种非常正式的实线表达方式,并添加了标记“o”,表示圆圈。

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

    这显然不能处理线条已经有破折号或标记模式的情况,但您可以使用这些例程作为起点来构建更复杂的转换器。例如,如果您的原始绘图有一条红色实线和一条红色虚线,则它们都会在这些例程中变成黑色点划线。使用它们时要注意的事项。

    【讨论】:

    • for line in ax.get_lines() + ax.get_legend().get_lines(): 将循环更改为上述行也可以更改图例。
    • 当没有图例时,ax.get_legend() 在 matplotlib 1.3.1 中返回 None,这使得上面的示例对我来说失败了。但是,快速修复后效果很好,非常感谢!
    • 很好的答案,@Yann!我刚刚在修改要发表的论文时遇到了这个问题,很高兴有一个现成的答案来适应我的情况。
    • @Yann:非常感谢您的精彩回答!但是您是否可以包括以下内容:try: lines_to_cycle = ax.get_lines() + ax.get_legend().get_lines() except AttributeError: lines_to_cycle = ax.get_lines() for line in lines_to_cycle: 由于 Abraham D Flaxman 提到的原因。
    • 你好,我怎样才能绘制一个填充颜色的标记和黑色的边框?
    【解决方案2】:

    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)
    ... 
    

    扩展答案

    较新的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'])
    

    对于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']
    

    但是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
    

    这里我们有两个不同的(?)复数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
    

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

    cyclers的组合怎么用?通过plt.rc,或者等效的方式修改matplotlibrcParams。例如,

    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();
    

    当然这只是一个例子,OP可以混合搭配不同的属性来达到最赏心悦目的视觉输出。

    PS 我忘了提到这种方法会自动处理图例框中的线条样本,

    【讨论】:

    • 这太干净了。
    【解决方案3】:

    我确实大量使用了 Yann 的代码,但今天我阅读了来自 Can i cycle through line styles in matplotlib 的答案,所以现在我将以这种方式制作我的 BW 图:

    import pylab as plt
    from itertools import cycle
    lines = ["k-","k--","k-.","k:"]
    linecycler = cycle(lines)
    plt.figure()
    for i in range(4):
        x = range(i,i+10)
        plt.plot(range(10),x,next(linecycler))
    plt.show()
    

    【讨论】:

      【解决方案4】:

      plot(x,y,'k-.') 之类的东西会产生黑色 ('k') 点划线 ('-.')。这不是你要找的吗?

      【讨论】:

      • 真的,我必须手动为每个绘图和数据集设置它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-30
      • 2017-09-17
      • 2012-02-12
      • 1970-01-01
      • 2016-09-18
      • 2011-07-26
      • 1970-01-01
      相关资源
      最近更新 更多