#python #python-3.x #pandas #matplotlib
#питон #python-3.x #панды #matplotlib
Вопрос:
Как я могу установить ширину полосы, соответствующую указанному количеству дней?
Я хочу, чтобы у меня было 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 года (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:
Похоже, что width
аргумент df.plot('kind'=bar)
функции от pandas допускает только одно значение, а не список ширин. Однако вы можете достичь желаемого, используя bar
функцию непосредственно из matplolib. Это позволяет передавать в функцию список ширины.
Вы можете найти код ниже:
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)
И результат дает:
Комментарии:
1. Это именно то, что я искал. Спасибо. Я столкнулся с проблемой, используя график бара matplotlib на ранней стадии, и никогда не возвращался после того, как нашел вариант графика бара pandas.