0

I know this has been asked before but I cannot figure out how to word my question to find what I am looking for. I am still fairly new to coding and am trying to generate plots using nested for loops. I intend to create 4 plots, but each plot is created 4 times, resulting in 16 figures total. What is causing the repetition?

I've already checked plotting multiple plots generated inside a for loop on the same axes python but this was irrelevant.

Here is my code:

###(this is sample data in case you are trying to recreate the code)
df24avg=pd.dataframe({'pm10_3135_2018':[30,34,32,44,45,46,59,54,59,30],
'nox_3135(ppb)':[20,29,27,31,33,14,34,23,32,31],
'CO_3135(ppm)':[0.8,0.9,0.1,0.2,0.5,0.5,0.7,0.9,0,9,0.3],
'O3_mda8_3135':[42,45,47,51,52,52,57,67,65,70],
'pm25_3135_2018':[6,7,6,7,4,5,2,11,9,18]})

x = [df24avg.pm10_3135_2018,df24avg['nox_3135(ppb)'],df24avg['CO_3135(ppm)'],df24avg.O3_mda8_3135]
y = df24avg.pm25_3135_2018
xlab = ["PM10 (ug/m^3)", "NOx (ppb)", "CO (ppm)", "O3 MDA8 (ppb)"]

for xcol in x:
    for lab in xlab:

        fig, ax = plt.subplots()
        ax = plt.gca()
        ax.plot(xcol, y, color='xkcd:red',linestyle='None',marker='o')
        ax.set_xlabel(lab,fontsize=15)
        ax.set_ylabel('PM2.5 (ug/m^3)',fontsize=15)
        ax.set_ylim(0,)
        ax.set_xlim(0,)
        #ax.set_title("{} vs {}".format(x1, ylab))
    
        #ax.legend(fontsize='medium', loc='lower right')
        fig.tight_layout()

I also would like to save each figure with different names of my choosing but am unsure how to do that in the loop without creating a third loop. I am also not opposed to creating another loop just want to avoid this issue of figures repeating. Thank you!

obscuredbyclouds
  • 189
  • 1
  • 1
  • 15
  • 2
    first guess is the double loop. Can you explain in clear english what the criteria is for splitting your dataframe into four parts to plot? – Umar.H Apr 26 '21 at 18:03
  • You are defining your figure within the second loop so that's 16 figures. You _probably_ want to define the figure in your first loop, use the second loop to plot the 4 lines and then set the axis properties outside of the second loop (again since there's only one plot...). Also probably need to reverse the order of your loops. – ALollz Apr 26 '21 at 18:05
  • 3
    IIUC, one loop: `for xcol, lab in zip(x, xlab):`. Also, `ax = plt.gca()` can be eliminated. If you want specific filenames, create another list and add that to the `zip`. – BigBen Apr 26 '21 at 18:06

2 Answers2

2

If I understand correctly, you need one loop with zip:

for xcol, lab in zip(x, xlab):
    fig, ax = plt.subplots()
    ax.plot(xcol, y, color='xkcd:red',linestyle='None',marker='o')

ax = plt.gca() should be removed as ax is already determined in the subplots call.

If you have a list of unique filenames for each plot, simply add that to zip:

fnames = ['foo.png', 'bar.png', 'baz.png', 'grr.png']

for xcol, lab, fname in zip(x, xlab, fnames):
    ...
    plt.savefig(fname)
BigBen
  • 46,229
  • 7
  • 24
  • 40
0

You can use range(len()) function instead of directly using values.

for i in range(len(x)):
#    for lab in xlab: # you don't need this line
        fig, ax = plt.subplots()
        ax = plt.gca()
        ax.plot(x[i], y, color='xkcd:red',linestyle='None',marker='o') # Modified with index
        ax.set_xlabel(xlab[i],fontsize=15) # Also used index
        ax.set_ylabel('PM2.5 (ug/m^3)',fontsize=15)
        ax.set_ylim(0,)
        ax.set_xlim(0,)
        #ax.set_title("{} vs {}".format(x1, ylab))
    
        #ax.legend(fontsize='medium', loc='lower right')
        fig.tight_layout()
Zalak Bhalani
  • 979
  • 7
  • 15