簡體   English   中英

如何使用 pandas plot 獲得兩個圖例,一個用於堆疊條的 colors,一個用於條的陰影?

[英]How to get two legends using pandas plot, one for the colors of the stacked bars and one for the hatches of the bars?

我一直試圖理解這篇文章的答案,以便填充兩個不同的傳說。

我創建了一個集群堆疊條 plot,每個條都有不同的陰影,我下面的代碼與上述帖子的答案有點不同。

但是我一直無法弄清楚如何獲得一個帶有 colors 的圖例和一個帶有艙口的圖例。

顏色圖例應對應於 A、B、C、D、E,如果條帶陰影線,則陰影圖例應指示“有”,如果沒有陰影線,則應指示“無”。

import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap as coloring

# copy the dfs below and use pd.read_clipboard() to reproduce
df_1
     A   B   C   D   E
Mg  10  15  23  25  27
Ca  30  33   0  20  17

df_2
     A   B   C   D   E
Mg  20  12   8  40  10
Ca   7  26  12  22  16

hatches=(' ', '//')
colors_ABCDE=['tomato', 'gold', 'greenyellow', 'forestgreen', 'palevioletred']
dfs=[df_1,df_2]

for each_df, df in enumerate(dfs):
    df.plot(ax=plt.subplot(111), kind="barh", \
            stacked=True, hatch=hatches[each_df], \
            colormap=coloring.from_list("my_colormap", colors_ABCDE), \
            figsize=(7,2.5), position=len(dfs)-each_df-1, \
            align='center', width=0.2, edgecolor="darkgrey")

plt.legend(loc='center left', bbox_to_anchor=(1.0, 0.5), fontsize=12)

我設法得到的 plot 是:

陰謀

任何想法如何創建兩個圖例並將它們放在另一個旁邊或一個在另一個下面? 提前謝謝^_^

由於在matplotlib中添加圖例是一個復雜而廣泛的步驟,因此請考慮使用您引用的鏈接與 @jrjc 的function 解決方案 但是,您需要根據水平條形圖的需要調整 function。 具體來說:

  • 添加顏色 map 和DataFrame.plot調用的參數
  • 將 bar plot 從kind='bar'調整為kind='barh'用於水平版本
  • 將 x 換成 y 行: rect.set_y(rect.get_y() + 1 / float(n_df + 1) * i / float(n_col))
  • width換成行中的heightrect.set_height(1 / float(n_df + 1))
  • np.arange(0, 120, 20)值調整axe.set_xticksaxe.set_xticklabels

Function

import numpy as np
import pandas as pd
import matplotlib.cm as cm
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap as coloring

def plot_clustered_stacked(dfall, labels=None, title="multiple stacked bar plot", H="//",
                            colors_ABCDE=['tomato', 'gold', 'greenyellow', 'forestgreen', 'palevioletred'], **kwargs):
    """
       CREDIT: @jrjc (https://stackoverflow.com/a/22845857/1422451)

       Given a list of dataframes, with identical columns and index, create a clustered stacked bar plot. 
       labels is a list of the names of the dataframe, used for the legend
       title is a string for the title of the plot
       H is the hatch used for identification of the different dataframe
    """

    n_df = len(dfall)
    n_col = len(dfall[0].columns) 
    n_ind = len(dfall[0].index)
    axe = plt.subplot(111)

    for df in dfall : # for each data frame
        axe = df.plot(kind="barh",
                      linewidth=0,
                      stacked=True,
                      ax=axe,
                      legend=False,
                      grid=False,
                      colormap=coloring.from_list("my_colormap", colors_ABCDE),
                      edgecolor="darkgrey",
                      **kwargs)  # make bar plots

    h,l = axe.get_legend_handles_labels() # get the handles we want to modify
    for i in range(0, n_df * n_col, n_col): # len(h) = n_col * n_df
        for j, pa in enumerate(h[i:i+n_col]):
            for rect in pa.patches: # for each index
                rect.set_y(rect.get_y() + 1 / float(n_df + 2) * i / float(n_col))
                rect.set_hatch(H * int(i / n_col)) #edited part     
                rect.set_height(1 / float(n_df + 2))

    axe.set_xticks(np.arange(0, 125, 20))
    axe.set_xticklabels(np.arange(0, 125, 20).tolist(), rotation = 0)
    axe.margins(x=0, tight=None)
    axe.set_title(title)

    # Add invisible data to add another legend
    n=[]        
    for i in range(n_df):
        n.append(axe.bar(0, 0, color="gray", hatch=H * i, edgecolor="darkgrey"))

    l1 = axe.legend(h[:n_col], l[:n_col], loc=[1.01, 0.5])
    if labels is not None:
        l2 = plt.legend(n, labels, loc=[1.01, 0.1]) 
    axe.add_artist(l1)
    return axe

稱呼

plt.figure(figsize=(10, 4))
plot_clustered_stacked([df_1, df_2],["df_1", "df_2"])
plt.show()

plt.clf()
plt.close()

Output

繪圖輸出

我認為@jrjc 的這個 function 解決方案對我的理解來說相當令人困惑,因此,我更願意稍微改變我自己的東西並進行調整。

因此,我花了一些時間才明白,當為 plot 創建第二個圖例時,python 會自動擦除第一個圖例,此時必須使用add_artist()

添加第二個圖例的另一個先決條件是命名 plot 並將 .add_artist() 方法應用於該特定的 plot,以便 python 知道該新棒的位置。

簡而言之,這就是我設法創建我想到的 plot 的方式,我希望這些評論能讓它對任何人都更加清晰和有用。

import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap as coloring
import matplotlib.patches as mpatches
# copy the dfs below and use pd.read_clipboard() to reproduce
df_1
     A   B   C   D   E
Mg  10  15  23  25  27
Ca  30  33   0  20  17
df_2
     A   B   C   D   E
Mg  20  12   8  40  10
Ca   7  26  12  22  16

hatches=(' ', '//')
colors_ABCDE=['tomato', 'gold', 'greenyellow', 'forestgreen', 'palevioletred']
dfs=[df_1,df_2]
for each_df, df in enumerate(dfs):
    #I name the plot as "figure"
    figure=df.plot(ax=plt.subplot(111), kind="barh", \
            stacked=True, hatch=hatches[each_df], \
            colormap=coloring.from_list("my_colormap", colors_ABCDE), \
            figsize=(7,2.5), position=len(dfs)-each_df-1, \
            align='center', width=0.2, edgecolor="darkgrey", \
            legend=False) #I had to False the legend too
legend_1=plt.legend(df_1.columns, loc='center left', bbox_to_anchor=(1.0, 0.5), fontsize=12)

patch_hatched = mpatches.Patch(facecolor='beige', hatch='///', edgecolor="darkgrey", label='hatched')
patch_unhatched = mpatches.Patch(facecolor='beige', hatch=' ', edgecolor="darkgrey", label='non-hatched')
legend_2=plt.legend(handles=[patch_hatched, patch_unhatched], loc='center left', bbox_to_anchor=(1.15, 0.5), fontsize=12)

# as soon as a second legend is made, the first disappears and needs to be added back again
figure.add_artist(legend_1) #python now knows that "figure" must take the "legend_1" along with "legend_2"

有兩個傳說的情節

我很確定它可以更加優雅和自動化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM