1

I am using the code (posted here: https://stackoverflow.com/a/22845857/6649485) below to generate a clustered stacked bar plot. Unfortunately the error bars are not shifted in the same way as the data bars. I am not sure how to adress them and set their x-value accordingly.

enter image description here

def plot_clustered_stacked(dfall, labels=None, title="SEC stress study",  H="/", **kwargs):
    """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="bar",
                      linewidth=0,
                      stacked=True,
                      ax=axe,
                      legend=False,
                      grid=False,
                      yerr=0.1,
                      **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_x(rect.get_x() + 1 / float(n_df + 1) * i / float(n_col))
                rect.set_hatch(H * int(i / n_col)) #edited part     
                rect.set_width(1 / float(n_df + 1))

    axe.set_xticks((np.arange(0, 2 * n_ind, 2) + 1 / float(n_df + 1)) / 2.)
    axe.set_xticklabels(df.index, rotation = 0)
    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))

    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
DavidG
  • 24,279
  • 14
  • 89
  • 82
ta8
  • 313
  • 3
  • 12
  • 1
    Could you provide a [mcve] of the issue and also clearly explain the purpose of the code? Also, why are you not simply plotting a grouped bar plot, but instead shift the bars manually? – ImportanceOfBeingErnest Jan 10 '18 at 22:34
  • Thanks for your input! I don't know how to group and stack. I posted below my solution. I still had to shift the bars manually... – ta8 Jan 10 '18 at 22:52

1 Answers1

0

This is what I came up with by now.

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np

def plot_clustered_stacked(dfall):

    for j, df in enumerate(dfall):
            set_count=1
            width = 0.2
            N=len(df.index)
            b_width = 0.2
            index=np.arange(N/set_count)
            labels=df.index
            p1 = plt.bar(index +j*b_width, df['Average Monomer Area'], width=width, yerr='0.5 Stdev Monomer Area', data=df)
            p2 = plt.bar(index +j*b_width, df['Average HMW Area'], bottom=df['Average Monomer Area'], width=width, yerr='0.5 Stdev HMW Area', data=df)
            plt.xticks(index+b_width, labels)
            plt.legend((p1[0], p2[0]), ('Average Monomer Area', 'Average 

HMW Area'))
data=pd.read_csv("SEC.csv")

df1 = data[data['Time'].str.contains("0 weeks")].drop(['High/low', 'Time'], axis=1)
df1.set_index('Excipient Name', inplace=True)
df2 = data[data['Time'].str.contains("1 week")].drop(['High/low', 'Time'], axis=1)
df2.set_index('Excipient Name', inplace=True)
df3 = data[data['Time'].str.contains("3 weeks")].drop(['High/low', 'Time'], axis=1)
df3.set_index('Excipient Name', inplace=True)




plot_clustered_stacked([df1, df2, df3])

plt.show()
ta8
  • 313
  • 3
  • 12