python - Matplotlib:条形顶部的线条,左侧的图例,没有样条线
问题描述
我无法调整下面的图表。
数据框如下所示:
Year Some All Ratio
0 2016 9 157 0.057325
1 2017 13 189 0.068783
2 2018 21 216 0.097222
3 2019 18 190 0.094737
4 2020 28 284 0.098592
这是我想要做的:
- 橙色线应该在条的前面。我尝试使用该
zorder
参数,但没有帮助。我也尝试切换轴对象的顺序,但我无法将线分配给主轴。 - 我想要左边的图例。您会在下面的代码中注意到我使用了一个有点大的
figsize
参数。如果我使用较小的,图例会神奇地向左移动,但我不想使用较小的。 - 我想用相应的值标记每个条形图顶部的条形图。我尝试迭代每个值并用 单独注释条
ax.annotate
,但我无法自动将值居中。在这个最小的例子中,所有的值都是三位数长,但在原始数据中,我有四位数长的数字,我找不到一个好方法让它在所有这些数字中居中。 - 最后,我想摆脱顶部和右侧的刺。我下面的代码由于某种原因没有删除它们。
帮助人们入门的代码如下。
data = {'Year': {0: '2016', 1: '2017', 2: '2018', 3: '2019', 4: '2020'},
'Some': {0: 9, 1: 13, 2: 21, 3: 18, 4: 28},
'All': {0: 157, 1: 189, 2: 216, 3: 190, 4: 284},
'Ratio': {0: 0.05732484076433121,
1: 0.06878306878306878,
2: 0.09722222222222222,
3: 0.09473684210526316,
4: 0.09859154929577464}}
df = __import__("pandas").DataFrame(data)
ax = df.plot(x="Year", y="Ratio",
kind="line", linestyle='-', marker='o', color="orange",
figsize=((24,12))
)
df.plot(x="Year", y="All",
kind="bar", ax=ax, secondary_y=True
)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
解决方案
你问了很多事情。
- 要在条形图的顶部绘制线条,似乎我们必须先绘制条形图,然后再绘制线条。最后画线会缩小 xlim,所以我们必须明确地应用它们。
- 移动图例更复杂。通常你只是这样做
ax1.legend(loc='upper left')
,但在我们的情况下,有两个图,这似乎总是绘制第二个图例,最后绘制的图作为唯一条目。 - 有一个文档
set_bbox_to_anchor
很少的功能。它定义了一些盒子 (x, y, width, height),但还有一个看似不可访问的参数控制盒子和位置的关系。“默认值是在使用 bbox_to_anchor 参数时给出不可预测的结果。” 可能需要进行一些实验。最好的办法,就是守护loc
loc
loc="best"
- 设置文本很简单。只需遍历 y 位置。放置在 x 位置 0,1,2,.. 并水平居中(垂直位于底部)。
- 要移除刺,似乎有两个轴相互重叠(这也可能导致
zorder
无法按预期工作)。你会想要隐藏他们两个的脊椎。 - 要删除刻度,请使用
ax1.axes.yaxis.set_ticks([])
. - 要将 ax2 刻度切换到左侧,请使用
ax2.yaxis.tick_left()
.
import pandas as pd
from matplotlib import pyplot as plt
data = {'Year': {0: '2016', 1: '2017', 2: '2018', 3: '2019', 4: '2020'},
'Some': {0: 9, 1: 13, 2: 21, 3: 18, 4: 28},
'All': {0: 157, 1: 189, 2: 216, 3: 190, 4: 284},
'Ratio': {0: 0.05732484076433121,
1: 0.06878306878306878,
2: 0.09722222222222222,
3: 0.09473684210526316,
4: 0.09859154929577464}}
df = pd.DataFrame(data)
ax1 = df.plot(x="Year", y="All",
kind="bar",
)
for i, a in df.All.items():
ax1.text(i, a, str(a), ha='center', va='bottom', fontsize=18)
xlims = ax1.get_xlim()
ax2 = df.plot(x="Year", y="Ratio",
kind="line", linestyle='-', marker='o', color="orange", ax=ax1, secondary_y=True,
figsize=((24, 12))
)
ax2.set_xlim(xlims) # needed because the line plot shortens the xlims
# ax1.get_legend().set_bbox_to_anchor((0.03, 0.9, 0.1, 0.1)) # unpredictable behavior when loc='best'
# ax1.legend(loc='upper left') # in our case, this would create a second legend
ax1.get_legend().remove() # remove badly placed legend
handles1, labels1 = ax1.get_legend_handles_labels()
handles2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(handles=handles1 + handles2, # create a new legend
labels=labels1 + labels2,
loc='upper left')
# ax1.yaxis.tick_right() # place the yticks for ax1 at the right
ax2.yaxis.tick_left() # place the yticks for ax2 at the left
ax2.set_ylabel('Ratio')
ax2.yaxis.set_label_position('left')
ax1.axes.yaxis.set_ticks([]) # remove ticks
for ax in (ax1, ax2):
for where in ('top', 'right'):
ax.spines[where].set_visible(False)
plt.show()
推荐阅读
- python - Python 3、Tkinter GUI、Juniper Switch DevOps 任务
- c# - VSCode Mac 上的 DotNet 实体框架 -- (Table)Exists() 在 Controller 的当前上下文中不存在
- arrays - 使用readarray时如何避免数组元素后的换行符?
- c# - '不存在数据时尝试读取无效。'
- python - 在参数中设置一个列表以从 python 调用 API
- apache-spark - 如何将每个 user_id 第一行的列中的值复制到相同 user_id 的第二行
- python-3.x - 通过 REST 框架在 Django 模型中进行健壮搜索的正确方法
- assembly - 如何找到编译器优化的内容?
- python - 根据条件从数据框中获取一列到另一个
- laravel - 用户的 Laravel 帖子在一列中,按行分隔,用户名在同一列的第一行