matplotlib pyplot 2 plots with different axes in same figure

2.3k views Asked by At

I have a small issue with matplotlib.pyplot and I hope someone might have come across it before.

I have data that contain X,Y,e values that are the X, Y measurements of a variable and e are the errors of the measurements in Y. I need to plot them in a log log scale.

I use the plt.errorbars function to plot them and then set yscale and xscale to log and this works fine. But I need to also plot a line on the same graph that needs to be in linear scale.

I am able to have the plots done separately just fine but I would like to have them in the same image if possible. Do you have any ideas? I am posting what I have done for now.

Cheers, Kimon

    tdlist = np.array([0.01,0.02,0.05,0.1,0.2,0.3,0.4,0.5,0.8,1,2,5,10,15,20,25,30,40,60,80,100,150,200,250,300,400])
    freqlist=np.array([30,40,50,60,70,80,90,100,110,120,140,160,180,200,220,250,300,350,400,450])

    filename=opts.filename

    data = reader(filename)
    data2 = logconv(data)

    #x,y,e the data. Calculating usefull sums
    x = data2[0]
    y = data2[1]
    e = data2[2]

    xoe2 = np.sum(x/e**2)
    yoe2 = np.sum(y/e**2)
    xyoe2 = np.sum(x*y/e**2)
    oe2 = np.sum(1/e**2)
    x2oe2 = np.sum(x**2/e**2)

    aslope = (xoe2*yoe2-xyoe2*oe2)/(xoe2**2-x2oe2*oe2)
    binter = (xyoe2-aslope*x2oe2)/xoe2
    aerr = np.sqrt(oe2/(x2oe2*oe2-xoe2**2))
    berr = np.sqrt(x2oe2/(x2oe2*oe2-xoe2**2))

    print('slope is ',aslope,' +- ', aerr)
    print('inter is ',binter,' +- ', berr)

    fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ax2 = fig.add_axes(ax1.get_position(), frameon=False)

ax1.errorbar(data[0],data[1],yerr=data[2],fmt='o')
ax1.set_xscale('log',basex=10)
ax1.set_yscale('log',basey=10)
ax1.set_yticks([])
ax1.set_xticks([])


ax2.plot(x,aslope*x+binter,'r')
ax2.plot(x,(aslope-aerr)*x+(binter+berr),'--')
ax2.plot(x,(aslope+aerr)*x+(binter-berr),'--')
ax2.set_xscale('linear')
ax2.set_yscale('linear')
plt.xticks(np.log10(freqlist),freqlist.astype('int'))
plt.yticks(np.log10(tdlist),tdlist.astype('float'))

plt.xlabel('Frequency (MHz)')
plt.ylabel('t_s (msec)')
fitndx1 = 'Fit slope '+"{0:.2f}".format(aslope)+u"\u00B1"+"{0:.2f}".format(aerr)
plt.legend(('Data',fitndx1))




plt.show()

Following Molly's suggestion I managed to get closer to my goal but still not there. I am adding a bit more info for what I am trying to do and it might clarify things a bit.

I am setting ax1 to the errobar plot that uses loglog scale. I need to use errorbar and not loglog plot so that I can display the errors with my points.

I am using ax2 to plot the linear fit in linealinear scale.

Moreover I do not want the x and y axes to display values that are 10,100,1000 powers of ten but my own axes labels that have the spacing I want therefore I am using the plt.xticks. I tried ax1.set_yticks and ax1.set_yticklabes but with no success. Below is the image I am getting.

I do not have enough reputation to post an image but here is the link of it uploaded

http://postimg.org/image/uojanigab/

The values of my points should be x range = 40 - 80 and y range = 5 -200 as the fit lines are now.

2

There are 2 answers

0
Kimon On BEST ANSWER

I was not able to get two sets of axis working with the errorbar function so I had to convert everything to log scale including my linear plot. Below is the code I use to get it might be useful to someone.

plt.errorbar(data[0],data[1],yerr=data[2],fmt='o')
plt.xscale('log',basex=10)
plt.yscale('log',basey=10)
plt.plot(data[0],data[0]**aslope*10**binter,'r')
plt.plot(data[0],data[0]**(aslope-aerr)*10**(binter+berr),'--')
plt.plot(data[0],data[0]**(aslope+aerr)*10**(binter-berr),'--')
plt.xticks(freqlist,freqlist.astype('int'))
plt.yticks(tdlist,tdlist.astype('float'))
plt.xlabel('Frequency (MHz)')
plt.ylabel('t_s (msec)')
fitndx1 = 'Fit slope '+"{0:.2f}".format(aslope)+u"\u00B1"+"{0:.2f}".format(aerr)
plt.legend(('Data',fitndx1))
plt.show()

And here is the link to the final image

http://postimg.org/image/bevj2k6nf/

1
Molly On

You can create two overlapping axes using the add_suplot method of figure. Here's an example:

from matplotlib import pyplot as plt

fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ax2 = fig.add_axes(ax1.get_position(), frameon=False)

ax1.loglog([1,10,100,1000],[1000,1,100,10])
ax2.plot([5,10,11,13],'r')

plt.show()

log and linear scale on the same plot

You can then turn off the x and y ticks for the linear scale plot like this:

ax2.set_xticks([])
ax2.set_yticks([])

enter image description here