Reputation: 42439
This is a rather simple issue at first glance, but I haven't been able to find a solution. There's a similar (old) question here but the closest answer given does not seem to apply to error bars in both dimensions.
I need to generate an "errorbar" plot where both error bars (in the x and y dimensions) are colored according to the values in the cc
array.
The code:
import numpy as np
import matplotlib.pyplot as plt
# Some random data
aa = np.array([3.581, -0.721, 0.137, 0.645, 0.12, 0., -3.236, 0.248, -5.687, 0.816])
e_aa = np.array([0.111, 0.991, 0.446, 0.07, 0.814, 0., 0.088, 0.805, 0.178, 0.552])
bb = np.array([6.671, 1.219, 0.119, -1.972, 1.834, 0., 4.93, 1.833, -11.542, -0.439])
e_bb = np.array([0.143, 1.316, 0.609, 0.094, 1.127, 0., 0.116, 1.227, 0.216, 0.726])
# The color array
cc = np.array([0.50344083, 0.49961867, 0.5055576, 0.48970365, 0.5078516, 0.49643923, 0.50089907, 0.50129157, 0.49627974, 0.5052376])
plt.errorbar(aa, bb, yerr=e_bb, xerr=e_aa, fmt='none', ecolor=cc)
plt.show()
fails with a:
ValueError: Invalid RGBA argument: 0.50344083
whether I use the ecolor
or color
argument.
Is there any way around this?
Upvotes: 2
Views: 2436
Reputation: 42439
I've found a solution. The trick is to map the floats to a valid colormap using matplotlib.cm
.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib.colors import Normalize
# Some random data
aa = np.array([3.581, -0.721, 0.137, 0.645, 0.12, 0., -3.236, 0.248, -5.687, 0.816])
e_aa = np.array([0.111, 0.991, 0.446, 0.07, 0.814, 0., 0.088, 0.805, 0.178, 0.552])
bb = np.array([6.671, 1.219, 0.119, -1.972, 1.834, 0., 4.93, 1.833, -11.542, -0.439])
e_bb = np.array([0.143, 1.316, 0.609, 0.094, 1.127, 0., 0.116, 1.227, 0.216, 0.726])
# The color array
cc = np.array([0.50344083, 0.49961867, 0.5055576, 0.48970365, 0.5078516, 0.49643923, 0.50089907, 0.50129157, 0.49627974, 0.5052376])
# Define function to map (normalized) values in `cc` to a colormap
cmap = cm.viridis
norm = Normalize(vmin=cc.min(), vmax=cc.max())
plt.errorbar(aa, bb, yerr=e_bb, xerr=e_aa, fmt='none', ecolor=cmap(norm(cc)))
plt.show()
Upvotes: 3
Reputation: 6440
plt.errorbar()
generates a three separate objects: the line between points, the lines for each errorbar cap (if any), and a matplotlib.collections.LineCollection
containing the errorbar lines themselves. The ecolor
argument is ultimately passed to matplotlib.collections.LineCollection.set_color()
, which accepts a:
Matplotlib color argument (all patches have the same color) or a sequence of rgba tuples; if it is a sequence the patches will cycle through the sequence.
Your array cc
is neither of these. The method receives a sequence, so it tries to set the color of each line in the collection to each element of the sequence. But those elements are just single floats, which are not valid matplotlib colors.
To fix this, generate a list of tuples, with each tuple specifying the RGB[A] color of the line segments for each errrorbar. For example, using the other data you specified in your question, the colors can be set as:
cc = np.random.rand(aa.size, 3) # Random colors, RGB tuples uniform on (0, 1)
collections = plt.errorbar(aa, bb, yerr=e_bb, xerr=e_aa, fmt='none', ecolor=cc)
This generates a plot like so:
Upvotes: 2