Horatio
Horatio

Reputation: 11

How do I create a 3D scatter plot with a vertical fill under the graph?

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: enter image description here

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

Answers (0)

Related Questions