Reputation: 923
Is it possibile to have an upper limit (with the down arrow) with the point centered in the the best value and, at the same time, the upper error?
Something like this:
I'm trying with:
import numpy as np
import matplotlib.pyplot as plt
x = np.array([10, 15, 20, 25, 30, 35])
x_el = np.array([1, 1, 2, 25, 1, 2, 1])
x_eu = np.array([1, 1, 2, 1, 1, 2, 1])
y = np.array([29, 15, 9, 10, 25, 14])
y_el = np.array([1, 1, 2, 1, 1, 2, 1])
y_eu = np.array([11,1,2,1,1,2,1])
fig, ax = plt.subplots()
for i in range(len(x)):
if (x[i] - x_el[i]) == 0:
el = 0
ax.errorbar(x[i], y[i], yerr=[[y_el[i]], [y_eu[i]]], xerr=[[el],[x_eu[i]]],
c='b', capsize=2, elinewidth=1, marker='o',
xuplims=True)
else:
ax.errorbar(x[i], y[i], yerr=[[y_el[i]], [y_eu[i]]], xerr=[[x_el[i]], [x_eu[i]]],
c='b', capsize=2, elinewidth=1, marker='o')
But this is the result:
The point number 4 has neither the uplim nor the upper error.
Upvotes: 0
Views: 2645
Reputation: 114290
The short answer is yes, but you have to plot the upper limits and the error bars separately. Let's start by plotting your normal error bars properly. You can do this without looping if your data is in a numpy array already:
import numpy as np
import matplotlib.pyplot as plt
x = np.array([10, 15, 20, 25, 30, 35])
x_el = np.array([1, 1, 2, 25, 1, 2])
x_eu = np.array([1, 1, 2, 1, 1, 2])
y = np.array([29, 15, 9, 10, 25, 14])
y_el = np.array([1, 1, 2, 1, 1, 2])
y_eu = np.array([11, 1, 2, 1, 1, 2])
fig, ax = plt.subplots()
mask = (x != x_el)
ax.errorbar(x, y, yerr=[y_el, y_eu], xerr=[x_el * mask, x_eu],
c='b', capsize=2, elinewidth=1, marker='o', linestyle='none')
Notice that I trimmed the error bar arrays down to the same size as x
, which allows me to compute the mask using the !=
operator. Since you are interested in having all the error bars besides the one in x_el
, I multiply by the mask. The mask is a boolean, and any error bar that is masked out will just be set to zero that way. All the other bars get plotted properly at this point:
Now you can use the same mask (but inverted) to plot the upper limits:
ax.errorbar(x[~mask], y[~mask], xerr=x_el[~mask],
c='b', capsize=2, elinewidth=1, marker='o', linestyle='none',
xuplims=True)
The result is
If you were not interested in having an obscenely long arrow that stretches to zero, you can shorten it to whatever size you like:
ax.errorbar(x[~mask], y[~mask], xerr=1,
c='b', capsize=2, elinewidth=1, marker='o', linestyle='none',
xuplims=True)
Alternative
You could even get pretty close with a single plotting call, since xuplims
accepts an array of booleans. However, anywhere it is True will eliminate the right bar:
mask = (x == x_el)
ax.errorbar(x, y, yerr=[y_el, y_eu], xerr=[x_el, x_eu],
c='b', capsize=2, elinewidth=1, marker='o', linestyle='none',
xuplims=mask)
You end up having to fill in the right bars in this case:
ax.errorbar(x[mask], y[mask], xerr=[np.zeros_like(x_eu)[mask], x_eu[mask]],
c='b', capsize=2, elinewidth=1, marker='o', linestyle='none')
Upvotes: 2