Search code examples
pythonpandasmatplotlibboxplot

Add grouped of boxplot legend in python


I have two dataframes (df1 and df2), and each of them has a shape (60,20). I combined them horizontally (i.e., 60,40) and draw the 40 columns using a boxplot. Now I want to add the legend (only two legends since all the 20 cols of the df1 and df2 are grouped and considered as one type of legend). I have searched and looked at several posts, but nothing similar to my problem. I put my code and output figure below. As shown in the figure, I need to add two legends ('A' for all red boxplot, 'B' for all gold boxplot).

df_combined = pd.concat([df1, df2], axis=1)
fig, ax1 = plt.subplots(figsize=(10,6))
labels = ['1', '2', '3','4', '5', 
  '6','7','8','9','10','11','12','13','14','15','16','17','18','19','20',
      '21', '22', '23','24', '25', 
           '26','27','28','29','30','31','32','33','34','35','36','37','38','39','40']
 props = ax1.boxplot(df_combined ,
                 vert=True,  
                 patch_artist=True,  
                 labels=labels)
 ax1.yaxis.grid(True)
 plt.show()

enter image description here


Solution

  • You can try something like below... once you have drawn the boxplot, use patch.set(facecolor=<...>) to give the color you want. Similarly, use the patch and the labels to give the custom ax1.legend() you need.

    ## My random data
    df1=pd.DataFrame(np.random.randint(25, 225, size=(60,20)))
    df2=pd.DataFrame(np.random.randint(25, 225, size=(60,20)))
    
    ##Your code for creation of boxplot
    df_combined = pd.concat([df1, df2], axis=1)
    fig, ax1 = plt.subplots(figsize=(10,6))
    props = ax1.boxplot(df_combined,
                     vert=True,  
                     patch_artist=True,  
                     labels=list(range(1,41)))  ## Note - use range as it is simpler/easier
    
    ## New code... for each patch (the box) in the boxplot, color ...
    for i, patch in enumerate(props['boxes']):
        if i < 21:  ## First 20 as red
            patch.set(facecolor='red') 
        else:  ## Last 20 as golden
            patch.set(facecolor='goldenrod')
            
    ax1.yaxis.grid(True)
    
    ##New code - For plotting legend, take first (red) box and first (golden) box, and the label names you want
    ax1.legend([props["boxes"][0], props["boxes"][21]], ['Red-A', 'Golden-B'])
    plt.show()
    

    enter image description here