I create scatterplots with code that, in essence, goes like this
cmap = (matplotlib.color.LinearSegmentedColormap.
from_list('blueWhiteRed', ['blue', 'white', 'red']))
fig = matplotlib.figure.Figure(figsize=(4, 4), dpi=72)
ax = fig.gca()
for record in data:
level = record.level # a float in [0.0, 1.0]
marker = record.marker # one of 'o', 's', '^', '*', etc.
ax.scatter(record.x, record.y, marker=marker,
c=level, vmin=0, vmax=1, cmap=cmap, **otherkwargs)
# various settings of ticks, labels, etc. omitted
canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(fig)
fig.set_canvas(canvas)
canvas.print_png('/path/to/output/fig.png')
My question is this:
What do I need add to the code above to get a vertical colorbar (representing the colormap in cmap
) along the plot's right edge?
NOTE: I find Matplotlib utterly incomprehensible, and this goes for both its design as well as its documentation. (Not for lack of trying: I have putting a lot of time, effort, and even some money, into it.) So I would appreciate complete, working code (even if it's just a toy example), because most likely I won't be able to fill in omitted details or fix bugs in the code.
EDIT: I fixed an important omission in the "code sketch" above, namely a record-specific marker specification in each call to ax.scatter
. This is the reason for creating the scatterplot with multiple calls to ax.scatter
, although, admittedly, one could at least reduce the number of calls to scatter to one per maker shape used; e.g.
for marker in set(record.marker for record in data):
X, Y, COLOR = zip(*((record.x, record.y, record.level)
for record in data if record.marker == marker))
ax.scatter(X, Y, marker=marker,
c=COLOR, vmin=0, vmax=1, cmap=cmap,
**otherkwargs)
I tried to extend the same trick to collapse all calls to ax.scatter
into one (by passing a sequence of markers as the marker
argument), like this:
X, Y, COLOR, MARKER = zip(*((record.x, record.y, record.level, record.marker)
for record in data))
ax.scatter(X, Y, marker=MARKER,
c=COLOR, vmin=0, vmax=1, cmap=cmap,
**otherkwargs)
...but this fails. The error goes something like this (after pruning some long paths):
Traceback (most recent call last):
File "src/demo.py", line 222, in <module>
main()
File "src/demo.py", line 91, in main
**otherkwargs)
File "<abbreviated-path>/matplotlib/axes.py", line 6100, in scatter
marker_obj = mmarkers.MarkerStyle(marker)
File "<abbreviated-path>/matplotlib/markers.py", line 113, in __init__
self.set_marker(marker)
File "<abbreviated-path>/matplotlib/markers.py", line 179, in set_marker
raise ValueError('Unrecognized marker style {}'.format(marker))
ValueError: Unrecognized marker style ('^', 'o', '^', '*', 'o', 's', 'o', 'o', '^', 's', 'o', 'o', '^', '^', '*', 'o', '*', '*', 's', 's', 'o', 's', 'o', '^', 'o', 'o', '*', '^', 's', '^', '^', 's', '*')
AFAICT, tcaswell's recipe requires reducing the calls to ax.scatter
to a single one, but this requirement appears to conflict with my absolute requirement for multiple marker shapes in the same scatterplot.
See Question&Answers more detail:
os