Python: Resetting A Matplotlib From An Ipywidget Button - python-2.7

When using iPyWidgets and Matplotlib in a Jupyter notebook, it is fairly easy to get a live-updating figure, even with multiple subplots, and multiple variables with multiple sliders. Simply set an interact to contain the activated plot function, and constructors for two slider variables:
%pylab inline
from ipywidgets import *
from IPython.display import display
import numpy as np
import matplotlib
t = np.arange(0.0, 4*pi, 0.01)
def pltsin(f1, f2):
ax11 = plt.subplot(121)
ax11.set_title('Plot 1')
ax11.plot(t, sin(2*pi*t*f1/4/pi), 'k'); ax11.grid(True)
ax11.plot(t, cos(2*pi*t*f1/4/pi), 'r'); ax11.grid(True)
ax12 = plt.subplot(122)
ax12.set_title('Plot 2')
ax12.plot(t, sin(2*pi*t*f2/4/pi), 'k'); ax12.grid(True)
ax12.plot(t, cos(2*pi*t*f2/4/pi), 'r'); ax11.grid(True)
plt.show()
interact(pltsin, f1 = (1, 2, 0.01), f2 = (1, 2, 0.01))
This could easily be extended to a plot where (say) three sliders control three polynomial coefficients all in a single window (i.e., no subplots).
But, it would be highly useful to have a reset button, which returns all variables to their default condition. How can I cause an ipywidget button's on_click method to affect the variables of the slider, and the figure itself?

This can be done by leveraging the interactive function.
%pylab inline
from ipywidgets import widgets
from IPython.display import display
import numpy as np
import matplotlib
t = np.arange(0.0, 4*pi, 0.01)
def pltsin(f1, f2):
ax11 = plt.subplot(121)
ax11.set_title('Plot 1')
ax11.plot(t, sin(2*pi*t*f1/4/pi), 'k'); ax11.grid(True)
ax11.plot(t, cos(2*pi*t*f1/4/pi), 'r'); ax11.grid(True)
ax12 = plt.subplot(122)
ax12.set_title('Plot 2')
ax12.plot(t, sin(2*pi*t*f2/4/pi), 'k'); ax12.grid(True)
ax12.plot(t, cos(2*pi*t*f2/4/pi), 'r'); ax11.grid(True)
plt.show()
def reset_values(b):
"""Reset the interactive plots to inital values."""
my_plts.children[0].value = 1
my_plts.children[1].value = 1
reset_button = widgets.Button(description = "Reset")
reset_button.on_click(reset_values)
my_plts = widgets.interactive(pltsin, f1 = (1, 2, 0.01), f2 = (1, 2, 0.01))
display(my_plts, reset_button)
Can't stand hard-coded variables? Then replace the reset_values function with this more elastic version:
def reset_values(b):
"""Reset the interactive plots to inital values."""
my_plts.children[0].value = my_plts.children[0].min
my_plts.children[1].value = my_plts.children[1].min
Hope that helps.

Related

how can i change the my color bar is work like a slider in matplotlib

Here is my code,here i don't want to use slider to change the intervals of
my plot.Instead of slider i want to use colorbar only,can any one please tell me is there any way to change colorbar i.e it exactly work like a slider.THank you in advance
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button
import matplotlib.colors
ax = plt.subplot(111)
plt.subplots_adjust(left=0.25, bottom=0.25)
img_data = np.random.rand(50,50)
c_max = 2
img = ax.imshow(img_data, interpolation='nearest')
cb = plt.colorbar(img)
axcolor = 'lightgoldenrodyellow'
ax_cmax = plt.axes([0.25, 0.15, 0.65, 0.03])
s_cmax = Slider(ax_cmax, 'max', 0, 50, valfmt=c_max)
def update(val, s=None):
# _cmin = s_cmin.val
_cmax = s_cmax.val
img.set_clim(_cmax)
plt.draw()
s_cmax.on_changed(update)
plt.show()

Animating Steronets

I have been looking around and have got to nowhere with this. I am trying to animate the poles on a stereonet diagram. However, the poles do not appear at the location that they should be in.
Figure 1 is the animated pole plot while Figure 2 is how the plot should be. I was wondering if anyone had an idea on how to proceed with this?
import matplotlib as mpl
mpl.use("TkAgg")
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np
import mplstereonet
fig, ax = mplstereonet.subplots()
fig2, ax1 = mplstereonet.subplots()
ax.grid(True)
ax1.grid(True)
# Assume a strike and dip with a random variance.
# Current values should plot the poles at either 0, 180
strike, dip = 90, 80
num = 10
strikes = strike + 10 * np.random.randn(num)
dips = dip + 10 * np.random.randn(num)
poles, = ax.pole([], [], 'o')
def init():
poles.set_data([], [])
return poles,
def animate(i):
poles.set_data(strikes[:i], dips[:i])
return poles,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames = len(strikes), interval = 100, blit=True, repeat=False)
poles1 = ax1.pole(strikes, dips, 'o') # This is how the final image should look like
plt.show()

add multiple colorbars to a subplot of polar contourf [duplicate]

I would like to add a separate colorbar to each subplot in a 2x2 plot.
fig , ( (ax1,ax2) , (ax3,ax4)) = plt.subplots(2, 2,sharex = True,sharey=True)
z1_plot = ax1.scatter(x,y,c = z1,vmin=0.0,vmax=0.4)
plt.colorbar(z1_plot,cax=ax1)
z2_plot = ax2.scatter(x,y,c = z2,vmin=0.0,vmax=40)
plt.colorbar(z1_plot,cax=ax2)
z3_plot = ax3.scatter(x,y,c = z3,vmin=0.0,vmax=894)
plt.colorbar(z1_plot,cax=ax3)
z4_plot = ax4.scatter(x,y,c = z4,vmin=0.0,vmax=234324)
plt.colorbar(z1_plot,cax=ax4)
plt.show()
I thought that this is how you do it, but the resulting plot is really messed up; it just has an all grey background and ignores the set_xlim , set_ylim commands I have (not shown here for simplicity). + it shows no color bars. Is this the right way to do it?
I also tried getting rid of the "cax = ...", but then the colorbar all goes on the bottom right plot and not to each separate plot!
This can be easily solved with the the utility make_axes_locatable. I provide a minimal example that shows how this works and should be readily adaptable:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
m1 = np.random.rand(3, 3)
m2 = np.arange(0, 3*3, 1).reshape((3, 3))
fig = plt.figure(figsize=(16, 12))
ax1 = fig.add_subplot(121)
im1 = ax1.imshow(m1, interpolation='None')
divider = make_axes_locatable(ax1)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(im1, cax=cax, orientation='vertical')
ax2 = fig.add_subplot(122)
im2 = ax2.imshow(m2, interpolation='None')
divider = make_axes_locatable(ax2)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(im2, cax=cax, orientation='vertical');
In plt.colorbar(z1_plot,cax=ax1), use ax= instead of cax=, i.e. plt.colorbar(z1_plot,ax=ax1)
Specify the ax argument to matplotlib.pyplot.colorbar(), e.g.
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2)
for i in range(2):
for j in range(2):
data = np.array([[i, j], [i+0.5, j+0.5]])
im = ax[i, j].imshow(data)
plt.colorbar(im, ax=ax[i, j])
plt.show()
Please have a look at this matplotlib example page. There it is shown how to get the following plot with four individual colorbars for each subplot:
I hope this helps.
You can further have a look here, where you can find a lot of what you can do with matplotlib.
Try to use the func below to add colorbar:
def add_colorbar(mappable):
from mpl_toolkits.axes_grid1 import make_axes_locatable
import matplotlib.pyplot as plt
last_axes = plt.gca()
ax = mappable.axes
fig = ax.figure
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
cbar = fig.colorbar(mappable, cax=cax)
plt.sca(last_axes)
return cbar
Then you codes need to be modified as:
fig , ( (ax1,ax2) , (ax3,ax4)) = plt.subplots(2, 2,sharex = True,sharey=True)
z1_plot = ax1.scatter(x,y,c = z1,vmin=0.0,vmax=0.4)
add_colorbar(z1_plot)

cannot get response from Bokeh RadioButtonGroup

I am trying to understand how to use interactivity in RadioButtonGroup using Bokeh and CustomJS with a Python function. I have tweaked the example provided at the Bokeh site for plotting y=x^f. Instead of using a slider for the power f, I would like to toggle between two powers, f=0.5 and f=0.2. I have followed the manual and inserted RadioButtonGroup in my code using Jupyter notebook. The buttons are showing and responsive, but I am unable to get any callback response out of toggling the buttons.
Any help will be appreciated.
from math import pi
from bokeh.io import output_file, show
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, CustomJS, Slider, TextInput, RadioButtonGroup
from bokeh.plotting import Figure, output_notebook
output_notebook()
x = [x*0.005 for x in range(0, 200)]
y = x
source = ColumnDataSource(data=dict(x=x, y=y))
plot = Figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)
def callback(source=source, input1=input1, window=None):
data = source.data
m= input1.active
if m==0:
f=.5
else:
f=2
x, y = data['x'], data['y']
for i in range(len(x)):
y[i] = window.Math.pow(x[i], f)
source.trigger('change')
input1 = RadioButtonGroup(labels=["power = .5", "power = 2."], active=0)
input1.button_type="success"
input1.js_on_change('active', CustomJS.from_py_func(callback))
layout = column(input1, plot)
show(layout)
I can not make bokeh.models.RadioButtonGroup generate a callback, but with bokeh.models.RadioGroup I can (I'm using bokeh version 0.12.4 Maybe a newer version facilitates RadioButtonGroup to generate a callback). Also, you are referencing input1 before declaring it. It's not needed as input of your callback function, inside you can use cb_obj. See:
import bokeh
import bokeh.plotting
bokeh.io.output_notebook()
x = [x*0.005 for x in range(0, 200)]
y = x
source = bokeh.models.ColumnDataSource(data=dict(x=x, y=y))
plot = bokeh.plotting.figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)
def callback(source=source, window=None):
data = source.data
m = cb_obj.active
if m==0:
f=.5
else:
f=2
x, y = data['x'], data['y']
for i in range(len(x)):
y[i] = window.Math.pow(x[i], f)
source.trigger('change')
input1 = bokeh.models.RadioGroup(labels=["power = .5", "power = 2."],active=0,
callback=bokeh.models.CustomJS.from_py_func(callback))
layout = bokeh.layouts.column(input1, plot)
bokeh.io.show(layout)

matplotlib subplot2grid doesn't display correctly

I'm using subplot2grid to display graphs. However, not all subplots are being displayed. Obviously it has to do with the if statement.
However, in my complete code I need those if statements because depending on some conditions plots have diffent formats. I want all 3 subplots to be displayed (one for each i). However, the first one is missing. How to display it correctly?
Here is the simplified code:
import matplotlib.pyplot as plt
fig=plt.figure()
for i in xrange(0,3):
if i==1:
ax=plt.subplot2grid((3,1),(i,0))
ax.plot([1,2],[1,2])
fig.autofmt_xdate()
else:
ax=plt.subplot2grid((3,1),(i,0), rowspan=2)
ax.plot([1,2],[1,2])
fig.autofmt_xdate()
plt.show()
I would just use the gridspec module from matplotlib. Then you can set the width/height ratios directly.
Then you can do something like this:
import numpy
from matplotlib import gridspec
import matplotlib.pyplot as plt
def do_plot_1(ax):
ax.plot([0.25, 0.5, 0.75], [0.25, 0.5, 0.75], 'k-')
def do_plot_2(ax):
ax.plot([0.25, 0.5, 0.75], [0.25, 0.5, 0.75], 'g--')
fig = plt.figure(figsize=(6, 4))
gs = gridspec.GridSpec(nrows=3, ncols=1, height_ratios=[2, 1, 2])
for n in range(3):
ax = fig.add_subplot(gs[n])
if n == 1:
do_plot_1(ax)
else:
do_plot_2(ax)
fig.tight_layout()
To use plt.subplot2grid, you'd need to effectively do something like this:
fig = plt.figure(figsize=(6, 4))
ax1 = plt.subplot2grid((5,1), (0, 0), rowspan=2)
ax2 = plt.subplot2grid((5,1), (2, 0), rowspan=1)
ax3 = plt.subplot2grid((5,1), (3, 0), rowspan=2)
Since you have two axes with a rowspan=2, your grid needs to be 2+1+2 = 5 blocks tall.