Found this code here.
%matplotlib inline
from ipywidgets import interactive
import matplotlib.pyplot as plt
import numpy as np
def f(m, b):
plt.figure(2)
x = np.linspace(-10, 10, num=1000)
plt.plot(x, m * x + b)
plt.ylim(-5, 5)
plt.show()
interactive_plot = interactive(f, m=(-2.0, 2.0), b=(-3, 3, 0.5))
output = interactive_plot.children[-1]
output.layout.height = '350px'
interactive_plot
It creates a plot that can be interacted with and doesn't flicker. I looked in the documentation but I don't know how to add a box to control this plot? For instance how would I use this hbox to update the plot?
items = [widgets.FloatSlider(value=5, min=0, max=10, step=0.01,
orientation='vertical', layout=Layout(width="15px"), readout_format='.0f')
for i in range(5)]
hbox = widgets.HBox(items)
hbox
If you know the answer please elaborate and explain why it is done like that.
I tried to call the function f from observe and it simply created new unrelated plots.
When the same function is called from interactive it works amazingly well.
Here's a rough idea of what is happening with an interactive, perhaps you can adapt it to your situation?
%matplotlib inline
import ipywidgets as ipwy
import matplotlib.pyplot as plt
import numpy as np
from IPython.display import clear_output
m_widg = ipwy.FloatSlider(min=-2, max=2, step=0.5)
b_widg = ipwy.FloatSlider(min=-3, max=3, step=0.5)
out = ipwy.Output(layout = ipwy.Layout(height='350px'))
display(ipwy.VBox(children=(m_widg, b_widg, out)))
def f(*args):
out.clear_output()
m = m_widg.value
b = b_widg.value
plt.figure(2)
x = np.linspace(-10, 10, num=1000)
plt.plot(x, m * x + b)
plt.ylim(-5, 5)
with out:
clear_output()
plt.show()
m_widg.observe(f, names=['value'])
b_widg.observe(f, names=['value'])
Related
is there a way to get TwoSlopeNorm in combination with base 2 ticks on the colorbar?
An example is something like this where you have normal linear scaling:
import matplotlib.pyplot as plt
import matplotlib.colors
import numpy as np
x = np.arange(-50,100,1)
y = x.copy()
c = x.copy()
scatter_plot = plt.scatter(x, y, c=c, cmap='bwr', norm=matplotlib.colors.TwoSlopeNorm(vmin=-50, vcenter=0, vmax=100))
cbar = plt.colorbar(scatter_plot)
plt.show()
I know based on a previous question of mine that SymLogNorm supports base2, but it looks like this is not the case for TwoSlopeNorm. Does anyone have a suggestion on how to do it?
With a horizontal log-scaled color bar and logged labels along the bottom, is it possible to show the exponentiated (original) values along the top?
So in this example, there should be ticks and labels along the top of the color bar going from mat.min() = 0.058 to mat.max() = 13.396
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
mat = np.exp(np.random.randn(20, 20))
plt.matshow(mat)
norm = mpl.colors.Normalize(1, np.log(mat.max()))
plt.colorbar(plt.cm.ScalarMappable(norm=norm), orientation="horizontal")
plt.savefig("rand_mat.png", dpi=200)
Here is the best answer for your response. I've customized it based on that. Does this result match the intent of your question? The color bar and the size of the figure are not the same, so I adjusted them.
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(20210404)
mat = np.exp(np.random.randn(20, 20))
norm = mpl.colors.Normalize(1, np.log(mat.max()))
fig, (ax, cax) = plt.subplots(nrows=2, gridspec_kw=dict(height_ratios=[15,1],hspace=0.5))
im = ax.matshow(mat)
cbar = plt.colorbar(plt.cm.ScalarMappable(norm=norm), orientation="horizontal", cax=cax)
cax2 = cax.twiny()
cbar.ax.xaxis.set_label_position("bottom")
iticks = np.arange(mat.min(), mat.max(), 2)
cax2.set_xticks(iticks)
ax_pos = ax.get_position()
cax_pos = cbar.ax.get_position()
new_size = [ax_pos.x0, cax_pos.y0, ax_pos.x1 - ax_pos.x0, cax_pos.y1 - cax_pos.y0]
cbar.ax.set_position(new_size)
plt.show()
At the risk of committing a faux pas, I'll answer my own question with the solution that best suits my needs:
cb.ax.secondary_xaxis("top", functions=(np.exp, np.log))
which gives
Full Code
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
mat = np.exp(np.random.randn(20, 20))
plt.matshow(mat)
norm = mpl.colors.Normalize(np.log(mat.min()), np.log(mat.max()))
cb = plt.colorbar(plt.cm.ScalarMappable(norm=norm), orientation="horizontal")
cb_ax_top = cb.ax.secondary_xaxis("top", functions=(np.exp, np.log))
cb_ax_top.set_xticks([0.1, 0.5, 1, 4, 10, 20])
With my code I get 2 equations in the legend that are the same. I don't how why it is so. I just want to correct this by making it only one equation. How can I do that? This equation is the line fit result of some of the data below.
Thanks in advance!
import matplotlib.pyplot as plt
import numpy as np
import plotly.plotly as py
import plotly.tools as tls
from sympy import S, symbols
import sympy
y = [2.7,2.3,1.9,1.5,1.3,1.0,0.8,0.6,0.5,0.4,0.2,0.1,0.0,0.0,-0.20,-0.2]
y = [i*10**(-16) for i in y]
x = [0,0.05,0.10,0.15,0.20,0.25,0.30,0.40,0.45,0.50,0.55,0.60,0.65,0.70,0.75,0.80]
e_y = [10**(-17)]* 16
e_x = [0.001] * 16
fig= plt.figure()
ax = fig.add_subplot(111)
ax.errorbar(x,y, yerr=e_y,xerr=0.001,fmt='-o')
ax.set_title('Current vs. Potential')
ax.set_xlabel('Retarding Potential')
ax.set_ylabel('Photocell Current')
x=x[:7]
y=y[:7]
e_y=e_y[:7]
e_x=e_x[:7]
#line fit:
fit=np.polyfit(x,y,1)
fit_fn = np.poly1d(fit)
a=symbols("x")
line = sum(S(format(v))*a**i for i, v in enumerate(fit[::-1]))
eq_latex = sympy.printing.latex(line)
plt.plot(x,y,x,fit_fn(x),label="${}$".format(eq_latex))
plt.legend(fontsize='small')
plt.show()
I solved this using the following:
#import matplotlib.patches as mpatches
plt.plot(x,y,x,fit_fn(x))
eqn = mpatches.Patch(color='green',label="${}$".format(eq_latex))
plt.legend(handles=[eqn])
instead of
plt.plot(x,y,x,fit_fn(x),label="${}$".format(eq_latex))
plt.legend(fontsize='small')
I am trying to generate an interactive plot that depends on widgets.
The problem I have is that when I change parameters using the slider, a new plot is done after the previous one, instead I would expect only one plot changing according to the parameters.
Example:
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
def plot_func(freq):
x = np.linspace(0, 2*np.pi)
y = np.sin(x * freq)
plt.plot(x, y)
interact(plot_func, freq = widgets.FloatSlider(value=7.5,
min=1,
max=5.0,
step=0.5))
After moving the slider to 4.0, I have:
while I just want one figure to change as I move the slider.
How can I achieve this?
(I am using Python 2.7, matplotlib 2.0 and I have just updated notebook and jupyter to the latest version. let me know if further info is needed.)
As you want to change the figure, instead of creating a new one, may I suggest the following way:
Use an interactive backend; %matplotlib notebook
Update the line in the plot, instead of drawing new ones.
So the code could look something like this:
%matplotlib notebook
from ipywidgets import *
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
line, = ax.plot(x, np.sin(x))
def update(w = 1.0):
line.set_ydata(np.sin(w * x))
fig.canvas.draw_idle()
interact(update);
Alternatively you may use plt.show() as in this answer.
This is an issue (?) introduced in the last version of jupyter and/or ipywidgets. One workaround I found was to add the line plt.show() at the end of plot_func.
For completion, here is an answer that makes use of more than one slider bar and sets the default parameters as well as the interval lengths.
%matplotlib notebook
from ipywidgets import *
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-10, 10,100)
def f(x, A, B, C):
return A*x**2 + B*x + C
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
line, = ax.plot(x, f(x, A=1, B=1, C=1))
def update(A = 1, B = 0, C = 0):
line.set_ydata(f(x,A,B,C))
fig.canvas.draw_idle()
interact(update, A = (-4,4,0.1), B = (-4,4,0.1), C = (-4,4,0.1));
I've tried multiple animation sample codes and cannot get any of them working. Here's a basic one I've tried from the Matplotlib documentation:
"""
A simple example of an animated plot
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
x = np.arange(0, 2*np.pi, 0.01) # x-array
line, = ax.plot(x, np.sin(x))
def animate(i):
line.set_ydata(np.sin(x+i/10.0)) # update the data
return line,
#Init only required for blitting to give a clean slate.
def init():
line.set_ydata(np.ma.array(x, mask=True))
return line,
ani = animation.FuncAnimation(fig, animate, np.arange(1, 200), init_func=init,
interval=25, blit=True)
plt.show()
When I execute the above in an IPython Notebook, I just see a blank plot generated. I've tried running this from multiple servers (including Wakari), on multiple machines, using multiple browsers (Chrome, FF, IE).
I can save the animation to an mp4 file just fine and it looks good when played.
Any help is appreciated!
To summarize the options you have:
Using display in a loop Use IPython.display.display(fig) to display a figure in the output. Using a loop you would want to clear the output before a new figure is shown. Note that this technique gives in general not so smooth resluts. I would hence advice to use any of the below.
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
from IPython.display import display, clear_output
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
for i in range(len(x)):
animate(i)
clear_output(wait=True)
display(fig)
plt.show()
%matplotlib notebook Use IPython magic %matplotlib notebook to set the backend to the notebook backend. This will keep the figure alive instead of displaying a static png file and can hence also show animations.
Complete example:
%matplotlib notebook
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
plt.show()
%matplotlib tk Use IPython magic %matplotlib tk to set the backend to the tk backend. This will open the figure in a new plotting window, which is interactive and can thus also show animations.
Complete example:
%matplotlib tk
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
plt.show()
Convert animation to mp4 video:
from IPython.display import HTML
HTML(ani.to_html5_video())
or use plt.rcParams["animation.html"] = "html5" at the beginning of the notebook.
This will require to have ffmpeg video codecs available to convert to HTML5 video. The video is then shown inline. This is therefore compatible with %matplotlib inline backend. Complete example:
%matplotlib inline
import matplotlib.pyplot as plt
plt.rcParams["animation.html"] = "html5"
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
ani
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
from IPython.display import HTML
HTML(ani.to_html5_video())
Convert animation to JavaScript:
from IPython.display import HTML
HTML(ani.to_jshtml())
or use plt.rcParams["animation.html"] = "jshtml" at the beginning of the notebook.
This will display the animation as HTML with JavaScript. This highly compatible with most new browsers and also with the %matplotlib inline backend. It is available in matplotlib 2.1 or higher.
Complete example:
%matplotlib inline
import matplotlib.pyplot as plt
plt.rcParams["animation.html"] = "jshtml"
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
ani
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
l, = ax.plot([0,2*np.pi],[-1,1])
animate = lambda i: l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
from IPython.display import HTML
HTML(ani.to_jshtml())
According to this answer, you can get animation (and full interactivity support) working in an IPython notebook enabling the nbagg backend with %matplotlib nbagg.
I was having the exact same problem as you until a moment ago. I am a complete novice, so tcaswell's answer was a bit cryptic to me. Perhaps you figured out what he meant or found your own solution. In case you have not, I will put this here.
I googled "matplotlib inline figures" and found this site, which mentions that you have to enable matplotlib mode. Unfortunately, just using %maplotlib didn't help at all.
Then I typed %matplotlib qt into the IPython console on a lark and it works just fine now, although the plot appears in a separate window.
I ran into this issue as well and found I needed to understand the concept of matplotlib backends, how to enable a specific backend, and which backends work with FuncAnimation. I put together an ipython notebook that explains the details and summarizes which backends work with FuncAnimation on Mac, Windows, and wakari.io. The notebook also summarizes which backends work with the ipython interact() widget, and where plots appear (inline or secondary window) for basic matplotlib plotting. Code and instructions are included so you can reproduce any of the results.
The bottom line is that you can't get an animation created with FuncAnimation to display inline in an ipython notebook. However, you can get it to display in a separate window. It turns out that I needed this to create visualizations for an undergraduate class I am teaching this semester, and while I would much prefer the animations to be inline, at least I was able to create some useful visualizations to show during class.
No inline video in Jupyter at the end of an animation also happens when
HTML(ani.to_html5_video())
is not at the very end of a notebook cell, as the output is then suppressed.
You may use it then as follows
out = HTML(ani.to_html5_video())
and just type out` in a new cell to get the video online.