您如何调整条形宽度以匹配辅助 x 轴?
Posted
技术标签:
【中文标题】您如何调整条形宽度以匹配辅助 x 轴?【英文标题】:How do you adjust bar width to match the secondary x-axis? 【发布时间】:2022-01-09 11:46:18 【问题描述】:如何设置条形宽度以匹配指定的天数?
我想要 4 个条形图,每个月的每个星期都有一个条形图。根据月份的不同,一周中的天数会有所不同。以下是我计算每周天数的方法:
from calendar import monthrange
def weekly_breakdown(year=2021, month=11):
total_days = monthrange(year, month)[1]
if total_days % 4 == 0: # 28 / 4 = 7
days_per_week = (7, 7, 7, 7)
elif total_days % 4 == 2: # 30 / 4 = 7.5
days_per_week = (8, 7, 8, 7)
elif total_days % 4 == 3: # 31 / 4 = 7.75
days_per_week = (8, 8, 8, 7)
# days_per_week = 'Week 1', 'Week 2', 'Week 3', 'Week 4'
return days_per_week
这是我的脚本中实际创建情节的部分。在此示例中,我使用的是 2021 年 11 月(30 天),因此我希望第一个条形宽度跨越 01-08
(8 天),第二个条形跨越 09-15
(7 天),第三个条形跨越16-23
(8 天),以及跨越 24-30
(7 天)的最后一个柱。
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter, DayLocator
# Generate data for bars.
df1 = pd.DataFrame(
[100, 1650, 2000, 3500],
index=['Week 1', 'Week 2', 'Week 3', 'Week 4'],
columns=['Amount']
)
df2 = pd.DataFrame(
[750, 1500, 2250, 3000],
index=['Week 1', 'Week 2', 'Week 3', 'Week 4'],
columns=['Amount']
)
# Generate line data.
days = pd.date_range(start="2021-11-01", end="2021-11-30").to_pydatetime().tolist()
daily_df = pd.DataFrame(
list(range(100, 3100, 100)),
index=days,
columns=['Cumulative']
)
fig, ax1 = plt.subplots(figsize=(8, 6), nrows=1, ncols=1)
# Share x-axis between bar and line plot.
ax2 = ax1.twiny()
df1['Amount'].plot(kind='bar', ax=ax1, color='red')
df2['Amount'].plot(kind='bar', ax=ax1, color='white', edgecolor='black', alpha=0.5)
daily_df['Cumulative'].plot(x='Adjusted Date', kind='line', ax=ax2, marker='o')
ax1.xaxis.tick_bottom()
ax1.tick_params(axis='x', rotation=0, length=0, pad=30)
ax1.set_ylabel('Dollars')
ax2.xaxis.tick_bottom()
ax2.tick_params(axis='x', which='major', length=3)
ax2.tick_params(axis='x', which='minor', length=3)
ax2.set_xlim([daily_df.index[0], daily_df.index[-1]])
ax2.xaxis.set_major_locator(DayLocator(interval=1))
ax2.xaxis.set_major_formatter(DateFormatter("%d"))
额外问题:我在哪里可以找到有关如何使用 df.plot(kind='')
创建绘图的文档?我搜索了 matplotlib 文档,但没有成功。
【问题讨论】:
【参考方案1】:似乎pandas 中df.plot('kind'=bar)
函数的width
参数只接受一个值而不是宽度列表。但是,您可以直接使用 matplolib 中的 bar
函数来实现您想要的。它允许您将宽度列表传递给函数。
您可以在下面找到代码:
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter, DayLocator
import numpy as np
# Generate data for bars.
df1 = pd.DataFrame(
[100, 1650, 2000, 3500],
index=['Week 1', 'Week 2', 'Week 3', 'Week 4'],
columns=['Amount']
)
df2 = pd.DataFrame(
[750, 1500, 2250, 3000],
index=['Week 1', 'Week 2', 'Week 3', 'Week 4'],
columns=['Amount']
)
# Generate line data.
days = pd.date_range(start="2021-11-01", end="2021-11-30").to_pydatetime().tolist()
daily_df = pd.DataFrame(
list(range(100, 3100, 100)),
index=days,
columns=['Cumulative']
)
fig, ax1 = plt.subplots(figsize=(8, 6), nrows=1, ncols=1)
# Share x-axis between bar and line plot.
ax2 = ax1.twiny()
days_per_week=weekly_breakdown(2021,11)
N_days=np.sum(days_per_week)
widths=np.array(days_per_week)-1
index_bars=[1+sum(widths[0:i]+1) for i in range(len(widths))]
ax1.bar(index_bars,df1['Amount'],color='red', width=widths,align='edge')
ax1.bar(index_bars,df2['Amount'],color='white',edgecolor='black', alpha=0.5,width=widths,align='edge')
ax1.plot(np.arange(N_days)+1,daily_df['Cumulative'],marker='o')
ax1.set_xlim([1,N_days])
ax1.set_xticks(np.arange(N_days)+1)
ax2.xaxis.tick_bottom()
ax2.tick_params(axis='x', rotation=0, length=0, pad=30)
ax2.set_xticks([1./(len(df1.index))*i+(1./(2*len(df1.index))) for i in range(len(df1.index))])
ax2.set_xticklabels(df1.index)
输出给出:
【讨论】:
这正是我想要的。谢谢你。我很早就在使用 matplotlib 条形图时遇到了一个问题,并且在找到 pandas 条形图选项后就再也没有回去过。以上是关于您如何调整条形宽度以匹配辅助 x 轴?的主要内容,如果未能解决你的问题,请参考以下文章