How can I have only one x-axis for a group of subplots with an already shared x-axis?

Viewed 89

My code below currently gives me this Matplotlib chart.

enter image description here

I want to modify it such that the left column and the right column of subplots have only one x-axis each at the bottom, instead of 4 x-axes currently per column.

How can I do this? I found some solutions with sharex="col", but it seems like I cannot use it as I have two groups of subplots with different x-axes, and I later join the specific x-axes with "axes.flat1.get_shared_x_axes().join(axes.flat1, axes.flat[3], axes.flat[5], axes.flat[7])".

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib.ticker import FuncFormatter
import os
import copy

x = range(10)
y = range(10)

fig, axes = plt.subplots(nrows=4, ncols=2, gridspec_kw={'width_ratios': [1, 1]}, sharex=False, figsize=(11, 7))

    def plot_function(axes_object, datatype=1, title=None):

    stdlist=[0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001]

    #Data to plot. Do not include a total, it will be calculated
    index = ["Client 1a", "Client 2a", "Client 1b", "Client 2b", "Client 1c", "Client 2c"]
    if(datatype == 2):
        data = {'amount': list([0.1, 0.2, 0.3, 0.3, -0.2, 0.3])}
    if(datatype == 1):
        data = {'amount': list([0.1, 2, 1, 1, -2, 0.3])}

    #Store data and create a blank series to use for the waterfall
    trans = pd.DataFrame(data=data,index=index)
    blank = trans.amount.cumsum().shift(1).fillna(0)

    #Get the net total number for the final element in the waterfall
    total = trans.sum().amount
    trans.loc["net"]= total
    blank.loc["net"] = total

    #The steps graphically show the levels as well as used for label placement
    step = blank.reset_index(drop=True).repeat(3).shift(-1)
    step[1::3] = np.nan

    blank.loc["net"] = 0   
    
    trans=trans.iloc[::-1]

    stdlist_plot = copy.deepcopy(stdlist)
    stdlist_plot.reverse()

    color_positive = 'g'
    color_negative = 'r'

    colors = []

    x = np.array(["A", "B", "C", "D"])
    y = np.array([3, 8, 1, 10])

    y = list(trans["amount"])
    x = list(trans.index.values)

    for val in y:
        if(val>=0):
            colors.append(color_positive)
        else:
            colors.append(color_negative)

    axes_object.barh(x, y, left=blank.iloc[::-1], xerr=stdlist_plot, height = 0.9, color=colors)

    #Start label loop
    loop = 0
    SV_sum = 0

    trans=trans.iloc[::-1]
    
    for index, row in trans.iterrows():

        if index == 'net':
            y = trans.iloc[loop].amount
        else:
            SV_sum += trans.iloc[loop].amount
            y = SV_sum
        # Determine if we want a neg or pos offset
        if row['amount'] > 0:
            #y += pos_offset + stdlist[loop]
            pass
        else:
            #y -= neg_offset + stdlist[loop]
            pass
        axes_object.annotate("{:,.3f}".format(row['amount'])+"%±"+"{:,.3f}".format(stdlist[loop])+"%",(y+stdlist[loop],6-loop+0.0),ha="left")
        loop+=1

    axes_object.set_ylim(-0.04,7)

    if(title!=None):
        axes_object.set_title(title)

plot_function(axes.flat[7], title=None)
plot_function(axes.flat[5], title=None)
plot_function(axes.flat[3], title=None)
plot_function(axes.flat[1], title=None)

plot_function(axes.flat[6], datatype=2, title=None)
plot_function(axes.flat[4], datatype=2, title=None)
plot_function(axes.flat[2], datatype=2, title=None)
plot_function(axes.flat[0], datatype=2, title=None)

axes.flat[0].get_shared_x_axes().join(axes.flat[0], axes.flat[2], axes.flat[4], axes.flat[6])

axes.flat[1].get_shared_x_axes().join(axes.flat[1], axes.flat[3], axes.flat[5], axes.flat[7])

axes.flat[0].xaxis.set_tick_params(which='major', labelbottom=True)


for i in range(8):
    axes.flat[i].set_ylim([-0.5, 6.6])

axes.flat[0].set_xlim([-0.1, 1.05])
axes.flat[1].set_xlim([0, 7.2])

plt.tight_layout()

plt.show()
0 Answers
Related