Search code examples
pythonpandasmatplotlibsubplot

How to change the order of subplots matplotlib


I have a data frame that contains average concentrations for 4 different sites based on season and year. The code I wrote produces a figure for each site, with four subplots for each season. Year is on the y-axis and concentration is on the x-axis. Here's the link to my data: https://drive.google.com/file/d/1mVAsjRiFmMXaW0F8HBhadi1ZQPcUGIa7/view?usp=sharing

The issue is that the code automatically plots the subplots as

fall - spring

summer - winter

I want them to plot in chronological order, because that makes more sense that alphabetical:

spring - summer

fall - winter

Here is my code:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import statsmodels.formula.api as smf
import scipy.stats

main_dataframe = pd.read_csv('NOx_sznl.csv')
main_dataframe.rename(columns={'NOx_3168':'Banning NOx', 'NOx_2199':'Palm Springs NOx', 'NOx_2551':'El Centro NOx', 'NOx_3135':'Calexico NOx'}, inplace=True)

col = list(main_dataframe.columns)
col.remove('Year')
col.remove('Season')

for ind,station in enumerate(col):
    
        df_new = main_dataframe[['Season', 'Year', col[ind]]]
###here I tried to reorder the seasons in the dataframe
        df_new = df_new.set_index('Season')
        df_new = df_new.loc[['Spring', 'Summer', 'Fall', 'Winter'], :]
        df_new = df_new.reset_index()
###but it didn't change the outcome
        df_new = df_new.set_index('Year')
        
        # df_new['Betty Jo Mcneece Receiving Home'].astype('float')
        df_new[col[ind]] = df_new[col[ind]]        


        grouped = df_new.groupby('Season')
        
        rowlength = grouped.ngroups/2                         # fix up if odd number of groups
        fig, axs = plt.subplots(figsize=(15,10), 
                                nrows=2, ncols=int(rowlength),     # fix as above
                                gridspec_kw=dict(hspace=0.4))#, sharex='col', sharey='row') # Much control of gridspec

        targets = zip(grouped.groups.keys(), axs.flatten())
        for i, (key, ax) in enumerate(targets):
            ax.plot(grouped.get_group(key)[col[ind]], marker='o', color='orange')
            ax.set_ylim(0,)
            ax.set_yticks(ax.get_yticks(),size=12)
            #ax.set_xlim(2009,2020)
            ax.set_xticks(np.arange(2009,2020,1))
            ax.set_xticklabels(ax.get_xticks(), rotation = 45, size=12)
        fig.suptitle("%s"%col[ind], fontsize=30)    
#         ax.set_title('%s')
        plt.subplot(221)
        plt.gca().set_title('Fall', fontsize=20)
        plt.subplot(222)
        plt.gca().set_title('Spring', fontsize=20)
        plt.subplot(223)
        plt.gca().set_title('Summer', fontsize=20)
        plt.subplot(224)
        plt.gca().set_title('Winter', fontsize=20)
        plt.show()

I would apppreciate any help rearranging the subplots.


Solution

  • The order of the subplots is given by grouped.groups.keys() in targets = zip(grouped.groups.keys(), axs.flatten()) but the problem is further upstream in grouped = df_new.groupby('Season') which is where grouped.groups.keys() comes from. df.groupby() automatically sorts alphabetically unless you do sort=False, so grouped = df_new.groupby('Season', sort=False) should follow the order you provided when you made df_new.

    Here is what your code looks like on my end so you can have an exact copy.

    import pandas as pd
    import matplotlib.pyplot as plt
    import numpy as np
    import statsmodels.formula.api as smf
    import scipy.stats
    
    main_dataframe = pd.read_csv('NOx_sznl.csv')
    main_dataframe.rename(columns={'NOx_3168': 'Banning NOx',
                                   'NOx_2199': 'Palm Springs NOx',
                                   'NOx_2551': 'El Centro NOx',
                                   'NOx_3135': 'Calexico NOx'},
                          inplace=True)
    
    col = list(main_dataframe.columns)
    col.remove('Year')
    col.remove('Season')
    
    for ind, station in enumerate(col):
    
        df_new = main_dataframe[['Season', 'Year', col[ind]]]
        ###here I tried to reorder the seasons in the dataframe
        df_new = df_new.set_index('Season')
        df_new = df_new.loc[['Spring', 'Summer', 'Fall', 'Winter'], :]
        df_new = df_new.reset_index()
        ###but it didn't change the outcome
        df_new = df_new.set_index('Year')
    
        # df_new['Betty Jo Mcneece Receiving Home'].astype('float')
        df_new[col[ind]] = df_new[col[ind]]
    
        grouped = df_new.groupby('Season', sort=False)
    
        rowlength = grouped.ngroups/2                         # fix up if odd number of groups
        fig, axs = plt.subplots(figsize=(15,10),
                                nrows=2, ncols=int(rowlength),     # fix as above
                                gridspec_kw=dict(hspace=0.4))#, sharex='col', sharey='row') # Much control of gridspec
    
    
        targets = zip(grouped.groups.keys(), axs.flatten())
        for i, (key, ax) in enumerate(targets):
    
            ax.plot(grouped.get_group(key)[col[ind]], marker='o', color='orange')
            ax.set_ylim(0,)
            ax.set_yticks(ax.get_yticks(),size=12)
            #ax.set_xlim(2009,2020)
            ax.set_xticks(np.arange(2009,2020,1))
            ax.set_xticklabels(ax.get_xticks(), rotation = 45, size=12)
            ax.set_title(key)
    
        fig.suptitle("%s"%col[ind], fontsize=30)
        plt.show()
    

    Organized months example