Matplotlib 在所有子图上显示 x-ticks 和唯一的 y 标签
Posted
技术标签:
【中文标题】Matplotlib 在所有子图上显示 x-ticks 和唯一的 y 标签【英文标题】:Matplotlib show x-ticks on all subplots and unique y label 【发布时间】:2018-04-05 08:15:18 【问题描述】:我正在绘制两个共享相同 x 轴的子图,但是当我绘制时,我只看到第二个子图上的 x 轴刻度。如何使 x-ticks 在两个子图上可见?
我还想为两个子图设置 y 标签,但只有第二个是可见的。您能帮忙在两个子图上显示 y 标签吗?
以下是我的可重现代码。
#!/usr/bin/python3
import pandas as pd
desired_width = 1500
pd.set_option('display.width', desired_width)
import matplotlib.pyplot as plt
import numpy as np
df = pd.DataFrame(['DATETIME': '2017-09-29 01:00,', 'Population': 1000, 'Temp': 90, 'State': 'California',
'DATETIME': '2017-09-29 01:00,', 'Population': 2000, 'Temp': 70, 'State': 'Illinois',
'DATETIME': '2017-09-29 01:00,', 'Population': 3000, 'Temp': 50, 'State': 'Georgia',
'DATETIME': '2017-09-29 02:00,', 'Population': 2000, 'Temp': 40, 'State': 'California',
'DATETIME': '2017-09-29 02:00,', 'Population': 6000, 'Temp': 20, 'State': 'Illinois',
'DATETIME': '2017-09-29 02:00,', 'Population': 4000, 'Temp': 30, 'State': 'Georgia',
'DATETIME': '2017-09-29 03:00,', 'Population': 3000, 'Temp': 40, 'State': 'California',
'DATETIME': '2017-09-29 03:00,', 'Population': 4000, 'Temp': 60, 'State': 'Illinois',
'DATETIME': '2017-09-29 03:00,', 'Population': 2000, 'Temp': 80, 'State': 'Georgia'])
df.index = df['DATETIME']
df.index = (pd.to_datetime(df.index)).strftime("%m/%d %H:00")
fig, axes = plt.subplots(nrows=2, ncols=1, sharex=True)
df.groupby('State')['Population'].plot(kind='line', linestyle='--', alpha=0.5, marker='o', legend=True, ax=axes[0])
plt.ylabel('Pop')
df.groupby('State')['Temp'].plot(kind='line', linestyle='--', alpha=0.5, marker='o', legend=True, ax=axes[1])
plt.ylabel('Temp')
plt.tick_params(axis='both', which='both', labelsize=7)
plt.tight_layout()
plt.show()
当前图表输出:
【问题讨论】:
删除 sharex=True 会在两个子图上显示,但在第一个图上显示的格式不正确。我想在所有子图上显示使用指定参数格式化的 x 轴。我也想拥有独特的 y 标签。 【参考方案1】:正如其他答案所提到的,要让ylabel
出现在两个子图上,您可以在此处使用面向对象的界面axes[0].set_ylabel
和axes[1].set_ylabel
。
您还应该在两个轴上使用.tick_params
来为两个子图获得相同大小的刻度标签等
最后,为了让刻度标签显示在第一个子图上,作为循环遍历所有刻度并必须将它们设置为可见的替代方法,您可以通过再提供一个选项来实现相同的目的@ 987654327@:labelbottom=True
.
fig, axes = plt.subplots(nrows=2, ncols=1, sharex=True)
df.groupby('State')['Population'].plot(kind='line', linestyle='--', alpha=0.5, marker='o', legend=True, ax=axes[0])
axes[0].set_ylabel('Pop')
df.groupby('State')['Temp'].plot(kind='line', linestyle='--', alpha=0.5, marker='o', legend=True, ax=axes[1])
axes[1].set_ylabel('Temp')
axes[0].tick_params(axis='both', which='both', labelsize=7, labelbottom=True)
axes[1].tick_params(axis='both', which='both', labelsize=7)
【讨论】:
啊,我不知道! @DavidG:当你设置sharex
时,你基本上只是在撤消matplotlib
在后台所做的事情,因为它只是为除底部之外的所有子图设置labelbottom=False
【参考方案2】:
您可以做几件事。要么删除sharex = True
。或者,如果你想使用它,sharex
将 x 刻度设置为不可见,即set_visible(False)
。因此,您可以将它们设置为True
来阻止这种情况。
为了使子图的格式相同,您需要使用axes[0].tick_params(axis='both', which='both', labelsize=7)
为两个子图设置每个子图的刻度参数(即重复axes[1]
)
注意,我个人更喜欢使用 matpotlib 面向对象的 API,即使用 ax.set_ylabel()
而不是 plt.ylabel()
,因为我认为它可以更好地控制您使用的子图和轴。因此,我在这方面也稍微修改了您的代码
df = pd.DataFrame(['DATETIME': '2017-09-29 01:00,', 'Population': 1000, 'Temp': 90, 'State': 'California',
'DATETIME': '2017-09-29 01:00,', 'Population': 2000, 'Temp': 70, 'State': 'Illinois',
'DATETIME': '2017-09-29 01:00,', 'Population': 3000, 'Temp': 50, 'State': 'Georgia',
'DATETIME': '2017-09-29 02:00,', 'Population': 2000, 'Temp': 40, 'State': 'California',
'DATETIME': '2017-09-29 02:00,', 'Population': 6000, 'Temp': 20, 'State': 'Illinois',
'DATETIME': '2017-09-29 02:00,', 'Population': 4000, 'Temp': 30, 'State': 'Georgia',
'DATETIME': '2017-09-29 03:00,', 'Population': 3000, 'Temp': 40, 'State': 'California',
'DATETIME': '2017-09-29 03:00,', 'Population': 4000, 'Temp': 60, 'State': 'Illinois',
'DATETIME': '2017-09-29 03:00,', 'Population': 2000, 'Temp': 80, 'State': 'Georgia'])
df.index = df['DATETIME']
df.index = (pd.to_datetime(df.index)).strftime("%m/%d %H:00")
fig, axes = plt.subplots(nrows=2, ncols=1, sharex=True)
df.groupby('State')['Population'].plot(kind='line', linestyle='--', alpha=0.5, marker='o', legend=True, ax=axes[0])
axes[0].set_ylabel('Pop')
df.groupby('State')['Temp'].plot(kind='line', linestyle='--', alpha=0.5, marker='o', legend=True, ax=axes[1])
axes[1].set_ylabel('Temp')
# Set the formatting the same for both subplots
axes[0].tick_params(axis='both', which='both', labelsize=7)
axes[1].tick_params(axis='both', which='both', labelsize=7)
# set ticks visible, if using sharex = True. Not needed otherwise
for tick in axes[0].get_xticklabels():
tick.set_visible(True)
plt.tight_layout()
plt.show()
这给出了:
【讨论】:
谢谢。这正是我所寻找的。我可以问一个跟进吗?对于更大的数据集,我设置了plt.xticks(np.arange(len(df) / df['State'].nunique()), df.index)
,以便显示所有 xticks。我也可以对两个子图都这样做吗?
它不再适用于 Matplotlib 3.3.2。【参考方案3】:
关于第一个问题,我建议不要这样做,不要用多余的墨水弄乱情节。
现在,到 y 标签上。您必须使用从 plt.subplots
获得的轴替换
plt.ylabel('Pop')
axes[0].set_ylabel('Pop')
和
plt.ylabel('Pop')
axes[1].set_ylabel('Temp')
【讨论】:
【参考方案4】:从fig, axes = plt.subplots(nrows=2, ncols=1, sharex=True)
中删除sharex=True
以获得单独的x 轴。
对于 ylabels
axes[0].set_ylabel('Pop')
axes[1].set_ylabel('Temp')
【讨论】:
以上是关于Matplotlib 在所有子图上显示 x-ticks 和唯一的 y 标签的主要内容,如果未能解决你的问题,请参考以下文章