making errorbars not clipped in matplotlib with Python - python

I am using matplotlib in Python to plot a line with errorbars as follows:
plt.errorbar(xvalues, up_densities, yerr=ctl_sds, fmt='-^', lw=1.2, markersize=markersize,
markeredgecolor=up_color, color=up_color, label="My label", clip_on=False)
plt.xticks(xvalues)
I set the ticks on the x-axis using "xticks". However, the error bars of the last point in xvalues (i.e. xvalues[-1]) are clipped on the right -- meaning only half an error bar appears. This is true even with the clip_on=False option. How can I fix this, so that the error bars appear in full, even though their right side is technically outside xvalues[-1]?
thanks.

In matplotlib, most of the detailed control needs to be done through the Artists. I think this should do what you want:
import matplotlib.pyplot as plt
from random import uniform as r
x = range(10)
e = plt.errorbar(x, [r(2,10) for i in x], [r(.1,1) for i in x], capsize=8, color='r')
for b in e[1]:
b.set_clip_on(False)
plt.show()
The problem you were having is that the clip_on keyword was being used to control the markers and not the error bars. To control the errorbars, plt.errorbar returns a tuple, where the second item is a list of errorbars. So here I go through the list and turn the clipping off for each errorbar.

Is this what you mean? Do you want to redefine the horizontal limits of your plot?
plt.errorbar(range(5), [3,2,4,5,1], yerr=[0.1,0.2,0.3,0.4,0.5])
ax = plt.gca()
ax.set_xlim([-0.5,4.5])
(source: stevetjoa.com)

Related

Matplotlib: Grid lines behind bars on twinned axes?

I'm plotting two series on one chart using twiny() and want the grid lines behind the bars. However, by default the behaviour is mixed: in front of elements of the original axes and behind the twin's.
Neither axes.set_axisbelow(True) nor zorder=0 with the grid call fixes this. Is this a bug in matplotlib? Anyone know of a work around?
Here's an example to illustrate:
import matplotlib, matplotlib.pyplot as plt
print('matplotlib: {}'.format(matplotlib.__version__))
series1 = [1.25,2.25,3]
series2 = [12,9.75,6.75]
categories = ['A','B','C']
fig, axes1 = plt.subplots(nrows=1,ncols=1)
axes2 = axes1.twiny()
axes1.barh(categories, series1, color='red', align='edge', height=-0.4)
axes2.barh(categories, series2, color='blue', align='edge', height=+0.4)
axes1.set_axisbelow(True)
axes2.set_axisbelow(True)
axes1.grid(axis='x')
axes2.grid(axis='x')
plt.show()
matplotlib v. 3.2.2
Everything drawn on one axis (including the grid) is always or completely before or completely behind everything drawn on the other axis. The only solution in your case is to only draw a grid for axes1, removing the call to the grid for the other axis.

Matplotlib: how to scale the y axis according to the y-value? [duplicate]

I'm trying to create a histogram of a data column and plot it logarithmically (y-axis) and I'm not sure why the following code does not work:
import numpy as np
import matplotlib.pyplot as plt
data = np.loadtxt('foo.bar')
fig = plt.figure()
ax = fig.add_subplot(111)
plt.hist(data, bins=(23.0, 23.5,24.0,24.5,25.0,25.5,26.0,26.5,27.0,27.5,28.0))
ax.set_xlim(23.5, 28)
ax.set_ylim(0, 30)
ax.grid(True)
plt.yscale('log')
plt.show()
I've also tried instead of plt.yscale('log') adding Log=true in the plt.hist line and also I tried ax.set_yscale('log'), but nothing seems to work. I either get an empty plot, either the y-axis is indeed logarithmic (with the code as shown above), but there is no data plotted (no bins).
try
plt.yscale('log', nonposy='clip')
http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.yscale
The issue is with the bottom of bars being at y=0 and the default is to mask out in-valid points (log(0) -> undefined) when doing the log transformation (there was discussion of changing this, but I don't remember which way it went) so when it tries to draw the rectangles for you bar plot, the bottom edge is masked out -> no rectangles.
The hist constructor accepts the log parameter.
You can do this:
plt.hist(data, bins=bins, log=True)
np.logspace returns bins in [1-10], logarithmically spaced - in my case xx is a npvector >0 so the following code does the trick
logbins=np.max(xx)*(np.logspace(0, 1, num=1000) - 1)/9
hh,ee=np.histogram(xx, density=True, bins=logbins)

How to change the axis interval in matplotlib? [duplicate]

I'm trying to create a histogram of a data column and plot it logarithmically (y-axis) and I'm not sure why the following code does not work:
import numpy as np
import matplotlib.pyplot as plt
data = np.loadtxt('foo.bar')
fig = plt.figure()
ax = fig.add_subplot(111)
plt.hist(data, bins=(23.0, 23.5,24.0,24.5,25.0,25.5,26.0,26.5,27.0,27.5,28.0))
ax.set_xlim(23.5, 28)
ax.set_ylim(0, 30)
ax.grid(True)
plt.yscale('log')
plt.show()
I've also tried instead of plt.yscale('log') adding Log=true in the plt.hist line and also I tried ax.set_yscale('log'), but nothing seems to work. I either get an empty plot, either the y-axis is indeed logarithmic (with the code as shown above), but there is no data plotted (no bins).
try
plt.yscale('log', nonposy='clip')
http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.yscale
The issue is with the bottom of bars being at y=0 and the default is to mask out in-valid points (log(0) -> undefined) when doing the log transformation (there was discussion of changing this, but I don't remember which way it went) so when it tries to draw the rectangles for you bar plot, the bottom edge is masked out -> no rectangles.
The hist constructor accepts the log parameter.
You can do this:
plt.hist(data, bins=bins, log=True)
np.logspace returns bins in [1-10], logarithmically spaced - in my case xx is a npvector >0 so the following code does the trick
logbins=np.max(xx)*(np.logspace(0, 1, num=1000) - 1)/9
hh,ee=np.histogram(xx, density=True, bins=logbins)

Logarithmic y-axis bins in python

I'm trying to create a histogram of a data column and plot it logarithmically (y-axis) and I'm not sure why the following code does not work:
import numpy as np
import matplotlib.pyplot as plt
data = np.loadtxt('foo.bar')
fig = plt.figure()
ax = fig.add_subplot(111)
plt.hist(data, bins=(23.0, 23.5,24.0,24.5,25.0,25.5,26.0,26.5,27.0,27.5,28.0))
ax.set_xlim(23.5, 28)
ax.set_ylim(0, 30)
ax.grid(True)
plt.yscale('log')
plt.show()
I've also tried instead of plt.yscale('log') adding Log=true in the plt.hist line and also I tried ax.set_yscale('log'), but nothing seems to work. I either get an empty plot, either the y-axis is indeed logarithmic (with the code as shown above), but there is no data plotted (no bins).
try
plt.yscale('log', nonposy='clip')
http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.yscale
The issue is with the bottom of bars being at y=0 and the default is to mask out in-valid points (log(0) -> undefined) when doing the log transformation (there was discussion of changing this, but I don't remember which way it went) so when it tries to draw the rectangles for you bar plot, the bottom edge is masked out -> no rectangles.
The hist constructor accepts the log parameter.
You can do this:
plt.hist(data, bins=bins, log=True)
np.logspace returns bins in [1-10], logarithmically spaced - in my case xx is a npvector >0 so the following code does the trick
logbins=np.max(xx)*(np.logspace(0, 1, num=1000) - 1)/9
hh,ee=np.histogram(xx, density=True, bins=logbins)

matplotlib colorbar in subplots: labels are vanishing

I am developing some code to produce an arbitrary number of 2D plots (maps and simple contour plots) on a figure. The matplotlib subplots routine works great for this. In the simplified example below, everything works as it should. However, in my real application - which uses the exact same commands for subplots, contourf and colorbar, only that these are dispersed across several routines - the labels on the colorbars are not showing up (the color patches seem to be ok though). Even after hours of reading documentation and searching the web, I don't even have a clue where I could start looking for what the problem is. If I have my colorbar instance (cbar), I should be able to find out if the ticklabel position makes sense, if the ticklabels are set to visible, if my font settings make sense, etc.... But how do I actually check these properties? Has anyone encountered similar problems already? (and even better: found a solution?) Oh yes: if I manually create a new figure and axes in the actual plotting routine (where the contourf command is issued), then it will work again. But that means losing all control over the figure layout etc. Could it be that I am not passing my axes instance correctly? Here is what I do:
fig, ax = plt.subplots(nrows, ncols)
row, col = getCurrent(...)
plotMap(x, y, data, ax=ax[row,col], ...)
Then, inside plotMap:
c = ax.contourf(x, y, data, ...)
ax.figure.colorbar(c, ax=ax, orientation="horizontal", shrink=0.8)
As said above, the example below with simplified plots and artificial data works fine:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0.,360.,5.)*np.pi/180.
y = np.arange(0.,360.,5.)*np.pi/180.
data = np.zeros((y.size, x.size))
for i in range(x.size):
data[:,i] = np.sin(x[i]**2*y**2)
fig, ax = plt.subplots(2,1)
contour = ax[0].contourf(x, y, data)
cbar = ax[0].figure.colorbar(contour, ax=ax[0], orientation='horizontal', shrink=0.8)
contour = ax[1].contourf(x, y, data, levels=[0.01,0.05,0.1,0.05])
cbar = ax[1].figure.colorbar(contour, ax=ax[1], orientation='horizontal', shrink=0.8)
plt.show()
Thanks for any help!
Addition after some further poking around:
for t in cbar.ax.get_xticklabels():
print t.get_position(), t.get_text(), t.get_visible()
shows me the correct text and visible=True, but all positions are (0.,0.). Could this be a problem?
BTW: axis labels are also missing sometimes... and I am using matplotlib version 1.1.1 with python 2.7.3 on windows.
OK - I could track it down: matplotlib is working as it should!
The error was embedded in a utility routine that adds some finishing touches to each page (=figure) once the given number of plot panels has been produced. In this routine I wanted to hide empty plot panels (i.e. on the last page) and I did this with
ax = fig.axes
for i in range(axCurrent, len(ax)):
ax[i].set_axis_off()
However, axCurrent was already reset to zero when the program entered this routine for any page but the last, hence the axes were switched off for all axes in figure. Adding
if axCurrent > 0:
before the for i... solves the problem.
Sorry if I stole anyone's time. Thanks anyway to everyone who was considering to help!

Categories