Reputation: 11
I'm trying to create 3D scatter plot using matplotlib where the area under the graph will be filled with colours.
I want to get (from https://austringer.net/wp/index.php/2011/05/20/plotting-a-dolphin-biosonar-click-train/): but with a gradient fill instead.
So far I've tried:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
%matplotlib widget
%matplotlib qt
for i in range(len(plot_data)):
ev=plot_data[i][:,0]
off=plot_data[i][:,1]
#change lp to match the length of the ev array
lp_plot=np.log(np.repeat(lp[i],len(ev)))
# Plotting the 3D scatterplot but with lines instead of markers
ax.plot(ev,lp_plot[0], off, zdir='z',ls='-')
gradient_fill(ev,off, fill_color=None, ax=None)
ax.scatter(ev, lp_plot, off ,cmap='viridis',marker='')
where my gradient_fill function is as below:
def gradient_fill(x, y, fill_color=None, ax=None, **kwargs):
"""
Plot a line with a linear alpha gradient filled beneath it.
Parameters
----------
x, y : array-like
The data values of the line.
fill_color : a matplotlib color specifier (string, tuple) or None
The color for the fill. If None, the color of the line will be used.
ax : a matplotlib Axes instance
The axes to plot on. If None, the current pyplot axes will be used.
Additional arguments are passed on to matplotlib's ``plot`` function.
Returns
-------
line : a Line2D instance
The line plotted.
im : an AxesImage instance
The transparent gradient clipped to just the area beneath the curve.
"""
if ax is None:
ax = plt.gca()
line, = ax.plot(x, y, **kwargs)
if fill_color is None:
fill_color = line.get_color()
zorder = line.get_zorder() - 1
alpha = line.get_alpha()
alpha = 1.0 if alpha is None else alpha
z = np.empty((100, 1, 4), dtype=float)
rgb = mcolors.colorConverter.to_rgb(fill_color)
z[:,:,:3] = rgb
z[:,:,-1] = np.linspace(0, alpha, 100)[:,None]
xmin, xmax, ymin, ymax = x.min(), x.max(), y.min(), y.max()
im = ax.imshow(z, aspect='auto', extent=[xmin, xmax, ymin, ymax],
origin='lower', zorder=zorder)
xy = np.column_stack([x, y])
xy = np.vstack([[xmin, ymin], xy, [xmax, ymin], [xmin, ymin]])
clip_path = Polygon(xy, facecolor='none', edgecolor='none', closed=True)
ax.add_patch(clip_path)
im.set_clip_path(clip_path)
ax.autoscale(True)
return line, im
Without the gradient fill, I'm getting:
But with it, I'm getting this error:
AttributeError Traceback (most recent call last)
File ...\.venv\Lib\site-packages\ipympl\backend_nbagg.py:279, in Canvas._handle_message(self, object, content, buffers)
276 self.manager.handle_json(content)
278 else:
--> 279 self.manager.handle_json(content)
File ...\.venv\Lib\site-packages\matplotlib\backends\backend_webagg_core.py:464, in FigureManagerWebAgg.handle_json(self, content)
463 def handle_json(self, content):
--> 464 self.canvas.handle_event(content)
File ...\.venv\Lib\site-packages\matplotlib\backends\backend_webagg_core.py:264, in FigureCanvasWebAggCore.handle_event(self, event)
261 e_type = event['type']
262 handler = getattr(self, f'handle_{e_type}',
263 self.handle_unknown_event)
--> 264 return handler(event)
File ...\.venv\Lib\site-packages\matplotlib\backends\backend_webagg_core.py:279, in FigureCanvasWebAggCore.handle_draw(self, event)
278 def handle_draw(self, event):
--> 279 self.draw()
File ...\.venv\Lib\site-packages\matplotlib\backends\backend_webagg_core.py:189, in FigureCanvasWebAggCore.draw(self)
187 self._png_is_old = True
188 try:
--> 189 super().draw()
...
443 reverse=True):
444 if isinstance(artist, mcoll.Collection):
445 artist.zorder = collection_zorder
AttributeError: 'Polygon' object has no attribute 'do_3d_projection'
What did I do wrong?
Upvotes: 0
Views: 40