2

I'm trying to create an interactive figure with a slider, but I'd also like to shade the region under the graph I'm drawing. The following code (adapted from Interactive matplotlib plot with two sliders) produces an interactive graph:

import numpy as np
from numpy import pi
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider

#Define the function we're graphing
def gaussian(x, sigma):
    N = pow(2*pi,-0.5)/sigma
    Z = x/sigma
    return N*np.exp(-Z*Z/2)

#Default standard deviation of 1
std0=1

#Set up initial default data
X = np.arange(-5,5,0.1)
Y = gaussian(X,std0)

#Create an axis for main graph
fig, ax = plt.subplots(1,1)
ax.set_xlim([-5,5])
ax.set_ylim([0,1])

#[line] will be modified later with new Y values
[line]=ax.plot(X,Y)
#this moves the figure up so that it's not on top of the slider
fig.subplots_adjust(bottom=0.4)

#Create slider
sigma_slider_ax = fig.add_axes([0.25,0.25,0.65,0.03])
sigma_slider = Slider(sigma_slider_ax, 'Standard Deviation', 0.5,2.0,valinit=std0)

#Define what happens when sliders changed
def line_update(val):
    Y = gaussian(X,sigma_slider.val)
    line.set_ydata(Y)
    fig.canvas.draw_idle()
#Call the above function when the slider is changed
sigma_slider.on_changed(line_update)

plt.show()

Still image of output of code - gaussian curve with slider beneath

What I want is for it to be shaded under the graph. If it's not interactive then the solution at: How to shade region under the curve in matplotlib works well (ie use ax.fill(X,Y) not ax.plot(X,Y)). However, with the interactivity I get an error:

"AttributeError: 'Polygon' object has no attribute 'set_ydata'"

Any idea how to achieve this?

jacob1729
  • 123
  • 4

1 Answers1

3

In pyplot, you can fill under the curve using fill_between. With animation, clear the previous data using fill_between with a white fill.

Here is the updated code:

#Define what happens when sliders changed
def line_update(val):
    ax.fill_between([-5,5], [1,1], facecolor='white', alpha=1)  # fill white
    #ax.fill_between(X, [1 for v in Y], facecolor='white', alpha=1)  # fill white
    Y = gaussian(X,sigma_slider.val)
    line.set_ydata(Y)
    ax.fill_between(X, Y, facecolor='blue', alpha=0.30) # fill blue
    fig.canvas.draw_idle()

#Call the above function when the slider is changed
sigma_slider.on_changed(line_update)
line_update(0)  # fill curve first time

plt.show()

Output

Fill

Mike67
  • 11,175
  • 2
  • 7
  • 15
  • Thanks, this is perfect! Two questions though: (1) What is the point of the line declaring global Y, ax? (2) Instead of setting the fill to be white under the graph, is there any downside to making it white everywhere (eg ax.fill_between([-5,5],[1,1],'white') should do that I think?) – jacob1729 Sep 07 '20 at 13:53
  • You are correct. Using [-5,5],[1,1] also works in this case.Good catch. As for the `global`, I think that was left over from various attempts at solutions. Answer updated with changes. – Mike67 Sep 07 '20 at 14:03