DIN*_*970 5 python matplotlib legend
我尝试在Matplotlib中绘制具有以下特征的数据:
数据可以细分为10个不同的组.我想用独特的标记形状绘制每个组.
每组可以再次细分为两种类型.我想区分我的情节中的两种类型与填充的经文相同形状的空标记.每个组细分为相同的两种类型.
为了使我的传奇更优雅,而不仅仅是所有不同标记类型的列表,我希望它看起来像:
|------------|Type 1-------| Type 2------|
|Group 1 | fil. mark 1 | empty mark 1|
|Group 2 | fil. mark 2 | empty mark 2|
Run Code Online (Sandbox Code Playgroud)
...
Matplotlib可以实现吗?
小智 4
我无法找到一个优雅的解决方案来解决你的问题,但知道如何通过一些技巧来做到这一点。
方法一
显而易见的选择是制作一个包含 3 列的图例。如果我们假设图例是一个表格,那么我们需要一个标题 - 第一行,我们在其中添加列名称。图例是逐列填充补丁,而不是逐行填充。为了处理这种行为,我们将为每个图例的列创建三个单独的列表并向它们添加补丁。然后连接所有三个列表并将最终的补丁列表添加到图例中。
生成该图像的代码如下
from random import random
import matplotlib.patches as m_patches
import matplotlib.pyplot as plt
groups = [{'Type 1': [i+random() for _ in range(25)], 'Type 2': [i+random() for _ in range(25)]} for i in range(10)]
markers = ['o', 'v', '^', '<', '>', '8', 's', 'p', '*', 'h']
colors = ['r', 'g', 'b', 'salmon', 'lime', 'purple', 'cyan', 'gold', 'peru', 'gray']
def main():
# Make legend with 3 columns:
# First column for group number, seconds on for Type 1 lines, and third for Type 2 lines
n_cols = 3
# Figure size
fig_width = 13
fig_height = 7
# Axis location
# Note that width must be lower than 1 so we could add legend to the right from a plot
ax_left, ax_bottom = 0.1, 0.1
ax_width, ax_height = 0.6, 0.8
# Make a figure
plt.figure(figsize=(fig_width, fig_height))
# Create axes
ax = plt.axes([ax_left, ax_bottom, ax_width, ax_height])
# Since we are going to create a custom legend, create a list of patches for each column
patches_column1 = [m_patches.Patch(color="w", label=f'')]
patches_column2 = [m_patches.Patch(color="none", label=f'Type 1')]
patches_column3 = [m_patches.Patch(color="none", label=f'Type 2')]
for i, (group, color, marker) in enumerate(zip(groups, colors, markers)):
l1, = ax.plot(group['Type 1'], f"{marker}-", color=color, label=f"Fill")
l2, = ax.plot(group['Type 2'], f"{marker}-", color=color, label=f"Empty", markerfacecolor='none')
# First column contains a 'group' info patch
patches_column1.append(m_patches.Patch(color='none', label=f'Group {i}'))
# Second column contains patches with lines of Type 1
patches_column2.append(l1)
# Third column contains patches with lines of Type 2
patches_column3.append(l2)
# Now we need to merge all three lists together and add the final list to a legend
patches = list()
patches.extend(patches_column1)
patches.extend(patches_column2)
patches.extend(patches_column3)
ax.legend(loc='upper left',
bbox_to_anchor=(1.0, 0.0, 1, 1),
ncol=n_cols, handles=patches)
plt.savefig("fig1", dpi=200, facecolor='w', edgecolor='w',
orientation='portrait', papertype=None, format=None,
transparent=False, bbox_inches=None, pad_inches=0.1,
frameon=None, metadata=None)
plt.show()
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
但是,您将在图例上看到Fill和标签。Empty我找不到一种简单的方法来去除它们,但找到了一种丑陋的方法。
方法二
这与方法 1相同,只是现在我们要对图例上的标记和文本进行一些操作。
首先,我们需要向legend()构造函数添加一个附加参数:
handletextpad=-2.5。此参数将移动标记并将其放置在大约列的中间。现在我们需要隐藏与每个行标记(“填充”和“空”)相对应的文本。为此,我们将从图例中获取所有文本对象,并根据我们想要隐藏的内容将其颜色更新为'black'或。'none'结果你应该得到这样的结果:
完整代码如下
from random import random
import matplotlib.patches as m_patches
import matplotlib.pyplot as plt
groups = [{'Type 1': [i+random() for _ in range(25)], 'Type 2': [i+random() for _ in range(25)]} for i in range(10)]
markers = ['o', 'v', '^', '<', '>', '8', 's', 'p', '*', 'h']
colors = ['r', 'g', 'b', 'salmon', 'lime', 'purple', 'cyan', 'gold', 'peru', 'gray']
def main():
# Make legend with 3 columns:
# First column for group number, seconds on for Type 1 lines, and third for Type 2 lines
n_cols = 3
# Figure size
fig_width = 10
fig_height = 7
# Axis location
# Note that width must be lower than 1 so we could add legend to the right from a plot
ax_left, ax_bottom = 0.1, 0.1
ax_width, ax_height = 0.65, 0.8
# Make a figure
plt.figure(figsize=(fig_width, fig_height))
# Create axes
ax = plt.axes([ax_left, ax_bottom, ax_width, ax_height])
# Since we are going to create a custom legend, create a list of patches for each column
patches_column1 = [m_patches.Patch(color="w", label=f'')]
patches_column2 = [m_patches.Patch(color="none", label=f'Type 1')]
patches_column3 = [m_patches.Patch(color="none", label=f'Type 2')]
for i, (group, color, marker) in enumerate(zip(groups, colors, markers)):
l1, = ax.plot(group['Type 1'], f"{marker}-", color=color, label="Filled")
l2, = ax.plot(group['Type 2'], f"{marker}-", color=color, markerfacecolor='none', label="Empty")
# First column contains a 'group' info patch
patches_column1.append(m_patches.Patch(color='none', label=f'Group {i}'))
# Second column contains patches with lines of Type 1
patches_column2.append(l1)
# Third column contains patches with lines of Type 2
patches_column3.append(l2)
# Now we need to merge all three lists together and add the final list to a legend
patches = list()
patches.extend(patches_column1)
patches.extend(patches_column2)
patches.extend(patches_column3)
# If you plan to
lg = ax.legend(loc='upper left',
bbox_to_anchor=(1.0, 0.0, 1, 1),
ncol=n_cols,
handles=patches,
handletextpad=-2.5,
borderpad=1.0)
for i, text in enumerate(lg.get_texts()):
if i < 11:
pass
elif i == 11:
text.set_color('black')
elif 12 <= i < 22:
text.set_color('none')
elif i == 22:
text.set_color('black')
else:
text.set_color('none')
plt.savefig("fig2", dpi=200, facecolor='w', edgecolor='w',
orientation='portrait', papertype=None, format=None,
transparent=False, bbox_inches=None, pad_inches=0.1,
frameon=None, metadata=None)
plt.show()
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)