Установить одну и ту же легенду для нескольких графиков - PullRequest
0 голосов
/ 02 октября 2019

Мне бы хотелось иметь общую легенду в конце моей «области нескольких графиков». «days_df_list» - пандас DataFrame. мой код:


    #https://stackoverflow.com/questions/41625077/python-pandas-split-a-timeserie-per-month-or-week
    weeks_df_list = [g for n, g in daily_data_df.groupby(_pd.Grouper(key='Transaction Date', freq='W'))]

    for my_df in weeks_df_list:
        my_df['day_of_the_week'] = my_df['Transaction Date'].dt.weekday_name
        my_df.set_index(keys=['day_of_the_week'], drop=True, inplace=True)

    fig, axs = plt.subplots(number_of_charts, 1, sharex=True, figsize=[8, 17])

    # Adjust horizontal space between axes
    fig.subplots_adjust(hspace=.5)
    for i in range(number_of_charts):
        print("i:", i)
        #axs[i].set_yticks(np.arange(-0.9, 1.0, 0.4))
        #axs[i].set_ylim(-1, 1)
        #axs[i] = weeks_df_list[i]['pct_daily_vol'].multiply(100).round(1).plot(label='% Daily Volumes')
        #percent daily
        axs[i].plot(weeks_df_list[i]['pct_daily_vol'].multiply(100).round(2), label='% Daily Volumes',
                     color='blue')
        axs[i].yaxis.set_major_formatter(mtick.PercentFormatter())
        axs[i].legend(loc=2)
        #percent daily max
        axs[i].plot(weeks_df_list[i]['pct_daily_limit'].multiply(100).round(2), label='% Daily Limit',
                     color='orange')
        axs[i].yaxis.set_major_formatter(mtick.PercentFormatter())
        axs[i].legend(loc=0)


        #secondary axis
        axs_2 = axs[i].twinx()
        axs_2.plot(weeks_df_list[i]['vwap'], label='VWAP Paid', color='green')
        axs_2.legend(loc=3)


        #comon variables
        axs[i].set_yticks(_np.arange(0, 100, 20))
        axs[i].set_ylim(0, 100)
        axs[i].set_title('Week:' + str(i + 1))
        axs[i].grid(True)


    plt.show()

Мои данные:

day_of_the_week;Transaction Date;Volume;vwap;mylow;myhigh;myopen;myclose;myvolume;20d_vol_avg;25%_limit;pct_daily_vol;pct_daily_limit
Monday;2019-09-02;35807;53.24725612310441;52.9;54.0;53.75;53.0;192570;246338.0;61584.0;0.18594277405618737;0.5814334892179787
Tuesday;2019-09-03;51200;52.923418945312505;52.75;53.25;53.25;53.1;231631;241551.0;60388.0;0.22104122505191448;0.847850566337683
Wednesday;2019-09-04;45100;52.97544235033262;52.5;53.4;53.35;53.0;220595;243379.0;60845.0;0.20444706362338222;0.7412277097542938
Thursday;2019-09-05;59000;51.50618474576272;51.2;52.0;51.65;51.55;740694;246378.0;61594.0;0.07965502623215524;0.9578855083287333
Friday;2019-09-06;59100;51.47736971235195;50.95;52.0;51.6;51.4;512996;273752.0;68438.0;0.1152055766516698;0.8635553347555451
Monday;2019-09-09;59100;51.450917935702215;51.15;51.7;51.2;51.25;215956;290220.0;72555.0;0.27366685806367963;0.8145544759148232
Tuesday;2019-09-10;60900;50.00561674876848;49.38;51.25;51.25;50.25;418767;289580.0;72395.0;0.14542693192156975;0.8412183161820568
Wednesday;2019-09-11;60800;50.00684062500002;49.56;50.45;50.45;49.7;335791;296832.0;74208.0;0.18106500769824088;0.8193186718413109
Thursday;2019-09-12;60800;50.0199384868421;49.66;50.3;49.88;50.2;241223;305352.0;76338.0;0.2520489339739577;0.7964578584715345
Friday;2019-09-13;60600;50.20141881188121;49.9;50.45;50.05;50.0;221205;292716.0;73179.0;0.27395402454736556;0.828106423974091
Monday;2019-09-16;61200;49.713364379084986;49.14;50.1;50.05;49.26;268788;293007.0;73252.0;0.22768873610429036;0.8354720690220062
Tuesday;2019-09-17;61300;49.60541109298533;48.96;50.2;49.26;50.0;364572;293632.0;73408.0;0.16814236968280613;0.8350588491717524
Wednesday;2019-09-18;60800;50.02049095394736;49.64;50.2;49.92;50.1;207805;304150.0;76038.0;0.2925819879213686;0.7996001999000499
Thursday;2019-09-19;60500;50.27256446280997;50.05;50.45;50.25;50.3;191168;304872.0;76218.0;0.3164755607633077;0.7937757485108504
Friday;2019-09-20;60700;50.136443822075755;49.86;50.35;50.1;50.3;375839;298466.0;74616.0;0.1615053254185968;0.8134984453736464
Monday;2019-09-23;60500;50.228577685950434;49.86;50.45;49.86;50.1;212277;296375.0;74094.0;0.2850049699213763;0.8165303533349529
Tuesday;2019-09-24;37295;50.85666282343475;49.9;51.3;49.9;51.3;348997;301849.0;75462.0;0.10686338277979467;0.49422225756009647
Wednesday;2019-09-25;39000;50.91075897435897;50.55;51.4;50.85;51.25;357430;305476.0;76369.0;0.10911227373191953;0.5106784166350221
Thursday;2019-09-26;22300;51.8501143497758;51.2;52.2;51.2;52.0;484304;312316.0;78079.0;0.04604545905051373;0.2856081660881927
Friday;2019-09-27;22300;51.96707174887891;51.4;52.3;51.95;52.15;111409;325248.0;81312.0;0.2001633620264072;0.27425226288862653

Пока я получаю легенду на каждом графике, но мне бы хотелось, чтобы только одна легенда была внизу моего "многочастичная зона ". Любая идея, входные ссылки, будет высоко ценится. Я попробовал:

Нажмите

и несколько других, но, очевидно, я что-то упускаю.

Я очистил некоторые фотографии. Поэтому, пытаясь использовать @SpghttCd:

    fig.subplots_adjust(hspace=.5)
    for i, ax in enumerate(axs):
        print("i:", i)
        #percent daily
        axs[i].plot(weeks_df_list[i]['pct_daily_vol'].multiply(100).round(2), label=('_', '')[i>0] + '% Daily Volumes',
                     color='blue')
        axs[i].yaxis.set_major_formatter(mtick.PercentFormatter())
        #percent daily max
        axs[i].plot(weeks_df_list[i]['pct_daily_limit'].multiply(100).round(2), label=('_', '')[i>0] + '% Daily Limit',
                     color='orange')
        axs[i].yaxis.set_major_formatter(mtick.PercentFormatter())
        #secondary axis
        axs_2 = axs[i].twinx()
        axs_2.plot(weeks_df_list[i]['vwap'], label=('_', '')[i>0] + 'VWAP Paid', color='green')

        #comon variables
        axs[i].set_yticks(_np.arange(0, 100, 20))
        axs[i].set_ylim(0, 100)
        axs[i].set_title('Week:' + str(i + 1))
        axs[i].grid(True)

    fig.legend(loc=8, ncol=3)
    plt.tight_layout(rect=[0, .05, 1, 1])
    plt.show()

, я получаю:

enter image description here

Пожалуйста, исправьте меня.

Ответы [ 2 ]

1 голос
/ 02 октября 2019

Не уверен, что это сработает для вас, так как я не проверял его, но стоит попробовать.


#https://stackoverflow.com/questions/41625077/python-pandas-split-a-timeserie-per-month-or-week
weeks_df_list = [g for n, g in daily_data_df.groupby(_pd.Grouper(key='Transaction Date', freq='W'))]

for my_df in weeks_df_list:
    my_df['day_of_the_week'] = my_df['Transaction Date'].dt.weekday_name
    my_df.set_index(keys=['day_of_the_week'], drop=True, inplace=True)

fig, axs = plt.subplots(number_of_charts, 1, sharex=True, figsize=[8, 17])

# Adjust horizontal space between axes
fig.subplots_adjust(hspace=.5)
for i in range(number_of_charts):
    print("i:", i)
    #axs[i].set_yticks(np.arange(-0.9, 1.0, 0.4))
    #axs[i].set_ylim(-1, 1)
    #axs[i] = weeks_df_list[i]['pct_daily_vol'].multiply(100).round(1).plot(label='% Daily Volumes')
    #percent daily
    axs[i].plot(weeks_df_list[i]['pct_daily_vol'].multiply(100).round(2), label='% Daily Volumes',
                 color='blue')
    axs[i].yaxis.set_major_formatter(mtick.PercentFormatter())
    #percent daily max
    axs[i].plot(weeks_df_list[i]['pct_daily_limit'].multiply(100).round(2), label='% Daily Limit',
                 color='orange')
    axs[i].yaxis.set_major_formatter(mtick.PercentFormatter())


    #secondary axis
    axs_2 = axs[i].twinx()
    axs_2.plot(weeks_df_list[i]['vwap'], label='VWAP Paid', color='green')


    #comon variables
    axs[i].set_yticks(_np.arange(0, 100, 20))
    axs[i].set_ylim(0, 100)
    axs[i].set_title('Week:' + str(i + 1))
    axs[i].grid(True)

fig.legend(loc=0)


plt.show()

Извинения, если результаты не соответствуют вашим ожиданиям.

После просмотракомментарий автора вопроса, я редактирую пост, добавив еще одно предложение. Идея состоит в том, чтобы удалить все легенды, закодированные в pyplot, и создать наши собственные легенды. Обратите внимание на необходимый импорт вверху (Line2D). Пожалуйста, добавьте его в свой код вверху.

from matplotlib.lines import Line2D

#https://stackoverflow.com/questions/41625077/python-pandas-split-a-timeserie-per-month-or-week
weeks_df_list = [g for n, g in daily_data_df.groupby(_pd.Grouper(key='Transaction Date', freq='W'))]

for my_df in weeks_df_list:
    my_df['day_of_the_week'] = my_df['Transaction Date'].dt.weekday_name
    my_df.set_index(keys=['day_of_the_week'], drop=True, inplace=True)

fig, axs = plt.subplots(number_of_charts, 1, sharex=True, figsize=[8, 17])

# Adjust horizontal space between axes
fig.subplots_adjust(hspace=.5)
for i in range(number_of_charts):
    print("i:", i)
    #axs[i].set_yticks(np.arange(-0.9, 1.0, 0.4))
    #axs[i].set_ylim(-1, 1)
    #axs[i] = weeks_df_list[i]['pct_daily_vol'].multiply(100).round(1).plot()
    #percent daily
    axs[i].plot(weeks_df_list[i]['pct_daily_vol'].multiply(100).round(2),color='blue')
    axs[i].yaxis.set_major_formatter(mtick.PercentFormatter())
    #percent daily max
    axs[i].plot(weeks_df_list[i]['pct_daily_limit'].multiply(100).round(2),color='orange')
    axs[i].yaxis.set_major_formatter(mtick.PercentFormatter())


    #secondary axis
    axs_2 = axs[i].twinx()
    axs_2.plot(weeks_df_list[i]['vwap'],color='green')


    #comon variables
    axs[i].set_yticks(_np.arange(0, 100, 20))
    axs[i].set_ylim(0, 100)
    axs[i].set_title('Week:' + str(i + 1))
    axs[i].grid(True)

Manual_Legends = [Line2D([0],[0],color='blue',label='% Daily Volumes'),Line2D([0],[0],color='orange',label='% Daily Volumes'),Line2D([0],[0],color='green',label='VWAP Paid')]
plt.legend(handles=Manual_Legends,loc='lower center',,bbox_to_anchor=(0.5,-0.35),ncol=3,title='Legend of the plot')
plt.show()

Убедившись, что вы уже опубликовали данные, я могу заставить их работать с моей стороны. Пожалуйста, смотрите вложение ниже. Это то, что вы хотели? Пожалуйста, дайте мне знать.

enter image description here

1 голос
/ 02 октября 2019

Начиная с - afaik - matplotlib 3.1 вы можете использовать рисунок с легендой , то есть просто использовать легенду, как и раньше, но не как метод plt или ваш axs, а с fig:

fig.legend()

в вашем примере для нижнего центра и трех столбцов, например:

fig.legend(loc=8, ncol=3)

относительно перекрытия:
legend может толькосоздайте легенду и разместите ее где угодно, чтобы предотвратить наложение, вам понадобится plt.tight_layout() с правильным значением rect, например,

plt.tight_layout(rect=[0, .05, 1, 1])

и для дубликатов:
legend собирает все помеченные графики, поэтому, конечно, это причина, по которой вы получаете дубликаты при создании графиков в цикле, как вы делали выше.

Однако вы можете предотвратить это с помощью небольшой функции:предписанное подчеркивание подавляет метку, которая будет добавлена ​​в легенду, например, label='VWAP Paid' не будет отображаться в легенде.
Зная это, вы можете добавить подчеркивание в зависимости от счетчика вашей петли, например:

label=('', '_')[i>0] + 'VWAP Paid'

Кстати, вы действительно должны рассмотреть возможность использования

for i, ax in enumerate(axs):    # ...(axs.flatten()): if you would have several rows _and_ colmns

вместо

for i in range(number_of_charts):

Это открывает возможность записать ax вместо axs[i], но все равно предоставляет i в качестве переменной счетчика, если вам это нужно (например, длядобавление подчеркивания за исключением первого цикла ... :))


РЕДАКТИРОВАТЬ:

это будет ваш кодс моими предложениями:

fig, axs = plt.subplots(len(weeks_df_list), sharex=True, figsize=[8, 17])

fig.subplots_adjust(hspace=.5)
for i, (ax, df) in enumerate(zip(axs, weeks_df_list)):
    print("i:", i)
    #percent daily
    ax.plot(df['pct_daily_vol'].multiply(100).round(2), label=('', '_')[i>0] + '% Daily Volumes', color='blue')
    ax.yaxis.set_major_formatter(mtick.PercentFormatter())
    #percent daily max
    ax.plot(df['pct_daily_limit'].multiply(100).round(2), label=('', '_')[i>0] + '% Daily Limit', color='orange')
    ax.yaxis.set_major_formatter(mtick.PercentFormatter())
    #secondary axis
    axs_2 = ax.twinx()
    axs_2.plot(df['vwap'], label=('', '_')[i>0] + 'VWAP Paid', color='green')

    #comon variables
    ax.set_yticks(np.arange(0, 100, 20))
    ax.set_ylim(0, 100)
    ax.set_title('Week:' + str(i + 1))
    ax.grid(True)

fig.legend(loc=8, ncol=3)
plt.tight_layout(rect=[0, .05, 1, 1])

enter image description here

...