如何在 matplotlib 图中突出显示周末?
how to highlight weekends in matplotlib plots?
对于简单的时间序列:
import pandas as pd
df = pd.DataFrame({'dt':['2020-01-01', '2020-01-02', '2020-01-04', '2020-01-05', '2020-01-06'], 'foo':[1,2, 4,5,6]})
df['dt'] = pd.to_datetime(df.dt)
df['dt_label']= df['dt'].dt.strftime('%Y-%m-%d %a')
df = df.set_index('dt')
#display(df)
df['foo'].plot()
x =plt.xticks(ticks=df.reset_index().dt.values, labels=df.dt_label, rotation=90, horizontalalignment='right')
如何突出显示周末的 x 轴标签?
编辑
Pandas Plots: Separate color for weekends, pretty printing times on x axis
建议:
def highlight_weekends(ax, timeseries):
d = timeseries.dt
ranges = timeseries[d.dayofweek >= 5].groupby(d.year * 100 + d.weekofyear).agg(['min', 'max'])
for i, tmin, tmax in ranges.itertuples():
ax.axvspan(tmin, tmax, facecolor='orange', edgecolor='none', alpha=0.1)
但应用
highlight_weekends(ax, df.reset_index().dt)
不会改变剧情
我稍微扩展了您的样本数据,这样我们就可以确保我们可以突出显示多个周末实例。
在这个解决方案中,我创建了一个列 'weekend'
,这是一个布尔值列,指示相应的日期是否在周末。
然后我们遍历这些值并调用 ax.axvspan
import pandas as pd
import matplotlib.pyplot as plt
# Add a couple of extra dates to sample data
df = pd.DataFrame({'dt': ['2020-01-01',
'2020-01-02',
'2020-01-04',
'2020-01-05',
'2020-01-06',
'2020-01-07',
'2020-01-09',
'2020-01-10',
'2020-01-11',
'2020-01-12']})
# Fill in corresponding observations
df['foo'] = range(df.shape[0])
df['dt'] = pd.to_datetime(df.dt)
df['dt_label']= df['dt'].dt.strftime('%Y-%m-%d %a')
df = df.set_index('dt')
ax = df['foo'].plot()
plt.xticks(ticks=df.reset_index().dt.values,
labels=df.dt_label,
rotation=90,
horizontalalignment='right')
# Create an extra column which highlights whether or not a date occurs at the weekend
df['weekend'] = df['dt_label'].apply(lambda x: x.endswith(('Sat', 'Sun')))
# Loop over weekend pairs (Saturdays and Sundays), and highlight
for i in range(df['weekend'].sum() // 2):
ax.axvspan(df[df['weekend']].index[2*i],
df[df['weekend']].index[2*i+1],
alpha=0.5)
这是一个使用 fill_between
绘图函数和 x 轴单位的解决方案,因此可以独立于 DatetimeIndex 和数据频率突出显示周末。
x 轴限制用于计算以天为单位的绘图覆盖的时间范围,这是 matplotlib dates 中使用的单位。然后计算 weekends
掩码并将其传递给 fill_between
函数的 where
参数。掩码被处理为右排他的,因此在这种情况下,它们必须包含星期一,以便绘制到星期一 00:00 的高光。因为当周末出现在限制附近时,绘制这些突出显示可能会改变 x 轴限制,因此在绘制后 x 轴限制将设置回原始值。
请注意,与 axvspan
相反,fill_between
函数需要 y1
和 y2
参数。出于某种原因,使用默认的 y 轴限制会在图框与周末亮点的顶部和底部之间留下一个小间隙。此问题在创建绘图后由 运行 ax.set_ylim(*ax.get_ylim())
解决。
这是一个完整的示例,它基于提供的示例代码并使用类似于 jwalton 提供的答案的扩展数据集:
import numpy as np # v 1.19.2
import pandas as pd # v 1.1.3
import matplotlib.pyplot as plt # v 3.3.2
import matplotlib.dates as mdates
# Create sample dataset
dt = pd.to_datetime(['2020-01-01', '2020-01-02', '2020-01-04', '2020-01-05',
'2020-01-06', '2020-01-07', '2020-01-09', '2020-01-10',
'2020-01-11', '2020-01-14'])
df = pd.DataFrame(dict(foo=range(len(dt))), index=dt)
# Draw pandas plot: setting x_compat=True converts the pandas x-axis units to
# matplotlib date units. This is not necessary for this particular example but
# it is necessary for all cases where the dataframe contains a continuous
# DatetimeIndex (for example ones created with pd.date_range) that uses a
# frequency other than daily
ax = df['foo'].plot(x_compat=True, figsize=(6,4), ylabel='foo')
ax.set_ylim(*ax.get_ylim()) # reset y limits to display highlights without gaps
# Highlight weekends based on the x-axis units
xmin, xmax = ax.get_xlim()
days = np.arange(np.floor(xmin), np.ceil(xmax)+2) # range of days in date units
weekends = [(dt.weekday()>=5)|(dt.weekday()==0) for dt in mdates.num2date(days)]
ax.fill_between(days, *ax.get_ylim(), where=weekends, facecolor='k', alpha=.1)
ax.set_xlim(xmin, xmax) # set limits back to default values
# Create and format x tick for each data point
plt.xticks(df.index.values, df.index.strftime('%d\n%a'), rotation=0, ha='center')
plt.title('Weekends are highlighted from SAT 00:00 to MON 00:00', pad=15, size=12);
您可以在我发布的答案中找到此解决方案的更多示例 and 。
对于简单的时间序列:
import pandas as pd
df = pd.DataFrame({'dt':['2020-01-01', '2020-01-02', '2020-01-04', '2020-01-05', '2020-01-06'], 'foo':[1,2, 4,5,6]})
df['dt'] = pd.to_datetime(df.dt)
df['dt_label']= df['dt'].dt.strftime('%Y-%m-%d %a')
df = df.set_index('dt')
#display(df)
df['foo'].plot()
x =plt.xticks(ticks=df.reset_index().dt.values, labels=df.dt_label, rotation=90, horizontalalignment='right')
如何突出显示周末的 x 轴标签?
编辑
Pandas Plots: Separate color for weekends, pretty printing times on x axis
建议:
def highlight_weekends(ax, timeseries):
d = timeseries.dt
ranges = timeseries[d.dayofweek >= 5].groupby(d.year * 100 + d.weekofyear).agg(['min', 'max'])
for i, tmin, tmax in ranges.itertuples():
ax.axvspan(tmin, tmax, facecolor='orange', edgecolor='none', alpha=0.1)
但应用
highlight_weekends(ax, df.reset_index().dt)
不会改变剧情
我稍微扩展了您的样本数据,这样我们就可以确保我们可以突出显示多个周末实例。
在这个解决方案中,我创建了一个列 'weekend'
,这是一个布尔值列,指示相应的日期是否在周末。
然后我们遍历这些值并调用 ax.axvspan
import pandas as pd
import matplotlib.pyplot as plt
# Add a couple of extra dates to sample data
df = pd.DataFrame({'dt': ['2020-01-01',
'2020-01-02',
'2020-01-04',
'2020-01-05',
'2020-01-06',
'2020-01-07',
'2020-01-09',
'2020-01-10',
'2020-01-11',
'2020-01-12']})
# Fill in corresponding observations
df['foo'] = range(df.shape[0])
df['dt'] = pd.to_datetime(df.dt)
df['dt_label']= df['dt'].dt.strftime('%Y-%m-%d %a')
df = df.set_index('dt')
ax = df['foo'].plot()
plt.xticks(ticks=df.reset_index().dt.values,
labels=df.dt_label,
rotation=90,
horizontalalignment='right')
# Create an extra column which highlights whether or not a date occurs at the weekend
df['weekend'] = df['dt_label'].apply(lambda x: x.endswith(('Sat', 'Sun')))
# Loop over weekend pairs (Saturdays and Sundays), and highlight
for i in range(df['weekend'].sum() // 2):
ax.axvspan(df[df['weekend']].index[2*i],
df[df['weekend']].index[2*i+1],
alpha=0.5)
这是一个使用 fill_between
绘图函数和 x 轴单位的解决方案,因此可以独立于 DatetimeIndex 和数据频率突出显示周末。
x 轴限制用于计算以天为单位的绘图覆盖的时间范围,这是 matplotlib dates 中使用的单位。然后计算 weekends
掩码并将其传递给 fill_between
函数的 where
参数。掩码被处理为右排他的,因此在这种情况下,它们必须包含星期一,以便绘制到星期一 00:00 的高光。因为当周末出现在限制附近时,绘制这些突出显示可能会改变 x 轴限制,因此在绘制后 x 轴限制将设置回原始值。
请注意,与 axvspan
相反,fill_between
函数需要 y1
和 y2
参数。出于某种原因,使用默认的 y 轴限制会在图框与周末亮点的顶部和底部之间留下一个小间隙。此问题在创建绘图后由 运行 ax.set_ylim(*ax.get_ylim())
解决。
这是一个完整的示例,它基于提供的示例代码并使用类似于 jwalton 提供的答案的扩展数据集:
import numpy as np # v 1.19.2
import pandas as pd # v 1.1.3
import matplotlib.pyplot as plt # v 3.3.2
import matplotlib.dates as mdates
# Create sample dataset
dt = pd.to_datetime(['2020-01-01', '2020-01-02', '2020-01-04', '2020-01-05',
'2020-01-06', '2020-01-07', '2020-01-09', '2020-01-10',
'2020-01-11', '2020-01-14'])
df = pd.DataFrame(dict(foo=range(len(dt))), index=dt)
# Draw pandas plot: setting x_compat=True converts the pandas x-axis units to
# matplotlib date units. This is not necessary for this particular example but
# it is necessary for all cases where the dataframe contains a continuous
# DatetimeIndex (for example ones created with pd.date_range) that uses a
# frequency other than daily
ax = df['foo'].plot(x_compat=True, figsize=(6,4), ylabel='foo')
ax.set_ylim(*ax.get_ylim()) # reset y limits to display highlights without gaps
# Highlight weekends based on the x-axis units
xmin, xmax = ax.get_xlim()
days = np.arange(np.floor(xmin), np.ceil(xmax)+2) # range of days in date units
weekends = [(dt.weekday()>=5)|(dt.weekday()==0) for dt in mdates.num2date(days)]
ax.fill_between(days, *ax.get_ylim(), where=weekends, facecolor='k', alpha=.1)
ax.set_xlim(xmin, xmax) # set limits back to default values
# Create and format x tick for each data point
plt.xticks(df.index.values, df.index.strftime('%d\n%a'), rotation=0, ha='center')
plt.title('Weekends are highlighted from SAT 00:00 to MON 00:00', pad=15, size=12);
您可以在我发布的答案中找到此解决方案的更多示例