Search code examples
pythonpandasmatplotlibannotationsmulti-index

Plot both multi-index labels on x-axis in pandas plot


I have a multi-index dataframe and would like to both index as x-axis labels. Where each of the "forecasts" index1 is listed as below, but want "year" index[0] to be shown instead of the x-axis label "forecast", so each panel would show the year index: 2020, 2050, 2099 below the forecast names. I am also trying to place labels above each bar with the values from the "most important observation" column.

  def plot_function(x, ax):
        ax = graph[x]
        ax.set_xlabel(x, weight='bold')
        return df_par_trans.xs(x).plot(kind='bar', stacked='False', ax=ax, legend=False)
    
n_subplots = len(df_par_trans.index.levels[0])
fig, axes = plt.subplots(nrows=1, ncols=n_subplots, sharey=True, figsize=(14, 8))  

graph = dict(zip(df_par_trans.index.levels[0], axes))
plots = list(map(lambda x: plot_function(x, graph[x]), graph))
ax.tick_params(axis='both', which='both', length=0)
fig.subplots_adjust(wspace=0)

plt.legend()
plt.show()

enter image description here

my dataframe looks like this:

year    forecast  most important observation  percent increase when left out
2020    PV6SM     Harkins                     17.371021
2050    PV6SM     Harkins                     10.569719
2099    PV6SM     Harkins                     12.343476
2020    PV3S      PV3S                        34.095863
2050    PV3S      PV3S                        32.565513
2099    PV3S      PV3S                        26.110555

Solution

  • You need to rename the index with the year:

    groups = df.groupby("year")
    fig, axes = plt.subplots(1, len(groups), sharey=True, figsize=(14,8))
    
    for ax, (year, group) in zip(axes, groups):
        # The rename_axis function makes the difference
        group.set_index("forecast").rename_axis(year)["percent increase when left out"].plot(kind="bar", ax=ax)
        ax.tick_params(axis='both', which='both', length=0)
    
    ax.legend()
    fig.subplots_adjust(wspace=0)
    

    Output:

    output