Python: Plotting errorbars in a loglog scale, in a loop and then saving the image

10.2k Views Asked by At

I have 58 files that I need to plot. Some of them are empty (not important, I already skipped them with the if condition). I need to plot the data in the files, using a loglog scale, with error bars. And I want to save the plots in the end. I am using Python, spyder. I have written the following code:

route='/......./'
L=np.arange (1,59, 1)
for i in range (L.shape[0]):
    I=L[i]
    name_sq= 'Spectra_without_quiescent_'+('{}'.format(I))+'.dat' 
    Q=np.loadtxt(route+name_sq)
    if (len(Q) != 0):
        x=Q[:,1]
        y=Q[:,2]
        z=Q[:,3]
        fig=plt.errorbar(x,y,yerr=z, fmt = 'b')
        fig.set_yscale('log')
        fig.set_xscale('log')
        xlabel='Frequency'
        ylabel='Flux'
        title='Spectrum_'+('{}'.format(I))+'.dat'
        name='Spectrum_without_quiescent_'+('{}'.format(I))+'.pdf'
        fig.savefig(route+name, fig)

however, when I run it, I get the following error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/spyderlib/widgets/externalshell/sitecustomize.py", line 540, in runfile
    execfile(filename, namespace)
  File "/media/chidiac/My Passport/DOCUMENTS/My_Publications/2-3C273_radio_spectra/Maximum_flux_code.py", line 49, in <module>
    fig.set_yscale('log')
AttributeError: 'ErrorbarContainer' object has no attribute 'set_yscale'

I am still a beginner in Python and I couldn't find the error, or how to fix it. Any help is very appreciated.

2

There are 2 best solutions below

1
On BEST ANSWER

A friend of mine helped me with this issue and if someone is interested, here is the solution:

route='/....../'
L=np.arange (1,59, 1)
print L 
for i in range (L.shape[0]):
    I=L[i]
    name_sq= 'Spectra_without_quiescent_'+('{}'.format(I))+'.dat' 
    Q=np.loadtxt(route+name_sq)
    if (len(Q) != 0):
        x=np.log(Q[:,1])
        y=np.log(Q[:,2])
        z=np.log(Q[:,3])
        fig, ax = plt.subplots(facecolor='w', edgecolor='k')
    plt.errorbar(x,y,yerr=z, fmt = 'b')
    plt.ylabel('Flux', size='x-large')
    plt.xlabel('Frequency', size='x-large')
    title='Spectrum_'+('{}'.format(I))+'.dat'
    name='Spectrum_without_quiescent_'+('{}'.format(I))+'.pdf'
    pylab.savefig(route+name)

The first trick was, to first get the log values of the data and then plot them. Since I am not aware of any command that allows me to plot the errorbars in a logscale, I think this is the best solution. The second trick was to use subplots. Otherwise, I got the 58 curves in one plot, 58 times.

I hope this solution is helpful.

0
On

This post may be a bit old, however I had the same problem and maybe this will help others in the future.

Your initial solution was actually almost correct. However, set_yscale is a method of the axes, not the figure. Thus your code in the if statement should look like:

import matplotlib.pyplot as plt

# other stuff you did ..

x=Q[:,1]
y=Q[:,2]
z=Q[:,3]
fig = plt.figure()
ax = plt.axes()
ax.set_xscale("log")
ax.set_yscale("log")
ax.errorbar(x,y,yerr=z, fmt = 'b')
ax.set_xlabel("Frequency")
ax.set_ylabel("Flux")
ax.set_title("Spectrum_{}.dat".format(I))
name="Spectrum_without_quiescent_{}.pdf".format(I)
plt.savefig(route+name)

Where I also adjusted your usage of the format function.

Note, that your second solution will not always work properly. If you have very small values and small errorbars the logarithm of these small values will get large (e.g. log(10^(-6)) = -6, as the logarithm to base 10 is used) and you will have huge errorbars though your actual error is small.

Long story short: Use ax.set_*scale. It's safe.