Python axis scaling in matplotlib - python

I am trying to make my plots a bit more readable and have come across a feature where the axes are automatically scaled by factors of tens (so instead of the y axis reading 0.00000005, 0.00000007, 0.00000009, it reads 0.5,0.7,0.9 and then says 1e-7 at the top of the axis). However some of my plots don't scale the axes automatically, and I would like to get advise of how to do that manually.
I have found threads on manually setting the tick marks, however I haven't been able to find threads on scaling only.
I can't imbed pictures but here is a link to a picture of what I would like to do: Ideal y axis and here's link to a picture of what I want to avoid: Current y axis.
I'm using seaborn formatting and matplotlib for plots and my code looks like this:
plt.plot(x_j_n,y_j_n, label='Scanning i negativ retning', color='grey', ls='dashed')
plt.plot(x_j_p,y_j_p, label='Scanning i positiv retning', color='black', ls='dashed')
plt.errorbar(x_j_n,y_j_n, yerr=std_j_n, fmt='o', color='black', mfc='white', label = 'Usikkerhed')
plt.errorbar(x_j_p,y_j_p, yerr=std_j_p, fmt='o', color='grey', mfc='white', label = 'Usikkerhed')
plt.ylabel('Målt spænding i volt (V)')
plt.xlabel('Påtrykt felt i tesla (T)')
plt.legend()
plt.show;

Set the y axis to scientific:
plt.gca().yaxis.get_major_formatter().set_scientific(True)
For example:
x = [1100000,2200000,3300000]
y = [1100000,2200000,3300000]
plt.plot(x,y)
plt.gca().xaxis.get_major_formatter().set_scientific(False)
plt.gca().yaxis.get_major_formatter().set_scientific(True)
plt.show()
will give:

Related

Impose minor grid on plot with y log scale, using Python

I'm making some plots with mathplotlib, the y axis is in log scale. I want to have both major and minor grids on both X and Y axis. The first plot comes out perfect (meaning that my code works), while in the second plot the y-minorgrid is suppressed (I assume for ease of visualisation reasons). I want to overcome this and impose the presence of y-minorgrid, even if the resulting plot looks less clear.
Any suggestion?
Current code is
fig, axes = plt.subplots(1, 1, figsize=[18, 10])
axes.plot(DF['value'])
axes.set_title('whatever')
axes.set_ylabel('Pressure [mbar]')
axes.set_xlabel('time [s]')
axes.set_yscale('log')
axes.set_ylim([1E-8, 10000])
axes.grid(b=True, which='minor', color='orange', linestyle=':')
axes.grid(b=True, which='major')
axes.minorticks_on()
take a look at this post below that may be helpful to your scenario. Good luck!
matplotlib: Setting both major and minor ticks forces same x and y scale

Adding histogram and 1 std band to residual plot

I have plotted a graph in python with a subplot of residuals and am trying to find a way to at a histogram plot of the residuals on the end of the histogram plot. I would also like to add a grey band on the residual plot showing 1 standard deviation.
also is there a way to remove the top and right-hand side boarders of the plot.
Here is a copy of the code and the graph I currently have.
fig1 = pyplot.figure(figsize =(9.6,7.2))
plt.frame1 =fig1.add_axes((0.2,0.4,.75,.6))
pyplot.errorbar(xval, yval*1000, yerr=yerr*1000, xerr=xerr, marker='x', linestyle='None')
# Axis labels
pyplot.xlabel('Height (m)', fontsize = 12)
pyplot.ylabel('dM/dt (g $s^{-1}$)', fontsize = 12)
# Generate best fit line using model function and best fit parameters, and add to plot
fit_line=model_funct(xval, [a_soln, b_soln])
pyplot.plot(xval, fit_line*1000)
# Set suitable axis limits: you will probably need to change these...
#pyplot.xlim(-1, 61)
#pyplot.ylim(65, 105)
# pyplot.show()
plt.frame2 = fig1.add_axes((0.2,0.2,.75,.2)) #start frame1 at 0.2, 0.4
plt.xlabel("Height of Water (m)", fontsize = 12)
plt.ylabel("Normalised\nResiduals", fontsize = 12) #\n is used to start a new line
plt.plot(h,normalised_residuals,"x", color = "green")
plt.axhline(0, linewidth=1, linestyle="--", color="black")
plt.savefig("Final Graph.png", dpi = 500)
The naming in your code is a bit weird, therefore I only post snippets since it is hard to try it by myself. Sometimes you use pyplot and sometimes you use plt which should be the same. Also you should name your axis like this ax = fig1.add_axes((0.2,0.4,.75,.6)). Then, if you do the plot, you should call it with the axis directly, i.e. use ax.errorbar().
To hide the borders of the axis in the top plot use:
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.yaxis.set_ticks_position('left')
ax.xaxis.set_ticks_position('bottom')
Adding an error band in the bottom plot is pretty easy to do. Just calculate the mean and standard deviation using np.mean() and np.std(). Afterwards, call
plt.fill_between(h, y1=np.mean(normalised_residuals) - np.std(normalised_residuals),
y2=np.mean(normalised_residuals) + np.std(normalised_residuals),
color='gray', alpha=.5)
and change the color and alpha however you want it to be.
For the histogram projection you just add another axis like you've done it two times before (let's assume it is called ax) and call
ax.hist(normalised_residuals, bins=8, orientation="horizontal")
Here, bins has to be set to a small value probably since you don't have that many data points.

matplotlib pyplot 2 plots with different axes in same figure

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.
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()
You can then turn off the x and y ticks for the linear scale plot like this:
ax2.set_xticks([])
ax2.set_yticks([])
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/

Matplotlib interactive navigation zoom-to-rectangle button doesn't work

I have this Python code to plotting a figure:
matplotlib.rcParams['axes.unicode_minus'] = False
fig = plt.figure()
ax = fig.add_subplot(111)
I draw each plot running a loop along x and y like this:
ax.plot(x, y, dotFormat)
ax.errorbar(x, y, yerr=errorStd, fmt=dotFormat)
Finally, I set the axes and show the chart with the interactive navigation:
ax.grid(True)
ax.set_title(chartTitle)
fontsize=10
ax.set_ylabel(yLabel, fontsize=fontsize+2)
ax.set_xlabel(xLabel+'\n', fontsize=fontsize+2)
ax.set_yticklabels(ax.get_yticks(), fontsize=fontsize)
ax.set_xticks(range(len(xMinorLabels)), minor=True)
ax.set_xticklabels(xMinorLabels, minor=True, rotation=90, fontsize=fontsize-5)
ax.set_xticks(xMajorPosition, minor=False)
ax.set_xticklabels(xMajorLabels, minor=False, rotation=90, fontsize=fontsize-4)
plt.show()
If I use the tool zoom-to-rectangle and the Y-axis doesn't work property, because the same dot before zooming in is under 5, and after zooming in it is over 5.
What is happening with the y-axis when I use the zoom tool? Is a bug in the interactive navigation of matplotlib library? Without this tool, the library is useless for huge charts.
Thanks in advance!
The problem is this
ax.set_yticklabels(ax.get_yticks(), fontsize=fontsize)
section. set_yticklabels sets the value of the tick independent of the data. That is the third tick will always be the third entry of what ever you passed in.
set_*ticklabels should be considered dangerous and only used in very specialized situations.
You can set the font size via ax.tick_params(...) doc, example

rotating xticks causes the ticks partially hidden in matplotlib

I am creating a plot with names on x axis and time values(minutes) on y axis.The names on x axis are like
['cooking']18:15:27 ,['study']18:09:19,['travel']18:21:34` etc ..
where as the y values are 5,1,1 etc.I have given xlabel as 'categories' and ylabel as 'durations in minutes'.
Since the xticks were strings of some length,I decided to rotate them by 90 to avoid overlapping.Now ,the ticks are partially hidden and the xlabel has disappeared.
Is there some way I can make the whole plot accommodate everything..?
thanks
mark
here is the code snippet
import matplotlib.pyplot as plt
...
figure = plt.figure()
barwidth = 0.25
ystep = 10
plt.grid(True)
plt.xlabel('categories')
plt.ylabel('durations in minutes')
plt.title('durations for categories-created at :'+now)
plt.bar(xdata, ydata, width=barwidth,align='center')
plt.xticks(xdata,catnames,rotation=90)
plt.yticks(range(0,maxduration+ystep,ystep))
plt.xlim([min(xdata) - 0.5, max(xdata) + 0.5])
plt.ylim(0,max(ydata)+ystep)
figure.savefig("myplot.png",format="png")
plt.tight_layout()
But be sure to add this command after plt.plot() or plt.bar()
One good option is to rotate the tick labels.
In your specific case, you might find it convenient to use figure.autofmt_xdate() (Which will rotate the x-axis labels among other things).
Alternatively, you could do plt.setp(plt.xticks()[1], rotation=30) (or various other ways of doing the same thing).
Also, as a several year later edit, with recent versions of matplotlib, you can call fig.tight_layout() to resize things to fit the labels inside the figure, as #elgehelge notes below.
Setting the bounding box when saving will also show the labels:
figure.savefig('myplot.png', bbox_inches='tight')

Categories

Resources