【问题标题】:Matplotilb - How to set colorbar for line plot with log scaleMatplotlib - 如何为具有对数刻度的线图设置颜色条
【发布时间】:2019-02-04 09:28:59
【问题描述】:

我在将颜色条添加到对应于幂律的多行图中时遇到问题。

为了为非图像图创建颜色条,我添加了一个虚拟图(来自此处的答案:Matplotlib - add colorbar to a sequence of line plots)。

到颜色条的刻度不对应于绘图的颜色。

我已尝试更改颜色条的规范,并且可以对其进行微调以使其在特定情况下保持准确,但通常我不能这样做。

def plot_loglog_gauss():
    from matplotlib import cm as color_map
    import matplotlib as mpl

    """Creating the data"""
    time_vector = [0, 1, 2, 4, 8, 16, 32, 64, 128, 256]
    amplitudes = [t ** 2 * np.exp(-t * np.power(np.linspace(-0.5, 0.5, 100), 2)) for t in time_vector]

    """Getting the non-zero minimum of the data"""
    data = np.concatenate(amplitudes).ravel()
    data_min = np.min(data[np.nonzero(data)])

    """Creating K-space data"""
    k_vector = np.linspace(0,1,100)

    """Plotting"""
    number_of_plots = len(time_vector)
    color_map_name = 'jet'
    my_map = color_map.get_cmap(color_map_name)
    colors = my_map(np.linspace(0, 1, number_of_plots, endpoint=True))

    # plt.figure()
    # dummy_plot = plt.contourf([[0, 0], [0, 0]], time_vector, cmap=my_map)
    # plt.clf()

    norm = mpl.colors.Normalize(vmin=time_vector[0], vmax=time_vector[-1])
    cmap = mpl.cm.ScalarMappable(norm=norm, cmap=color_map_name)
    cmap.set_array([])


    for i in range(number_of_plots):
        plt.plot(k_vector, amplitudes[i], color=colors[i], label=time_vector[i])

    c = np.arange(1, number_of_plots + 1)
    plt.xlabel('Frequency')
    plt.ylabel('Amplitude')
    plt.yscale('symlog', linthreshy=data_min)
    plt.xscale('log')
    plt.legend(loc=3)

    ticks = time_vector
    plt.colorbar(cmap, ticks=ticks, shrink=1.0, fraction=0.1, pad=0)

    plt.show()

通过与图例进行比较,您会发现刻度值与实际颜色不匹配。例如,128 在颜色图中显示为绿色,而在图例中显示为红色。

实际结果应该是一个线性颜色的颜色条。在颜色条上以规则的间隔带有刻度(对应于不规则的时间间隔......)。当然,正确的颜色是刻度值。

(最终该图包含许多图(len(time_vector) ~ 100),我降低了图的数量来说明并能够显示图例。)

澄清一下,这就是我想要的结果。

【问题讨论】:

  • 小修正 - 1,2,4,8,16,32,64 ,128,256
  • 是的。更新了代码和图片。
  • 链接问题中接受的答案没有用。你考虑过其他答案吗?
  • @ImportanceOfBeingErnest:当您撰写此评论时,我正在准备解决方案。确实,我正要说同样的话
  • 是的,我尝试了所有这些答案,但无法让它们中的任何一个起作用。

标签: python matplotlib colormap


【解决方案1】:

最重要的原则是保持线图中的颜色和ScalarMappable 同步。这意味着,线条的颜色不应取自独立的颜色列表,而应取自相同的颜色图并使用与要显示的颜色条相同的规范化。

然后一个主要问题是决定如何处理0,它不能成为对数归一化的一部分。以下是一种解决方法,假设线性比例介于 0 和 2 之间,并且使用 SymLogNorm 在上面的对数比例。

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

"""Creating the data"""
time_vector = [0, 1, 2, 4, 8, 16, 32, 64, 128, 256]
amplitudes = [t ** 2 * np.exp(-t * np.power(np.linspace(-0.5, 0.5, 100), 2)) for t in time_vector]

"""Getting the non-zero minimum of the data"""
data = np.concatenate(amplitudes).ravel()
data_min = np.min(data[np.nonzero(data)])

"""Creating K-space data"""
k_vector = np.linspace(0,1,100)

"""Plotting"""
cmap = plt.cm.get_cmap("jet")
norm = mpl.colors.SymLogNorm(2, vmin=time_vector[0], vmax=time_vector[-1])

sm = mpl.cm.ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([])

for i in range(len(time_vector)):
    plt.plot(k_vector, amplitudes[i], color=cmap(norm(time_vector[i])), label=time_vector[i])

#c = np.arange(1, number_of_plots + 1)
plt.xlabel('Frequency')
plt.ylabel('Amplitude')
plt.yscale('symlog', linthreshy=data_min)
plt.xscale('log')
plt.legend(loc=3)

cbar = plt.colorbar(sm, ticks=time_vector, format=mpl.ticker.ScalarFormatter(), 
                    shrink=1.0, fraction=0.1, pad=0)

plt.show()

【讨论】:

  • 看起来不错。非常感谢!我仍然想知道如果间距是单调的但不受幂律(或任何定律)支配,会发生什么情况。我在想如何以某种方式通过颜色而不是值来放置刻度。再次感谢。
  • 如果没有函数关系,你宁愿使用离散的颜色条,对吧?如in this answer。 (当然,如果只使用足够的颜色,任何离散的颜色条都会看起来是连续的,以防仍然需要。)
  • 天哪。我是如此接近。我正在尝试PowerNormgamma=2norm。我会删除我无用的答案
  • 这里提供的解决方案不是“用 linspace 拉动”。但如果你想这样做,我把你推荐给this answer
  • 是的,你可以。在这种情况下,这就是 format 的用途。您可以将其替换为您喜欢的任何其他格式化程序。
猜你喜欢
  • 2013-02-21
  • 1970-01-01
  • 2017-01-22
  • 2013-08-14
  • 1970-01-01
  • 2013-09-13
  • 1970-01-01
  • 2016-02-13
  • 1970-01-01
相关资源
最近更新 更多