Как настроить ширину полосы в соответствии со вторичной осью x?

#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.