Ipywidgets: alter slider defaults based on a scenario - python
I'm using ipywidges to create a plot. I'd like to have a dropdown with options (e.g. Scenario A, Scenario B). Each scenario should change the slider position (a=0, b=1), and one should be able to modify the parameters freely afterwards. Any ideas?
Here is my toy example:
import ipywidgets as widgets
def line(a=0,b=1):
#fig, ax = plt.subplots(figsize=(6, 4))
x = np.arange(-10,10)
y = a+xrange*b
plt.xlim((-10,10))
plt.ylim((-10,10))
plt.plot(x, y)
widgets.interact(line, a=(-10,10,0.1), b=(-10,10,0.1))
I was playing with an additional wrapper functions but with no success. In reality of course, I would like to have a few more scenarios and a lot more parameters.
Just as another answer, you could also link different widgets. In this case we are going to link the a and b sliders with a Dropdown menu, such that a change of the latter will call the functions on_change_* and switch the default values of the sliders (depending on the chosen scenario).
import ipywidgets as widgets
import numpy as np
import matplotlib.pyplot as plt
def line(a=0,b=0):
x = np.arange(-10,10)
y = a+x*b
plt.xlim((-10,10))
plt.ylim((-10,10))
plt.plot(x, y)
a_slider = widgets.FloatSlider(min=-10, max=10, step=0.1, value=0)
b_slider = widgets.FloatSlider(min=-10, max=10, step=0.1, value=1)
drop = widgets.Dropdown(options=["a", "b"], value="a", description='Scenario:')
def on_choose_a(d):
if drop.value == "a":
a_slider.value = 2
else:
a_slider.value = 5
return a_slider.value
def on_choose_b(d):
if drop.value == "a":
b_slider.value = 3
else:
b_slider.value = 7
return b_slider.value
widgets.dlink((drop, "value"), (a_slider, "value"), on_choose_a)
widgets.dlink((drop, "value"), (b_slider, "value"), on_choose_b)
display(drop)
widgets.interact(line, a=a_slider, b=b_slider);
All right, I think I've found a very nice workaround:
def line(a=0,b=0):
x = np.arange(-10,10)
y = a+x*b
plt.xlim((-10,10))
plt.ylim((-10,10))
plt.plot(x, y)
sliders = widgets.interact(a=(-10,10,0.1), b=(-10,10,0.1))
def test(chose_defaults):
if chose_defaults=="a":
#sliders
def h(a=5,b=5):
return(line(a,b))
if chose_defaults=="b":
#sliders
def h(a=0,b=1):
return(line(a,b))
widgets.interact(test, chose_defaults=["a","b"])
The above code basically nests two widgets. Firstly a separate widget for chosing a scenario is shown; action for the scenarios are the plots that differ only in the default setup.
Related
`update` function doesn't work correctly for bokeh interactors in python
I have a source code that plots the alphashape of a stock price. There's a slider to update the plot dynamically. But the update function doesn't work as expected. Here's the source code. x=[76.84,76.85,76.86,76.87,76.88,76.9,76.91,76.92,76.93,76.94,76.97,76.97,76.98,76.99,77.0,77.03,77.03,77.04,77.05,77.06,77.09,77.09,77.1,77.11,77.12,77.15,77.16,77.16,77.17,77.18,77.21,77.22,77.22,77.23,77.24,77.27,77.28,77.28,77.29,77.3,77.33,77.34,77.35,77.35,77.36,77.39,77.4,77.41,77.41,77.42,77.45,77.46,77.47,77.47,77.48,77.51,77.52,77.53,77.54,77.54,77.57,77.58,77.59,77.6,77.6,77.63,77.64,77.65,77.66,77.66,77.69,77.7,77.71,77.72,77.73,77.75,77.76,77.77,77.78,77.79,77.81,77.82,77.83,77.84,77.85,77.87,77.88,77.89,77.9,77.91,77.93,77.94,77.95,77.96,77.97,77.99,78.0,78.01,78.02,78.03,78.05,78.06,78.07,78.08,78.09,78.13,78.14,78.15,78.17,78.18,78.19,78.2,78.21,78.24,78.24,78.25,78.26,78.27,78.3,78.3,78.31,78.32,78.33,78.36,78.36,78.37,78.38,78.39,78.42,78.43,78.43,78.44,78.45,78.48,78.49,78.49,78.5,78.51,78.54,78.55,78.55,78.56,78.57,78.6,78.61,78.62,78.62,78.63,78.66,78.67,78.68,78.68,78.69,78.72,78.73,78.74,78.74,78.75,78.78,78.79,78.8,78.81,78.81,78.84,78.85,78.86,78.87,78.87,78.91,78.92,78.93,78.94,78.96,78.97,78.98,78.99,79.0,79.02,79.03,79.04,79.05,79.06,79.08,79.09,79.1,79.11,79.12,79.2,79.21,79.22,79.23,79.24,79.26,79.27,79.28,79.29,79.3,79.32,79.33,79.34,79.35,79.36,79.38,79.39,79.4,79.41,79.42,79.44,79.45,79.46,79.47,79.48,79.51,79.51,79.52,79.53,79.54,79.57,79.57,79.58,79.59,79.6,79.63,79.63,79.64,79.65,79.66,79.69,79.7,79.7,79.71,79.72,79.75,79.76,79.76,79.77,79.78,79.81,79.82,79.82,79.83,79.84,79.87,79.88,79.89,79.89,79.9,79.94,79.95,79.95,79.96,79.99,80.0,80.01,80.02,80.02,80.05,80.06,80.07,80.08,80.08,80.11,80.12,80.13,80.14,80.14,80.17,80.18,80.19,80.2,80.21,80.23,80.24,80.25,80.26,80.27,80.29,80.3,80.31,80.32,80.33,80.35,80.36,80.37,80.38,80.39,80.41,80.42,80.43,80.44,80.45,80.47,80.48,80.49,80.5,80.51,80.53,80.54,80.55,80.56,80.57,80.59,80.6,80.61,80.62,80.63,80.65,80.66,80.67,80.68,80.69,80.71,80.72,80.73,80.74,80.75,80.78,80.78,80.79,80.8,80.81,80.84,80.84,80.85,80.86,80.87,80.9,80.9,80.91,80.92,80.93,80.96,80.97,80.97,80.98,80.99,81.02,81.03,81.03,81.04,81.05,81.08,81.09,81.1,81.1,81.11,81.14,81.15,81.16,81.16,81.17,81.2,81.21,81.22,81.22,81.23,81.28,81.29,81.29,81.32,81.33,81.34,81.35,81.35,81.38,81.39,81.4,81.41,81.41,81.44,81.45,81.46,81.47,81.48,81.5,81.51,81.52,81.53,81.54,81.56,81.57,81.58,81.59,81.6,81.62,81.63,81.64,81.65,81.66,81.68,81.69,81.7,81.71,81.72,81.74,81.75,81.76,81.77,81.78,81.8,81.81,81.82,81.83,81.84,81.86,81.87,81.88,81.89,81.9,81.92,81.93,81.94,81.95,81.96,81.98,81.99,82.0,82.01,82.02,82.05,82.06,82.07,82.08,82.11,82.11,82.12,82.13,82.14,82.17,82.18,82.18,82.19,82.2,82.23,82.24,82.24,82.25,82.26,82.29,82.3,82.3,82.31,82.32,82.35,82.36,82.37,82.37,82.38,82.41,82.42,82.43,82.43,82.44,82.59,82.6,82.61,82.62,82.62,82.65,82.66,82.67,82.68,82.68,82.71,82.72,82.73,82.74,82.75,82.77,82.78,82.79,82.8,82.81,82.83,82.84,82.85,82.86,82.87,82.89,82.9,82.91,82.92,82.93,82.95,82.96,82.97,82.98,82.99,83.01,83.02,83.03,83.04,83.05,83.07,83.08,83.1,83.11,83.13,83.14,83.15,83.16,83.17,83.19,83.2,83.21,83.22,83.23,83.26,83.26,83.27,83.28,83.29,83.32,83.32,83.33,83.34,83.35,83.38,83.38,83.39,83.4,83.41,83.44,83.45,83.45,83.46,83.47,83.5,83.51,83.51,83.52,83.53,83.56,83.57,83.57,83.58,83.59,83.62,83.63,83.64,83.64,83.65,83.68,83.69,83.7,83.7,83.71,83.74,83.75,83.76,83.76,83.77,83.8,83.81,83.82,83.83,83.83,83.86,83.87,83.88,83.89,83.89,83.92,83.93,83.94,83.95,83.95,83.98,83.99,84.0,84.01,84.02,84.04,84.05,84.06,84.07,84.08,84.1,84.11,84.12,84.13,84.14,84.16,84.17,84.18,84.19,84.2,84.22,84.23,84.24,84.25,84.26,84.28,84.29,84.3,84.31,84.32,84.34,84.35,84.36,84.37,84.38,84.43,84.44,84.46,84.47,84.48,84.49,84.5,84.53,84.53,84.54,84.55,84.56,84.59,84.59,84.6,84.61,84.62,84.65,84.65,84.66,84.67,84.68,84.71,84.72,84.72,84.73,84.74,84.77,84.78,84.78,84.79,84.8,84.83,84.84,84.84,84.85,84.86,84.89,84.9,84.91,84.91,84.92,84.95,84.96,84.97,84.97,84.98,85.01,85.02,85.03,85.03,85.04,85.07,85.08,85.09,85.1,85.1,85.13,85.14,85.15,85.16,85.16,85.19,85.2,85.22,85.22,85.25,85.26,85.27,85.28,85.29,85.31,85.32,85.33,85.34,85.35,85.37,85.38,85.39,85.4,85.41,85.43,85.44,85.45,85.46,85.47,85.61,85.62,85.63,85.64,85.65,85.67,85.68,85.69,85.7,85.71,85.73,85.74,85.75,85.76,85.77,85.8,85.8,85.81,85.82,85.83,85.86,85.86,85.87,85.88,85.89,85.92,85.92,85.93,85.94,85.95,85.98,85.99,85.99,86.0,86.01,86.04,86.05,86.05,86.06,86.07,86.1,86.11,86.11,86.12,86.13,86.16,86.17,86.18,86.18,86.19,86.22,86.23,86.24,86.28,86.29,86.3,86.3,86.31,86.34,86.35,86.36,86.37,86.37,86.4,86.41,86.42,86.43,86.43,86.46,86.47,86.48,86.49,86.5,86.52,86.53,86.54,86.55,86.56,86.58,86.59,86.6,86.61,86.62,86.64,86.65,86.66,86.67,86.68,86.7,86.71,86.72,86.73,86.74,86.78,86.79,86.8,86.82,86.83,86.84,86.85,86.86,86.88,86.89,86.9,86.91,86.92,86.94,86.95,86.96,86.97,86.98,87.0,87.01,87.02,87.03,87.04,87.07,87.07,87.08,87.09,87.1,87.13,87.13,87.14,87.15,87.16,87.19,87.19,87.2,87.21,87.22,87.25,87.26,87.26,87.27,87.28,87.31,87.32,87.32,87.33,87.34,87.37,87.38,87.38,87.39,87.4,87.43,87.44,87.45,87.45,87.46,87.49,87.5,87.51,87.51,87.52,87.55,87.56,87.61,87.62,87.63,87.64,87.64,87.67,87.68,87.69,87.7,87.7,87.73,87.74,87.75,87.76,87.77,87.79,87.8,87.81,87.82,87.83,87.85,87.86,87.87,87.88,87.89,87.91,87.92,87.93,87.94,87.95,87.97,87.98,87.99,88.0,88.01,88.03,88.04,88.05,88.06,88.07,88.09,88.1,88.11,88.12,88.13,88.15,88.16,88.17,88.18,88.19,88.21,88.22,88.23,88.24,88.25,88.27,88.28,88.29,88.3,88.31,88.34,88.34,88.35,88.4,88.4,88.41,88.42,88.43,88.46,88.46,88.47,88.48,88.49,88.52,88.53,88.53,88.54,88.55,88.7,88.71,88.72,88.72,88.73,88.76,88.77,88.78,88.78,88.79,88.82,88.83,88.84,88.85,88.85,88.88,88.89,88.9,88.91,88.91,88.94,88.95,88.96,88.97,88.97,89.0,89.01,89.02,89.03,89.04,89.06,89.07,89.08,89.09,89.1,89.12,89.13,89.14,89.15,89.16,89.18,89.19,89.2,89.21,89.22,89.24,89.25,89.26,89.27,89.28,89.3,89.31,89.32,89.33,89.34,89.36,89.37,89.38,89.39,89.42,89.43,89.44,89.45,89.46,89.48,89.49,89.5,89.51,89.52,89.54,89.55,89.56,89.57,89.58,89.61] y=[2.29,2.41,2.4,2.38,2.43,2.42,2.38,2.36,2.4,2.37,2.36,2.37,2.34,2.32,2.31,2.25,2.25,2.21,2.2,2.21,2.21,2.21,2.21,2.19,2.17,2.1,2.08,2.08,2.12,2.15,2.1,2.09,2.1,2.08,2.08,2.01,2.0,1.98,1.98,1.95,1.92,1.92,1.92,1.92,1.92,1.88,1.88,1.91,1.91,1.88,1.89,1.87,1.85,1.84,1.83,1.88,1.93,1.88,1.82,1.82,2.08,2.13,2.35,2.32,2.37,2.34,2.25,2.35,2.33,2.34,2.32,2.34,2.39,2.53,2.49,2.53,2.54,2.55,2.53,2.52,2.52,2.54,2.66,2.71,2.81,2.92,3.09,2.99,3.03,2.98,3.01,2.98,2.93,2.91,2.93,2.91,2.89,2.92,2.9,2.87,2.9,2.9,2.93,2.83,2.78,2.67,2.6,2.66,2.61,2.61,2.61,2.54,2.56,2.51,2.52,2.55,2.6,2.6,2.67,2.63,2.62,2.63,2.61,2.58,2.59,2.59,2.62,2.59,2.58,2.61,2.63,2.6,2.63,2.63,2.61,2.6,2.58,2.58,2.57,2.58,2.58,2.58,2.58,2.57,2.58,2.58,2.58,2.58,2.55,2.52,2.53,2.53,2.51,2.46,2.48,2.45,2.54,2.53,2.49,2.51,2.49,2.48,2.49,2.47,2.48,2.49,2.48,2.5,2.5,2.55,2.53,2.52,2.51,2.49,2.5,2.49,2.49,2.47,2.46,2.48,2.45,2.45,2.43,2.43,2.45,2.45,2.45,2.45,2.45,2.45,2.45,2.45,2.46,2.45,2.44,2.44,2.45,2.45,2.47,2.56,2.52,2.48,2.47,2.5,2.54,2.54,2.58,2.61,2.63,2.63,2.63,2.61,2.59,2.59,2.56,2.57,2.58,2.56,2.57,2.61,2.59,2.6,2.6,2.58,2.6,2.59,2.6,2.61,2.61,2.59,2.6,2.62,2.62,2.6,2.61,2.59,2.59,2.59,2.59,2.61,2.67,2.65,2.63,2.63,2.6,2.56,2.59,2.59,2.59,2.58,2.58,2.57,2.58,2.55,2.55,2.58,2.58,2.57,2.58,2.83,2.88,2.93,2.79,2.82,2.81,2.86,2.86,2.85,2.82,2.82,2.82,2.78,2.78,2.82,2.79,2.8,2.79,2.79,2.78,2.72,2.73,2.71,2.72,2.73,2.73,2.74,2.74,2.72,2.73,2.73,2.71,2.68,2.71,2.75,2.84,2.91,2.89,2.92,2.97,2.96,2.94,2.99,3.04,2.97,2.99,2.97,2.99,2.98,2.99,3.0,3.01,2.99,2.98,2.99,2.99,2.99,3.01,2.96,2.97,3.0,2.98,2.97,2.96,2.96,3.0,3.0,2.99,2.98,2.99,2.99,2.99,2.99,2.99,2.99,2.98,2.98,2.98,2.98,3.02,3.03,3.03,3.05,3.09,3.08,3.1,3.12,3.14,3.13,3.12,3.14,3.15,3.13,3.15,3.14,3.14,3.14,3.14,3.13,3.11,3.08,3.08,3.08,3.08,3.1,3.11,3.11,3.11,3.09,3.13,3.17,3.28,3.43,3.52,3.47,3.45,3.45,3.45,3.44,3.46,3.46,3.45,3.44,3.45,3.45,3.45,3.45,3.45,3.47,3.5,3.54,3.52,3.5,3.5,3.5,3.44,3.45,3.45,3.45,3.43,3.45,3.48,3.48,3.45,3.46,3.43,3.46,3.45,3.43,3.43,3.42,3.42,3.43,3.42,3.41,3.39,3.38,3.38,3.38,3.4,3.39,3.38,3.39,3.37,3.37,3.38,3.38,3.38,3.38,3.38,3.38,3.37,3.36,3.37,3.36,3.36,3.37,3.36,3.41,3.41,3.4,3.39,3.39,3.37,3.37,3.36,3.36,3.36,3.36,3.36,3.37,3.36,3.37,3.39,3.45,3.42,3.39,3.4,3.4,3.39,3.38,3.38,3.38,3.38,3.38,3.38,3.38,3.38,3.38,3.42,3.42,3.41,3.39,3.39,3.39,3.37,3.38,3.4,3.41,3.44,3.43,3.43,3.43,3.43,3.42,3.42,3.42,3.47,3.46,3.47,3.53,3.65,3.59,3.76,3.85,3.77,3.9,3.76,3.75,3.8,3.73,3.7,3.66,3.68,3.66,3.69,3.68,3.69,3.69,3.61,3.61,3.61,3.59,3.59,3.59,3.63,3.61,3.62,3.63,3.62,3.61,3.61,3.62,3.69,3.66,3.69,3.68,3.66,3.65,3.66,3.68,3.78,3.76,3.77,3.74,3.75,3.77,3.75,3.7,3.7,3.73,3.74,3.79,3.83,3.87,3.86,3.8,3.81,3.78,3.8,3.78,3.78,3.84,3.81,3.81,3.82,3.78,3.75,3.76,3.74,3.72,3.71,3.72,3.78,3.78,3.77,3.76,3.74,3.74,3.75,3.75,3.73,3.72,3.71,3.68,3.7,3.67,3.64,3.56,3.57,3.56,3.61,3.62,3.59,3.57,3.59,3.55,3.54,3.53,3.52,3.53,3.53,3.58,3.6,3.57,3.53,3.53,3.54,3.55,3.57,3.57,3.58,3.64,3.63,3.6,3.6,3.6,3.59,3.6,3.6,3.61,3.61,3.62,3.64,3.64,3.64,3.69,3.73,3.71,3.69,3.69,3.69,3.65,3.66,3.66,3.72,3.73,3.7,3.7,3.72,3.74,3.74,3.74,3.79,3.85,3.9,3.88,3.93,3.86,3.94,4.0,4.0,3.97,3.94,3.93,3.91,3.92,3.94,3.94,3.94,3.99,3.98,4.01,3.99,3.92,3.82,3.71,3.81,3.77,3.76,3.81,3.79,3.83,3.83,3.88,3.89,3.84,3.84,3.83,3.79,3.81,3.8,3.81,3.82,3.83,3.8,3.81,3.81,3.83,3.83,3.86,3.92,3.93,3.97,3.97,3.96,3.95,3.94,3.96,3.98,3.88,3.98,4.0,4.02,4.04,4.08,4.09,4.09,4.16,4.22,4.21,4.19,4.19,4.18,4.19,4.2,4.19,4.2,4.21,4.27,4.3,4.29,4.26,4.29,4.29,4.34,4.36,4.35,4.33,4.33,4.36,4.34,4.33,4.34,4.37,4.35,4.36,4.39,4.38,4.41,4.4,4.4,4.39,4.39,4.41,4.42,4.46,4.48,4.53,4.63,4.65,4.71,4.81,4.91,5.0,4.95,5.04,5.01,4.98,4.9,4.95,4.91,4.8,4.9,4.86,4.76,4.77,4.77,4.79,4.8,4.79,4.81,4.89,4.87,4.87,4.87,4.8,4.79,4.75,4.69,4.69,4.71,4.78,4.76,4.74,4.73,4.8,4.81,4.84,4.83,4.83,4.83,4.79,4.75,4.75,4.66,4.69,4.7,4.68,4.7,4.73,4.72,4.75,4.75,4.75,4.71,4.72,4.71,4.69,4.68,4.64,4.65,4.65,4.66,4.66,4.64,4.65,4.64,4.62,4.63,4.6,4.52,4.45,4.53,4.49,4.5,4.48,4.37,4.39,4.4,4.41,4.43,4.47,4.46,4.45,4.42,4.44,4.45,4.45,4.44,4.43,4.41,4.41,4.44,4.41,4.38,4.38,4.37,4.37,4.38,4.32,4.24,4.29,4.31,4.29,4.27,4.28,4.28,4.28,4.32,4.32,4.33,4.33,4.32,4.33,4.39,4.47,4.47,4.53,4.53,4.53,4.52,4.54,4.51,4.53,4.53,4.53,4.54,4.54,4.58,4.56,4.58,4.56,4.55,4.53,4.54,4.54,4.55,4.54,4.53,4.52,4.49,4.45,4.45,4.46,4.46,4.48,4.46,4.47,4.47,4.49,4.47,4.47,4.48,4.51,4.57,4.57,4.59,4.61,4.57,4.57,4.6,4.64,4.64,4.63,4.65,4.65,4.64,4.64,4.66,4.72,4.73,4.76,4.74,4.8,4.78,4.72,4.76,4.86,4.86,4.88,4.86,4.83,4.85,4.85,4.84,4.81,4.82,4.82,4.82,4.81,4.82,4.85,4.85,4.84,4.82,4.81,4.78,4.81,4.79,4.75,4.78,4.8,4.79,4.78,4.76,4.77,4.77,4.77,4.78,4.79,4.79,4.76,4.75,4.74,4.73,4.74,4.75,4.8,4.81,4.84,4.82,4.8,4.81,4.8,4.77,4.81,4.8,4.81,4.84,4.86,4.83,4.82,4.81,4.8,4.78,4.81,4.81,4.82,4.88,4.84,4.84,4.83,4.83,4.85,4.85,4.83,4.81,4.82,4.79,4.8,4.79,4.78,4.8,4.79,4.78,4.77,4.78,4.77,4.76,] from alphashape import alphashape from shapely.geometry import mapping from bokeh.plotting import figure from ipywidgets import interact from bokeh.io import output_notebook, show, push_notebook def alphashape_func(x, y, alpha): length = range(len(x)) # date count pnt = [[x[i],y[i]] for i in length] # return a shapely.polygon/multipolygon alpha_shape = alphashape(pnt, alpha=alpha) # convert shapely.polygon/multipolygon to list map = mapping(alpha_shape)['coordinates'] poly_shp = [i[0] for i in map] bound_len = len(poly_shp) # single alpha shape case if bound_len == 1: bound_x = [i[0] for i in poly_shp] bound_y = [i[1] for i in poly_shp] # multiple alpha shape case else: bound_x = [[i[0] for i in poly_shp[j]] for j in range(bound_len)] bound_y = [[i[1] for i in poly_shp[j]] for j in range(bound_len)] # return a dict containing 2 lists: x & y. return {'x':bound_x, 'y':bound_y} alpha = 5 alpha_high_pnt = alphashape_func(x,y,alpha) plot = figure(sizing_mode='stretch_width', output_backend="webgl") # line_pnt(plot, max_processed_xy['x'], max_processed_xy['y'],legend_label ='processed_xy',line_color='yellow', line_width=2) alpha_shape_plt = plot.multi_line(xs=alpha_high_pnt['x'],ys=alpha_high_pnt['y'], line_color='cyan',legend_label = 'alpha_high_pnt') # create an update function def update(alpha=5): alpha_high_pnt = alphashape_func(x,y,alpha) alpha_shape_plt.data_source.data['xs'] = alpha_high_pnt['x'] alpha_shape_plt.data_source.data['ys'] = alpha_high_pnt['y'] # push new values to the notebook push_notebook() output_notebook() show(plot) interact(update, alpha=(0,25,1)) (the dynamic slider only works when you run it in jupyter in a web browser) When I drag the slider, it shows an error message: BokehUserWarning: ColumnDataSource's columns must be of the same length. Current lengths: ('xs', 54), ('ys', 99) I don't see the reason of this error, since when I manually adjust the alpha value, the lengths of xs and ys equal. Can anyone help? ===================== update ====================== Based on #bigreddot suggestion, I update the code to this, the doesn't match problem is resolved, but the plot doesn't refresh yet. from alphashape import alphashape from shapely.geometry import mapping from bokeh.plotting import figure from bokeh.io import output_notebook, show, push_notebook from bokeh.models import ColumnDataSource from ipywidgets import interact output_notebook() def alphashape_func(x, y, alpha): length = range(len(x)) # date count pnt = [[x[i],y[i]] for i in length] # return a shapely.polygon/multipolygon alpha_shape = alphashape(pnt, alpha=alpha) # convert shapely.polygon/multipolygon to list map = mapping(alpha_shape)['coordinates'] poly_shp = [i[0] for i in map] bound_len = len(poly_shp) # single alpha shape case if bound_len == 1: bound_x = [i[0] for i in poly_shp] bound_y = [i[1] for i in poly_shp] # multiple alpha shape case else: bound_x = [[i[0] for i in poly_shp[j]] for j in range(bound_len)] bound_y = [[i[1] for i in poly_shp[j]] for j in range(bound_len)] # return a dict containing 2 lists: x & y. return {'x':bound_x, 'y':bound_y} alpha = 5 plot = figure(sizing_mode='stretch_width', output_backend="webgl") source = ColumnDataSource(data=alphashape_func(x,y,alpha)) alpha_shape_plt = plot.multi_line(source=source, xs='x',ys='y', line_color='cyan',legend_label = 'alpha_high_pnt') print # create an update function def update(alpha=5): source.data = alphashape_func(x,y,alpha) # push new values to the notebook push_notebook() interact(update, alpha=(0,25,1)) show(plot)
In between this line: alpha_shape_plt.data_source.data['xs'] = alpha_high_pnt['x'] and this line: alpha_shape_plt.data_source.data['ys'] = alpha_high_pnt['y'] the CDS columns are not all the same length. If you need to update with data that has a new length you should collect all the updates up front in a new_data dict and then set source.data = new_data to update the CDS "all at once". This is more efficient in any case, as well, since it results in fewer property update change events being sent out.
Options next to graph / plot
This is how it looks now: current application This is what I want: what i want I am looking for ways to directly implement options next to my graph. When I select an option, the option should be instantly applied into the graph. For example: I want to change the points color to green. Or only show values that are lower than 5. I can't find a way to create such window next to my graph. The graph takes the whole screen, I believe it's a canvas. But I want the graph to dock to the right side and dock the graph options to the left side. Here is my code (just an example): import numpy as np from matplotlib.widgets import LassoSelector from matplotlib.path import Path class SelectFromCollection: """ Select indices from a matplotlib collection using `LassoSelector`. Selected indices are saved in the `ind` attribute. This tool fades out the points that are not part of the selection (i.e., reduces their alpha values). If your collection has alpha < 1, this tool will permanently alter the alpha values. Note that this tool selects collection objects based on their *origins* (i.e., `offsets`). Parameters ---------- ax : `~matplotlib.axes.Axes` Axes to interact with. collection : `matplotlib.collections.Collection` subclass Collection you want to select from. alpha_other : 0 <= float <= 1 To highlight a selection, this tool sets all selected points to an alpha value of 1 and non-selected points to *alpha_other*. """ def __init__(self, ax, collection, alpha_other=0.3): self.canvas = ax.figure.canvas self.canvas.show() self.collection = collection self.alpha_other = alpha_other self.xys = collection.get_offsets() self.Npts = len(self.xys) # Ensure that we have separate colors for each object self.fc = collection.get_facecolors() if len(self.fc) == 0: raise ValueError('Collection must have a facecolor') elif len(self.fc) == 1: self.fc = np.tile(self.fc, (self.Npts, 1)) self.lasso = LassoSelector(ax, onselect=self.onselect) self.ind = [] def onselect(self, verts): path = Path(verts) self.ind = np.nonzero(path.contains_points(self.xys))[0] self.fc[:, -1] = self.alpha_other self.fc[self.ind, -1] = 1 self.collection.set_facecolors(self.fc) self.canvas.draw_idle() def disconnect(self): #self.lasso.disconnect_events() self.fc[:, -1] = 1 self.collection.set_facecolors(self.fc) self.canvas.draw_idle() if __name__ == '__main__': import matplotlib.pyplot as plt # Fixing random state for reproducibility np.random.seed(19680801) data = np.random.rand(100, 2) subplot_kw = dict(xlim=(0, 1), ylim=(0, 1), autoscale_on=False) fig, ax = plt.subplots(subplot_kw=subplot_kw) pts = ax.scatter(data[:, 0], data[:, 1], s=80) selector = SelectFromCollection(ax, pts) def onPress(event): # print("Selected points:") # print(selector.xys[selector.ind]) selector.disconnect() ax.set_title("") fig.canvas.draw() def onRelease(event): print("Selected points:") print(selector.xys[selector.ind]) fig.canvas.mpl_connect("button_press_event", onPress) fig.canvas.mpl_connect("button_release_event", onRelease) ax.set_title("Press enter to accept selected points.") ax_color = plt.axes([0, 0.10, 0.20, 0.20]) plt.show() Does anyone know a solution for this? I would greatly appreciate it.
creating functions in for loop to control ToggleButton, problem with late binding (ipywidgets JupyterLab)
I'm trying to make ToggleButtons for my plot and stumble upon a problem. I created the buttons, no problem: # create buttons button = [] for i in range(len(expnum)): button.append(wg.ToggleButton(value=False, description=expnum[i], tooltip='Click to show/hide', layout=wg.Layout(width='60px', height='30px'))) button.append(wg.Output()) The problem is this part: # control buttons for i in range(len(expnum)): def on_value_change(change): with button[i * 2 + 1]: plots[i][0].set_visible(change['new']) button[i * 2].observe(on_value_change, names='value') The problem with the code is (I guess) the late binding problem. It recognizes only the last value (meaning: only in the state of i == len(expnum)-1) which is not what I expected. I actually succeeded in making it works like what I expected with the following codes below: # control buttons def on_value_change(change): with button[1]: plots[0][0].set_visible(change['new']) button[0].observe(on_value_change, names='value') def on_value_change(change): with button[3]: plots[1][0].set_visible(change['new']) button[2].observe(on_value_change, names='value') def on_value_change(change): with button[5]: plots[2][0].set_visible(change['new']) button[4].observe(on_value_change, names='value') and so on. Currently the number of iteration is still manageable to have it manually written like that, but with increasing amount of data, it is impossible to not using for loop. I am kind of new to python and I'm pretty sure there must be some kind of simple hack or workaround to make this thing works. I have found some thread that explained about forcing early binding with def f(i=i): instead of just def f():. But I have no idea how to implement those to my case. Does anyone have any idea how to solve my problem with for loop? Otherwise a complete new approach is also welcomed. --- edit --- This is the full code: import pandas as pd import numpy as np import ipywidgets as wg from ipywidgets import HBox, VBox import matplotlib.pyplot as plt import matplotlib from IPython.display import display %matplotlib widget expnum = ['data1', 'data2', 'data3'] t_all = [ [1, 2, 3], [1, 3, 4], [1, 2, 5] ] V_all = [ [100, 200, 100], [100, 120, 130], [150, 105, 100] ] # create buttons button = [] for i in range(len(expnum)): button.append(wg.ToggleButton(value=False, description=expnum[i], tooltip='Click to show/hide', layout=wg.Layout(width='60px', height='30px'))) button.append(wg.Output()) display(HBox(( [button[i] for i in range(len(button))] )) ) # create figure fig, ax = plt.subplots() ax.set_xlabel('t [s]') ax.set_ylabel('V [V]') plots = [] for i in range(len(t_all)): plots.append(ax.plot(t_all[i], V_all[i], visible=False, alpha=0.7)) # ---------------- The problem starts here -------------------------- # set visibility of plots for i in range(len(expnum)): def on_value_change(change): with button[i * 2 + 1]: plots[i][0].set_visible(change['new']) button[i * 2].observe(on_value_change, names='value') Why does above code (starting from # set visibility of plots) doesn't work, while below code works: def on_value_change(change): with button[1]: plots[0][0].set_visible(change['new']) button[0].observe(on_value_change, names='value') def on_value_change(change): with button[3]: plots[1][0].set_visible(change['new']) button[2].observe(on_value_change, names='value') def on_value_change(change): with button[5]: plots[2][0].set_visible(change['new']) button[4].observe(on_value_change, names='value') I see no difference in the code below and the code above other than using for loop instead of manually retype the same code over and over.
Restricting panning range in matplotlib plots
Is there any way to restrict the range that a user can interactively pan a plot in matplotlib? For example, I'd like to limit the user's panning range to the positive quadrant of the plot, so x > 0 and y > 0, effectively creating floors at x = 0 and y = 0.
There is not built-in way to restrict zooming or panning other than restricting it to either the x or y direction. So you need to implement that yourself. Connecting to the 'xlim_changed' and 'ylim_changed' events, you may check if the limits are valid or not, and potentially reset them to the valid range. import matplotlib.pyplot as plt import numpy as np fig,ax=plt.subplots() x = np.sin(np.linspace(0,10, 266))+1 ax.plot(x) class Restrictor(): def __init__(self, ax, x=lambda x: True,y=lambda x: True): self.res = [x,y] self.ax =ax self.limits = self.get_lim() self.ax.callbacks.connect('xlim_changed', lambda evt: self.lims_change(axis=0)) self.ax.callbacks.connect('ylim_changed', lambda evt: self.lims_change(axis=1)) def get_lim(self): return [self.ax.get_xlim(), self.ax.get_ylim()] def set_lim(self, axis, lim): if axis==0: self.ax.set_xlim(lim) else: self.ax.set_ylim(lim) self.limits[axis] = self.get_lim()[axis] def lims_change(self, event=None, axis=0): curlim = np.array(self.get_lim()[axis]) if self.limits[axis] != self.get_lim()[axis]: # avoid recursion if not np.all(self.res[axis](curlim)): # if limits are invalid, reset them to previous state self.set_lim(axis, self.limits[axis]) else: # if limits are valid, update previous stored limits self.limits[axis] = self.get_lim()[axis] res = Restrictor(ax, x=lambda x: x>=0,y=lambda x: x>=0) plt.show() The user experience of such limitations are not great, since a certain action (like moving the mouse) is not answered with the expected behaviour (plot does not move); but one has to judge for oneself if this would still make sense.
How to set interact arguments programmatically?
Suppose I have function, that accepts list of arguments. List can be of variable length and function is ok with it. For example: import math import numpy as np import matplotlib.pyplot as plt from ipywidgets import interact, interactive, fixed, interact_manual import ipywidgets as widgets %matplotlib inline def PlotSuperposition(weights): def f(x): y = 0 for i, weight in enumerate(weights): if i==0: y+=weight else: y += weight*math.sin(x*i) return y vf = np.vectorize(f) xx = np.arange(0,6,0.1) plt.plot(xx, vf(xx)) plt.gca().set_ylim(-5,5) PlotSuperposition([1,1,2]) shows I can hardcode interact for given number of arguments, like here interact(lambda w0, w1, w2: PlotSuperposition([w0,w1,w2]), w0=(-3,+3,0.1), w1=(-3,+3,0.1), w2=(-3,+3,0.1)) which shows But how can I make number of sliders defined programmatically? I tried n_weights=10 weight_sliders = [widgets.FloatSlider( value=0, min=-10.0, max=10.0, step=0.1, description='w%d' % i, disabled=False, continuous_update=False, orientation='horizontal', readout=True, readout_format='.1f', ) for i in range(n_weights)] interact(PlotSuperposition, weights=weight_sliders) but got error TypeError: 'FloatSlider' object is not iterable inside PlotSuperposition saying that interact doesn't pass a list of values to the function. How to accomplish?
First, modify your function to take an arbitrary number of keyword arguments instead of a plain list: def PlotSuperposition(**kwargs): def f(x): y = 0 for i, weight in enumerate(kwargs.values()): if i==0: y+=weight else: y += weight*math.sin(x*i) return y vf = np.vectorize(f) xx = np.arange(0,6,0.1) plt.plot(xx, vf(xx)) plt.gca().set_ylim(-5,5) Notice the asterisks in front of kwargs. Then, call interact with a dictionary of key/value arguments: kwargs = {'w{}'.format(i):slider for i, slider in enumerate(weight_sliders)} interact(PlotSuperposition, **kwargs)