Issue
I would like to use the interact function to create sliders where the user would input vector coordinates and plot these coordinates. The problem is that changing the input values doesn't make a new graph, would it be possible to make it work?
I'm working with jupyter notebook. My code
import panel as pn
import numpy as np
import matplotlib.pyplot as plt
from panel.interact import interact, interactive, fixed, interact_manual
pn.extension()
def f(u1,u2,v1,v2):
plt.clf()
vetores = np.array([[0,0,u1,u2], [u1,u2,v1,v2]])
X, Y, U, V = zip(*vetores)
plt.figure()
ax = plt.gca()
ax.quiver(X, Y, U, V, angles='xy', scale_units='xy', scale=1, color = ['r','g','b'])
ax.set_xlim([min(-1,u1-1, v1-1), max(u1+v1+1, v1+1)])
ax.set_ylim([min(-1,u2-1, v2-1), max(u2+v2+1, v2+1)])
plt.show()
interact(f, u1=2, u2=0, v1=2, v2=3)
Solution
You can use ipywidgets interactive plot. Matplotlib has quiver:
from ipywidgets import interactive
import matplotlib.pyplot as plt
import numpy as np
def f(u1,u2,v1,v2):
plt.figure()
vetores = np.array([[0,0,u1,u2], [u1,u2,v1,v2]])
X, Y, U, V = zip(*vetores)
plt.quiver(X, Y, U, V, angles='xy', scale_units='xy', scale=1, color = ['r','g','b'])
ax = plt.gca()
ax.set_xlim([min(-1,u1-1, v1-1), max(u1+v1+1, v1+1)])
ax.set_ylim([min(-1,u2-1, v2-1), max(u2+v2+1, v2+1)])
plt.show()
interactive_plot = interactive(f, u1=2, u2=0, v1=2, v2=3)
interactive_plot
Your code was adapted into my answer here.
It works in notebooks in Jupyter sessions launched from the link at the bottom there.
It also works in notebooks in Jupyter sessions launched via the holoviz panel MyBinder launch here.
Using Panel
Or using Panel in combination with Matplotlib based on upper part of here and returning a proper Matplotlib figure based on here:
import panel as pn
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
pn.extension()
title = '## Quiver Panel controller'
def f(u1,u2,v1,v2):
pl = plt.figure()
vetores = np.array([[0,0,u1,u2], [u1,u2,v1,v2]])
X, Y, U, V = zip(*vetores)
pl.add_subplot(111).quiver(X, Y, U, V, angles='xy', scale_units='xy', scale=1, color = ['r','g','b'])
ax = plt.gca()
ax.set_xlim([min(-1,u1-1, v1-1), max(u1+v1+1, v1+1)])
ax.set_ylim([min(-1,u2-1, v2-1), max(u2+v2+1, v2+1)])
plt.close(pl)
return pl
interact = pn.interact(f, u1=2, u2=0, v1=2, v2=3)
pn.Row(
pn.Column(title, interact[0], sizing_mode="fixed", width=300),
interact[1]
)
#interact # use this if don't want side-by-side
The layout is nicer in this example, but ipywidgets, which was used in the above option, can be used to arrange the controls side-by-side as well, see bottom of post here for an example.
I would imagine there's a way to make it simpler and instead use return plt.gcf()
based on this and associated note in FAQ:
"A: Matplotlib pyplot users often use
%matplotlib inline
, which shows plots as a "side effect" in a Jupyter notebook, rather than using the cell's return value like Python literals and other objects do. Panel callbacks like those accepted forpn.interact()
work on the return value of the callback, which is then provided as the return value of the cell, and thus directly display without any requirements for side effects. So, if you create a Matplotlib plot that would magically appear via%matplotlib inline
, for Panel you need to ensure that the callback actually returns a value, rather than counting on this side effect. Specifically, if you have a callback with some Matplotlib plotting calls, you can addreturn plt.gcf()
to your callback to make the current figure be returned, which will ensure that your plot is displayed properly."
However, I wasn't able to easily find the combination where it worked and I didn't see two plots. In fact, just trying the example code there results in two plots as well, only the upper one updating via the slider. The approach earlier in that thread produces no such artifact.
Answered By - Wayne
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.