boxplots with not-in-scale y-axis - python

I have some data I want to box plot. Outliers (e.g. 20, 30) are too far away from most values (e.g. 0.0002, 0.0003) and as a consequence I can only see outliers when I plot with matplotlib.
Is there anyway to zoom in the values around the median and then let the rest of the y-axis not be in scale and display outliers too?
EDIT
Here's my code in python. I would like to use inset axes, as suggested below, for each box plot I have. How can I do this in an easy way? There seems to be way too many parameters to take care of from the examples in the documentation.
plt.figure()
ax = plt.subplot(111)
plt.boxplot(dataToPlot)
axins = zoomed_inset_axes(ax, 6, loc=1) # zoom = 6
# what follows is taken from example linked in the answer below.
# I didn't get if the first argument is indeed the data this zoomed image refers to or not.
axins.imshow(dataToPlot[1], interpolation="nearest", origin="lower")
# here I only need the y-axis to be in [0,0.1], x-axis is no of use with vertical boxplots
x1, x2, y1, y2 = -1.5, -0.9, 0.0, 0.1
axins.set_xlim(x1, x2)
axins.set_ylim(y1, y2)
plt.xticks(visible=True)
plt.yticks(visible=True)
plt.savefig( 'somewhere.jpeg', bbox_inches=0)

You could do an inset axes as described on this page, about 1/2 way down.
inset axes

Very old question, but I came across this looking for something similar. I solved this by adding sym='' (this option may have not existed 7 years ago!) which tells boxplot not to show fliers (anything past the whiskers).
So for anyone else who comes across this, you might try changing line 3 in the question to:
plt.boxplot(dataToPlot, sym='')

Related

Tight curves in a plot in python

I have four curves to plot in Python, each one corresponds to a certain value of a parameter γ. As one may see in the figure, the four curves are really tight with almost no distinction between them. I would like to do a plot as the one in the figure and to add a subplot inside where the difference of the lines could be seen.
I tried reducing the scales but it looks impossible.
Is there a in-built way in matplotlib to see these differences?
Here is a csv file with the values of each curve!
Well, thanks to #JohanC I found a walk around solution on https://matplotlib.org/3.3.1/gallery/subplots_axes_and_figures/zoom_inset_axes.html
dataframe = pd.read_csv('z_curves.csv')
fig, ax = plt.subplots()
r=dataframe['rad']
z_2=dataframe['z_2']
z_4=dataframe['z_4']
z_6=dataframe['z_6']
z_8=dataframe['z_8']
ax.plot(r,z_2,"k")
ax.plot(r,z_4,"k--")
ax.plot(r,z_6,"k:")
ax.plot(r,z_8,"k-.")
ax.plot(r,[0.0 for i in range(len(r))],"g--")
ax.set_xlabel('$r/r_c$',fontsize=20)
ax.set_ylabel('$e^{\\nu(r)}-1$',fontsize=20)
plt.xlim(0.0,1.0)
plt.ylim(-0.000001,0.0000001)
targets = ["$\gamma=0.2$", "$\gamma=0.4$", "$\gamma=0.6$", "$\gamma=0.8$"]
legend = plt.legend(targets,loc='best', shadow=True)
legend.get_frame().set_facecolor('white')
axins = ax.inset_axes([0.4, 0.4, 0.4, 0.4])
x1, x2, y1, y2 = 0.2, 0.201, -5.5634547184309856e-08, -5.5606744002038696e-08
axins.set_xlim(x1, x2-0.0008)
axins.plot(r,z_2,"k")
axins.plot(r,z_4,"k--")
axins.plot(r,z_6,"k:")
axins.plot(r,z_8,"k-.")
axins.set_ylim(y1, y2)
axins.set_xticklabels('')
axins.set_yticklabels('')
ax.indicate_inset_zoom(axins)
plt.show()

Matplotlib - axvspan vs subplots

I'm writing a pythonic script for a coastal engineering application which should output, amongst other things, a figure with two subplots.
The problem is that I would like to shade a section of both subplots using plt.axvspan() but for some reason it only shades one of them.
Please find below an excerpt of the section of the code where I set up the plots as well as the figure that it's currently outputting (link after code).
Thanks for your help, and sorry if this is a rookie question (but it just happens that I am indeed a rookie in Python... and programming in general) but I couldn't find an answer for this anywhere else.
Feel free to add any comments to the code.
# PLOTTING
# now we generate a figure with the bathymetry vs required m50 and another figure with bathy vs Hs
#1. Generate plots
fig = plt.figure() # Generate Figure
ax = fig.add_subplot(211) # add the first plot to the figure.
depth = ax.plot(results[:,0],results[:,1]*-1,label="Depth [mDMD]") #plot the first set of data onto the first set of axis.
ax2 = ax.twinx() # generate a secondary vertical axis with the same horizontal axis as the first
m50 = ax2.plot(results[:,0],results[:,6],"r",label="M50 [kg]") # plot the second set of data onto the second vertical axis
ax3 = fig.add_subplot(212) # generate the second subplot
hs = ax3.plot(results[:,0],results[:,2],"g",label="Hs(m)")
#Now we want to find where breaking starts to occur so we shade it on the plot.
xBreakingDistance = results[numpy.argmax(breakingIndex),0]
# and now we plot a box from the origin to the depth of breaking.
plt.axvspan(0,xBreakingDistance,facecolor="b",alpha=0.1) # this box is called a span in matplotlib (also works for axhspan)
# and then we write BREAKING ZONE in the box we just created
yLimits = ax.get_ylim() # first we get the range of y being plotted
yMiddle = (float(yLimits[1])-float(yLimits[0])) / 2 + yLimits[0] # then we calculate the middle value in y (to center the text)
xMiddle = xBreakingDistance / 2 # and then the middle value in x (to center the text)
#now we write BREAKING ZONE in the center of the box.
ax.text(xMiddle,yMiddle,"BREAKING ZONE",fontweight="bold",rotation=90,verticalalignment="center",horizontalalignment="center")
#FIGURE FORMATTING
ax.set_xlabel("Distance [m]") # define x label
ax.set_ylabel("Depth [mDMD]") # define y label on the first vertical axis (ax)
ax2.set_ylabel("M50 [kg]") # define y label on the second vertical axis (ax2)
ax.grid() # show grid
ax3.set_xlabel("Distance[m]") #define x label
ax3.set_ylabel("Hs[m]") # define y label
ax3.grid()
plt.tight_layout() # minimize subplot labels overlapping
# generating a label on a plot with 2 vertical axis is not very intuitive. Normally we would just write ax.label(loc=0)
combined_plots = depth+m50 #first we need to combine the plots in a vector
combined_labels = [i.get_label() for i in combined_plots] # and then we combine the labels
ax.legend(combined_plots,combined_labels,loc=0) # and finally we plot the combined_labels of the combined_plots
plt.savefig("Required M50(kg) along the trench.png",dpi=1000)
plt.close(fig)
Output Figure:
By just calling plt.axvspan, you are telling matplotlib to create the axvspan on the currently active axes (i.e. in this case, the last one you created, ax3)
You need to plot the axvspan on both of the axes you would like for it to appear on. In this case, ax and ax3.
So, you could do:
ax.axvspan(0,xBreakingDistance,facecolor="b",alpha=0.1)
ax3.axvspan(0,xBreakingDistance,facecolor="b",alpha=0.1)
or in one line:
[this_ax.axvspan(0,xBreakingDistance,facecolor="b",alpha=0.1) for this_ax in [ax,ax3]]
It's difficult to analyze your code and not being able to reproduce it. I advise you to build a minimal example. In any case notice that you are calling "plt.axvspan(" which is general call to the library.
You need to specifically state that you want this in both "ax" and "ax2" (i think).
Also if you need more control consider using Patches (I don't know axvspan):
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig1 = plt.figure()
ax1 = fig1.add_subplot(111, aspect='equal')
ax1.add_patch(
patches.Rectangle(
(0.1, 0.1), # (x,y)
0.5, # width
0.5, # height
)
)
fig1.savefig('rect1.png', dpi=90, bbox_inches='tight')
See that call to "ax1" in the example? Just make something similar to yours. Or just add axvspan to each of your plots.

Matplotlib axes autoscale does not work with after twinx()

I have found that I can not get axes autoscale to work on the 1st axes after creating a second axes using twinx. Is this expected?
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 10, 0.1)
y1 = 0.05 * x**2
y2 = -1 *y1
fig, axL = plt.subplots() # Make Left Axes
axR = axL.twinx() # Make Left Axes
axL.plot(x, y1, 'g-') # Plot on Left
axL.grid()
axL.autoscale(enable=True, axis=u'both', tight=False)
plt.show()
# Do some stuff then later plot on axR
When I run the above code it autoscales in the y-direction correctly on the left axes (0 to 5) but changes the X-Axis scale to +/- 0.06 instead of the correct 0 to 10. However, once axR is no longer blank and something is plotted on axR it behaves as I would expect.
This is only an example as I first came across this issue in more complicated PyQT4 GUI that allows the user to create multiple subplots & left/right combinations. Since the user is the one manually controlling the plot creation order it is possible for the above situation to present itself.
Is there a way for autoscale to work with a blank twinx right axes. Or is the Xlimit just going to have to be manually set?
FYI, I am using Python 3.4 as part of Anaconda v2.0.1 with Matplotlib v1.3.1
Thanks.
This is merely a workaround than a proper solution or explanation.
Simply add an invisible point in the right axes so it is not completely empty:
axR.plot(0, 0, visible=False)
You have to make sure though, that the invisible point lies within the ranges of the data that you plot in axL. E.g.:
axR.plot(np.mean(x),np.mean(y1),visible=False)
As for an explanation (I'm guessing):
axR.dataLim is [-np.inf, np.inf] initially. The union of axR.dataLim and axL.dataLim still gives [-np.inf, np.inf] which is then collapsed to [0,0].
EDIT: This was fixed recently (here). Upgrading to matplotlib v1.4.* should solve the problem.

physically stretch plot in horizontal direction in python

I want a simple x,y plot created with matplotlib stretched physically in x-direction.
The intention is to get a result were it is easier for me to detect features in the signal.
So I don't want to change any scales or values or limits. Just change the distance between two gridpoint in my output file...
I want to do that on four subplots which should have the same size afterwards.
Thanks in advance... I tried for hours now and I think one of you could probably help me...
David Zwicker already solved my problem in this special case, thanks a lot for that, but in general... If I plot 2 subplots like in this code:
fig = plt.figure()
ax1 = fig.add_subplot(1,2,1)
plot(u_av,z)
ax2 = fig.add_subplot(1,2,2)
plot(pgrd_av,z)
clf()
and want to stretch only one of them. What can I do?
You can change the figure size by using plt.figure(figsize=(20,5)). See the documentation of the figure command.
I know, this is a bit out of the context. But if someone is looking for a solution while using pandas plot which internally uses matplotlib. Here is the solution.
df.plot('col_x', 'col_y', title='stretched_plot', figsize=(20, 1))
You can directly add axes to the canvas at an arbitrary position with plt.axes(). For instance:
ax1 = plt.axes([0, 0, 3, 0.5])
ax2 = plt.axes([0, 0.6, 1, 1])
You can do this:
x = 1.5 # or your needed amount
plt.plot(x_array * x, y_array)
Your line or graph will move to the right depending on your x value

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