Search code examples
pythonmatplotlibhistogram

Multi-axis x with matplotlib python


My aim is to get something that looks like the image below:

enter image description here

For the moment I've tried to build it like this:

import matplotlib.pyplot as plt
import numpy as np 

X = ['Class 1','Class 2','Class 3','Class 4', 'Class 5', 'Class 6', 'Class 7'] 

sE = ['-9,51', '-13,5', '0,193', '9,564', '23,13', '-0,252', '-0,442']
s = ['19,605', '28,388', '1,762', '-4,264', '-24,716', '-26,956', '0,382']
eE = ['-5,364', '-7,954', '-3,756', '-0,184', '1,883', '41,876', '-0,012']


X_axis = np.arange(len(X)) 

# plt.bar(X_axis, sE, color='red',width = 0.25, edgecolor='black') 
# plt.bar(X_axis+0.25, s, color='cyan',width = 0.25, edgecolor='black') 
# plt.bar(X_axis+0.5, eE, color='green',width = 0.25, edgecolor='black') 

#plt.hist([sE, s, eE], color = ['red', 'cyan', 'green'], edgecolor = 'black', histtype = 'bar')

#plt.xticks(X_axis, X) 
plt.xlabel("Classes")  
plt.title("Geographical STP A") 
plt.show() 

But we're a long way from achieving the desired result. I really have no idea how to do this, can you help me ?


Solution

  • To be able to plot, the strings should be converted to numeric.

    Plots with multiple bars per X-value are much easier using the Pandas (or Seaborn) library which builds on matplotlib for plotting. Your data doesn't have data for histogram, you seem to want a bar plot.

    Here is some code. Many customizations are possible.

    import matplotlib.pyplot as plt
    import pandas as pd
    
    X = ['Class 1', 'Class 2', 'Class 3', 'Class 4', 'Class 5', 'Class 6', 'Class 7']
    
    sE = ['-9,51', '-13,5', '0,193', '9,564', '23,13', '-0,252', '-0,442']
    s = ['19,605', '28,388', '1,762', '-4,264', '-24,716', '-26,956', '0,382']
    eE = ['-5,364', '-7,954', '-3,756', '-0,184', '1,883', '41,876', '-0,012']
    
    # organize the data as a pandas dataframe
    df = pd.DataFrame({'Class': X, 'sE': sE, 's': s, 'eE': eE})
    
    # convert strings to numeric
    df['sE'] = df['sE'].str.replace(',','.').astype(float)
    df['s'] = df['s'].str.replace(',','.').astype(float)
    df['eE'] = df['eE'].str.replace(',','.').astype(float)
    
    ax = df.set_index('Class').plot(kind='bar')
    
    ax.set_title("Geographical STP A")
    ax.tick_params(axis='x', rotation=0)
    
    plt.show()
    

    pandas bar plot

    Possible customizations could include:

    ax = df.set_index('Class').plot(kind='bar', color=['crimson', 'limegreen', 'dodgerblue'])
    
    ax.set_title("Geographical STP A")
    ax.tick_params(axis='x', rotation=0, length=0)  # rotate tick labels horizontally, remove tick mark
    ax.grid(True, axis='y')  # add a grid in the y direction
    ax.set_xlabel('')  # remove superfluous x label
    for dir in ['top', 'bottom', 'right']:
        ax.spines[dir].set_visible(False)  # remove the border around the plot
    

    customized bar plot with pandas and matplotlib

    PS: The dataframe looks like:

    Class sE s eE
    Class 1 -9.51 19.605 -5.364
    Class 2 -13.5 28.388 -7.954
    Class 3 0.193 1.762 -3.756
    Class 4 9.564 -4.264 -0.184
    Class 5 23.13 -24.716 1.883
    Class 6 -0.252 -26.956 41.876
    Class 7 -0.442 0.382 -0.012