![](/img/trans.png)
[英]How to create a legend instead of a colorbar for a multicolored scatter plot?
[英]How to create a basic legend to a multicolored line?
我目前正在完成一个更大的项目,最后一部分是在彩色线条图中添加一个简单的图例。 该行仅包含两种不同的颜色。
该图显示了地球和火星之间随时间的距离。 在三月到八月的几个月中,该线为橙色,在其他月份中,该线为蓝色。 图例应该放在图的右上角的一个简单框中,其中显示每个所用颜色的标签。 喜欢的东西这将是很好的。
绘图的数据来自我称为master_array
的巨大矩阵。 在显示此问题所涉及的情节之前,它包含许多某些任务所需的更多信息。 对于我正在苦苦挣扎的情节,重要的是第0列,第1列和第6列,其中包含日期,相关日期的行星之间的距离,在第6列中,我设置了一个标志来确定给定的点是否属于“ 8月至8月” '是否设置( 0
表示9月至2月/“冬季”, 1
表示3月至8月/“夏季”)。 master_array
是一个numpy数组,dtype是float64
。 它包含大约45k数据点。
看起来像:
In [3]: master_array
Out[3]:
array([[ 1.89301010e+07, 1.23451036e+00, -8.10000000e+00, ...,
1.00000000e+00, 1.00000000e+00, 1.89300000e+03],
[ 1.89301020e+07, 1.24314818e+00, -8.50000000e+00, ...,
2.00000000e+00, 1.00000000e+00, 1.89300000e+03],
[ 1.89301030e+07, 1.25179997e+00, -9.70000000e+00, ...,
3.00000000e+00, 1.00000000e+00, 1.89300000e+03],
...,
[ 2.01903100e+07, 1.84236878e+00, 7.90000000e+00, ...,
1.00000000e+01, 3.00000000e+00, 2.01900000e+03],
[ 2.01903110e+07, 1.85066892e+00, 5.50000000e+00, ...,
1.10000000e+01, 3.00000000e+00, 2.01900000e+03],
[ 2.01903120e+07, 1.85894904e+00, 9.40000000e+00, ...,
1.20000000e+01, 3.00000000e+00, 2.01900000e+03]])
这是获取我在开始时描述的图的功能:
def md_plot3(dt64=np.array, md=np.array, swFilter=np.array):
""" noch nicht fertig """
y, m, d = dt64.astype(int) // np.c_[[10000, 100, 1]] % np.c_[[10000, 100, 100]]
dt64 = y.astype('U4').astype('M8') + (m-1).astype('m8[M]') + (d-1).astype('m8[D]')
cmap = ListedColormap(['b','darkorange'])
plt.figure('zeitlich-global betrachtet')
plt.title("Marsdistanz unter Berücksichtigung der Halbjahre der steigenden und sinkenden Temperaturen",
loc='left', wrap=True)
plt.xlabel("Zeit in Jahren\n")
plt.xticks(rotation = 45)
plt.ylabel("Marsdistanz in AE\n(1 AE = 149.597.870,7 km)")
# plt.legend(loc='upper right', frameon=True) # worked formerly
ax=plt.gca()
plt.style.use('seaborn-whitegrid')
#convert dates to numbers first
inxval = mdates.date2num(dt64)
points = np.array([inxval, md]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)
lc = LineCollection(segments, cmap=cmap, linewidth=3)
# set color to s/w values
lc.set_array(swFilter)
ax.add_collection(lc)
loc = mdates.AutoDateLocator()
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(mdates.AutoDateFormatter(loc))
ax.autoscale_view()
在较大的脚本中,还有另一个函数(散点图)用于标记曲线的最小值和最大值,但是我想这在这里并不是那么重要。
我已经试过这导致一个传说,即显示了垂直彩条,只有一个标签,并在答案中描述这两个选项这个问题,因为它看起来更像是我的目标,但对于不能让它为我的情况下工作。
也许我应该补充一点,我只是python的初学者,这是我的第一个项目,所以我不熟悉matplotlib
的更深层次的功能,这可能是为什么我无法自定义上述答案以使其工作的原因。我的情况。
UPDATE
借助于用户ImportanceOfBeingErnest的帮助,我进行了一些改进:
import matplotlib.dates as mdates
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap
from matplotlib.lines import Line2D
def md_plot4(dt64=np.array, md=np.array, swFilter=np.array):
y, m, d = dt64.astype(int) // np.c_[[10000, 100, 1]] % np.c_[[10000, 100, 100]]
dt64 = y.astype('U4').astype('M8') + (m-1).astype('m8[M]') + (d-1).astype('m8[D]')
z = np.unique(swFilter)
cmap = ListedColormap(['b','darkorange'])
fig = plt.figure('Test')
plt.title("Test", loc='left', wrap=True)
plt.xlabel("Zeit in Jahren\n")
plt.xticks(rotation = 45)
plt.ylabel("Marsdistanz in AE\n(1 AE = 149.597.870,7 km)")
# plt.legend(loc='upper right', frameon=True) # worked formerly
ax=plt.gca()
plt.style.use('seaborn-whitegrid')
#plt.style.use('classic')
#convert dates to numbers first
inxval = mdates.date2num(dt64)
points = np.array([inxval, md]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)
lc = LineCollection(segments, array=z, cmap=plt.cm.get_cmap(cmap),
linewidth=3)
# set color to s/w values
lc.set_array(swFilter)
ax.add_collection(lc)
fig.colorbar(lc)
loc = mdates.AutoDateLocator()
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(mdates.AutoDateFormatter(loc))
ax.autoscale_view()
def make_proxy(zvalue, scalar_mappable, **kwargs):
color = scalar_mappable.cmap(scalar_mappable.norm(zvalue))
return Line2D([0, 1], [0, 1], color=color, **kwargs)
proxies = [make_proxy(item, lc, linewidth=2) for item in z]
ax.legend(proxies, ['Winter', 'Summer'])
plt.show()
md_plot4(dt64, md, swFilter)
+有什么好处:
好吧,它显示了一个图例,并根据标签显示了正确的颜色。
-还有哪些要优化的:
1)图例不在框中,并且图例的“线条”正在干扰绘图的底层。 如用户ImportanceOfBeingErnest所说,这是由于使用plt.style.use('seaborn-whitegrid')
。 因此,如果有一种将plt.style.use('seaborn-whitegrid')
与传奇风格的plt.style.use('classic')
使用的方法可能会有所帮助。 2)更大的问题是颜色栏。 我在原始代码中添加了fig.colorbar(lc)
行,以根据此答案实现所需的内容。
因此,我尝试了其他一些更改:
我使用plt.style.use('classic')
以我需要的方式获取了图例,但这plt.style.use('seaborn-whitegrid')
我损失了plt.style.use('seaborn-whitegrid')
的漂亮样式。 此外我禁用了colorbar
之前根据所提到的我加线答案 。
这就是我得到的:
import matplotlib.dates as mdates
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap
from matplotlib.lines import Line2D
def md_plot4(dt64=np.array, md=np.array, swFilter=np.array):
y, m, d = dt64.astype(int) // np.c_[[10000, 100, 1]] % np.c_[[10000, 100, 100]]
dt64 = y.astype('U4').astype('M8') + (m-1).astype('m8[M]') + (d-1).astype('m8[D]')
z = np.unique(swFilter)
cmap = ListedColormap(['b','darkorange'])
#fig =
plt.figure('Test')
plt.title("Test", loc='left', wrap=True)
plt.xlabel("Zeit in Jahren\n")
plt.xticks(rotation = 45)
plt.ylabel("Marsdistanz in AE\n(1 AE = 149.597.870,7 km)")
# plt.legend(loc='upper right', frameon=True) # worked formerly
ax=plt.gca()
#plt.style.use('seaborn-whitegrid')
plt.style.use('classic')
#convert dates to numbers first
inxval = mdates.date2num(dt64)
points = np.array([inxval, md]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)
lc = LineCollection(segments, array=z, cmap=plt.cm.get_cmap(cmap),
linewidth=3)
# set color to s/w values
lc.set_array(swFilter)
ax.add_collection(lc)
#fig.colorbar(lc)
loc = mdates.AutoDateLocator()
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(mdates.AutoDateFormatter(loc))
ax.autoscale_view()
def make_proxy(zvalue, scalar_mappable, **kwargs):
color = scalar_mappable.cmap(scalar_mappable.norm(zvalue))
return Line2D([0, 1], [0, 1], color=color, **kwargs)
proxies = [make_proxy(item, lc, linewidth=2) for item in z]
ax.legend(proxies, ['Winter', 'Summer'])
plt.show()
md_plot4(dt64, md, swFilter)
+有什么好处:
它以我需要的方式显示了传说。
它不再显示颜色条。
-要优化的是:
该图不再是彩色的。
传说都不是。
正如我之前解释的那样, classic
风格不是我想要的。
因此,如果有人有好的建议,请告诉我!
我正在使用numpy版本1.16.2和matplotlib版本3.0.3
要在matplotlib中获取多色图,请标记图,然后调用legend()
函数。 以下示例代码摘自link ,但是随着链接断开,这是帖子。
这里使用的图表是一条线,但是相同的原理也适用于其他图表类型,正如您从其他SO答案中可以看到的那样
import matplotlib.pyplot as plt
import numpy as np
y = [2,4,6,8,10,12,14,16,18,20]
y2 = [10,11,12,13,14,15,16,17,18,19]
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
ax.plot(x, y, label='$y = numbers')
ax.plot(x, y2, label='$y2 = other numbers')
plt.title('Legend inside')
ax.legend()
plt.show()
此代码将显示以下图像(图表中带有图例)
希望这可以帮助
因此,这是如何为多色线创建基本图例的答案,该图例包含每种使用的颜色的多个标签并且在图旁边不显示色条(标准色条,图例中没有内容;有关更多信息,请参阅原始问题的更新)问题):
由于很多有益的意见,我想出了一个规范添加到LineCollection()
以避免通过禁用取出彩条时monocolored线结束了fig.colorbar()
另见本 )的附加参数(在这种情况下,要添加的“范数”是norm=plt.Normalize(z.min(), z.max())
,其中z
是一个数组,其中包含负责各部分颜色的信息。 请注意, z
只需为每种不同的颜色保留一个元素。 这就是为什么我将包含每个数据点一个标志的swFilter
数组包装到np.unique()
。
进去一箱没有接触适当的传说plt.style.use()
我根本就向右参数添加到ax.legend()
在我的情况下,一个简单的frameon=True
完成了这项工作。
这是代码:
import matplotlib.dates as mdates
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap
from matplotlib.lines import Line2D
def md_plot4(dt64=np.array, md=np.array, swFilter=np.array):
y, m, d = dt64.astype(int) // np.c_[[10000, 100, 1]] % np.c_[[10000, 100, 100]]
dt64 = y.astype('U4').astype('M8') + (m-1).astype('m8[M]') + (d-1).astype('m8[D]')
z = np.unique(swFilter)
cmap = ListedColormap(['b','darkorange'])
#fig =
plt.figure('Test')
plt.title("Marsdistanz unter Berücksichtigung der Halbjahre der steigenden und sinkenden Temperaturen\n",
loc='left', wrap=True)
plt.xlabel("Zeit in Jahren\n")
plt.xticks(rotation = 45)
plt.ylabel("Marsdistanz in AE\n(1 AE = 149.597.870,7 km)")
plt.tight_layout()
ax=plt.gca()
plt.style.use('seaborn-whitegrid')
#convert dates to numbers first
inxval = mdates.date2num(dt64)
points = np.array([inxval, md]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)
lc = LineCollection(segments, array=z, cmap=plt.cm.get_cmap(cmap),
linewidth=3, norm=plt.Normalize(z.min(), z.max()))
# set color to s/w values
lc.set_array(swFilter)
ax.add_collection(lc)
loc = mdates.AutoDateLocator()
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(mdates.AutoDateFormatter(loc))
ax.autoscale_view()
def make_proxy(zvalue, scalar_mappable, **kwargs):
color = scalar_mappable.cmap(scalar_mappable.norm(zvalue))
return Line2D([0, 1], [0, 1], color=color, **kwargs)
proxies = [make_proxy(item, lc, linewidth=2) for item in z]
ax.legend(proxies, ['Halbjahr der sinkenden \nTemperaturen',
'Halbjahr der steigenden \nTemperaturen'], frameon=True)
plt.show()
md_plot4(dt64, md, swFilter)
请注意,我添加了plt.tight_layout()
以确保在窗口模式下显示图的标题和轴的描述而没有任何截断。
现在的新问题 (由于添加了tight_layout()
而导致)是,图被水平压缩,即使图的右侧(调用时显示tight_layout()
有很多可用空间。
这需要另一个修复程序,但目前我不知道如何解决。 因此,如果有人知道如何在窗口模式下阻止图形标题和坐标轴的描述,请在此处发表评论,我将不胜感激。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.