Search code examples
pythonloopssubplot

Three/multiple subplots per page in loop using python


I want to keep three plots(1 column, 3 rows) in each page of the pdf. This code is generating 12 plots in 12 pages, an is also creating 12 pngs. I don't know how to use the subplots in loop so that per page contains 3 plots and there will be a total 4 pages. Combinig three consecutive pngs into one png will also work. Thanks.

import re
import os
import pandas as pd
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt

#plt.style.use('ggplot')
plt.style.use('default')



obs = pd.read_excel(r'T:/Active Projects/US Army Corps of Engineers/St Louis District/LD25/Model/Model_Testing/Excel/LD25 Model testing Velocity_210119.xlsm','base')

sim1=pd.read_excel(r'T:/Active Projects/US Army Corps of Engineers/St Louis District/LD25/Model/Model_Testing/Excel/LD25 Model testing Velocity_210119.xlsm', 'itl')

p='T:/Active Projects/US Army Corps of Engineers/St Louis District/LD25/Model/Model_Testing/plot/raw data/' #p=path loc
pdf = PdfPages(p+'LDbase_211229_LDitl_211229_vel1.pdf')  # set pdf name
folder='LDbase_211229_LDitl_211229_vel1/' # set folder name for png files,pdf and folder name are same 


path=p+folder
isExist = os.path.exists(path)
if not isExist:
    os.makedirs(path, exist_ok=False)
    
x=[0,1,2,3,4,5,6,7,8,9,10,11]
y=[0,1,2,0,1,2,0,1,2,0,1,2]


for i,j in zip(x,y): # no of rows of obs is 24 or obs.shape[1]=24, so range(0,obs.shape[1]-1)
     title=[' Existing Pool Lock Approach: 2265 cms', ' Existing Pool Lock Approach: 3511 cms',' Existing Pool Lock Approach: 8920 cms',
            ' Existing TW Lock Approach: 2265 cms',' Existing TW Lock Approach: 3511 cms',' Existing TW Lock Approach 8920: cms',
            ' Proposed Pool Lock Approach: 2265 cms', ' Proposed Pool Lock Approach: 3511 cms',' Proposed Pool Lock Approach: 8920 cms',
            ' Proposed TW Lock Approach: 2265 cms', ' Proposed TW Lock Approach: 3511 cms',' Proposed TW Lock Approach: 8920 cms']
     b=[re.sub(r':', '', i) for i in title] # replace colon coz filename can't be saved with :
     #plt.rcParams.update({'font.size': 10})  
     fig, ax = plt.subplots(3,figsize=(7,3))
    
     a= 3.28084 # m to ft converter
    
     
     ax[j].plot(obs.iloc[:,2*i]*a,obs.iloc[:,2*i+1]*a,linestyle='-',ms='6',mfc='none') # base model
     ax[j].plot(sim1.iloc[:,2*i]*a,sim1.iloc[:,2*i+1]*a,linestyle='--',ms='6',mfc='none') # sim1 
     
     plt.grid(which='major',  linestyle='-',linewidth=0.3)
     plt.grid(which='minor',  linestyle='--',linewidth=0.2)
     #plt.minorticks_on()
     
     plt.xlabel("Distance (ft)")
     plt.ylabel(" Velocity (ft/s)")
     ax[j].legend(['Base','ITL'],prop={"size":10})
     ax[j].set_title(title[i])
   

   
     plt.savefig(path+'\{}.png'.format(str(b[i])),bbox_inches='tight',dpi=300)
     pdf.savefig(fig)     

       
pdf.close() 

It yields the attached plot: https://drive.google.com/file/d/19uBwC2b9CfiC68zQnhSoOebFrta68iln/view?usp=sharing

Here is the excel file used as input: https://docs.google.com/spreadsheets/d/18wIyrnW0M4CfjyyZIUmnkT2OQ-hOsR0R/edit?usp=sharing&ouid=102781316443126205856&rtpof=true&sd=true


Solution

  • You are looping through x, that has 12 items, and creating a new figure each time, so you get 12 of everything. A possible solution is:

    # --- snipped first part: it's the same as OP's ---
    
    # these constructs are unnecessary
    # x=[0,1,2,3,4,5,6,7,8,9,10,11]
    # y=[0,1,2,0,1,2,0,1,2,0,1,2]
    
    title=[' Existing Pool Lock Approach: 2265 cms', ' Existing Pool Lock Approach: 3511 cms',' Existing Pool Lock Approach: 8920 cms',
           ' Existing TW Lock Approach: 2265 cms',' Existing TW Lock Approach: 3511 cms',' Existing TW Lock Approach 8920: cms',
           ' Proposed Pool Lock Approach: 2265 cms', ' Proposed Pool Lock Approach: 3511 cms',' Proposed Pool Lock Approach: 8920 cms',
           ' Proposed TW Lock Approach: 2265 cms', ' Proposed TW Lock Approach: 3511 cms',' Proposed TW Lock Approach: 8920 cms']
    b = [re.sub(r':', '', i) for i in title]
    a = 3.28084 # m to ft converter
    # for i,j in zip(x,y):  # BAD
    for page in range(4):
        fig, ax = plt.subplots(3, figsize=(7,3)) # One figure per page
        for j in range(3):
             i = page * 3 + j 
             ax[j].plot(obs.iloc[:,2*i]*a,obs.iloc[:,2*i+1]*a,linestyle='-',ms='6',mfc='none') # base model
             ax[j].plot(sim1.iloc[:,2*i]*a,sim1.iloc[:,2*i+1]*a,linestyle='--',ms='6',mfc='none') # sim1 
             plt.grid(which='major',  linestyle='-',linewidth=0.3)
             plt.grid(which='minor',  linestyle='--',linewidth=0.2)
             plt.xlabel("Distance (ft)")
             plt.ylabel(" Velocity (ft/s)")
             ax[j].legend(['Base','ITL'],prop={"size":10})
             ax[j].set_title(title[i])
        plt.savefig(path+'\{}.png'.format(str(b[i])),bbox_inches='tight',dpi=300)
        pdf.savefig(fig)
           
    pdf.close() 
    

    It can be done more general, but it's not the point of the question.