E: Widget para MatPlotLib
en Jupyter-Lab
¶
Con MatPlotLib
hemos ido visualizando gráficas e imágenes. Sin embargo dicha biblioteca tal cual es un poco incómoda en Jupyter-Lab
ya que ajustar el tamaño y escalas de las imágenes es un proceso un tanto tedioso. Existe un widget que nos va a facilitar mucho la visualización de datos en nuestros notebooks. Podemos instalarlo como:
> conda install -c conda-forge ipympl
Para activarlo solo hay que usar el decorador %matplotlib widget
:
[1]:
%matplotlib widget
import matplotlib.pyplot as plt
import numpy as np
Cuando creemos una gráfica como venimos haciendo hasta ahora al mover el ratón por encima se nos descubrirá una barra de botones (a la izquierda arriba por defecto) que nos permitirá mover la gráfica, hacer zoom e incluso guardar cómodamente la gráfica:
[2]:
# Testing matplotlib interactions with a simple plot
fig = plt.figure()
plt.plot(np.sin(np.linspace(0, 20, 100)));
Añadiendo componentes a la interfaz¶
Se pueden incluso crear elementos de interfaz para modificar interactivamente aspectos del gráfico. En el siguiente ejemplo se crea un slider para modificar un parámetro de la gráfica:
[3]:
from ipywidgets import AppLayout, FloatSlider
plt.ioff()
slider = FloatSlider( # Creamos un slider que permite valores de .02 a 2.0 inicializado en 1.0
orientation='horizontal',
description='Factor:',
value=1.0,
min=0.02,
max=2.0
)
slider.layout.margin = '0px 30% 0px 0px' # Márgenes y tamaño del slider
slider.layout.width = '100%'
fig = plt.figure() # Dibujamos la gráfica
fig.canvas.header_visible = False
fig.canvas.layout.min_height = '400px'
plt.title('Plotting: y=sin({} * x)'.format(slider.value))
x = np.linspace(0, 20, 500) # Creamos los puntos de la gráfica
lines = plt.plot(x, np.sin(slider.value * x))
def update_lines(change): # Función que se ejecutará cada vez que se cambie el valor del slider
plt.title('Plotting: y=sin({} * x)'.format(change.new))
lines[0].set_data(x, np.sin(change.new * x))
fig.canvas.draw()
fig.canvas.flush_events()
slider.observe(update_lines, names='value') # Indicamos la función que tiene que ejecutarse cuando cambie el slider
AppLayout( # Indicamos donde tiene que aparecer la gráfica (center) y el slider (abajo)
center=fig.canvas,
footer=slider,
pane_heights=[0, 6, 1]
)
[3]:
Un ejemplo un poco más elaborado¶
Vamos a representar una imagen astronómica y crear 3 sliders para controlar el valor mínimo, máximo y gamma de la paleta de colores. Además veremos que cuando situamos el cursor sobre la imagen nos dice las coordenadas a las que estamos apuntando y el valor del píxel sobre el que nos encontramos (¡muy útil!):
[4]:
%matplotlib widget
import matplotlib.pyplot as plt
from ipywidgets import AppLayout, FloatSlider
from astropy.io import fits
import numpy as np
import matplotlib.colors as colors
from ipywidgets import GridspecLayout
hdul = fits.open("imagenes/m1_new.fit") # La imagen que vamos a representar
data = hdul[0].data
plt.ioff()
plt.clf()
plt.draw()
slider_max = FloatSlider( # Creamos los 3 sliders
orientation='vertical',
description='Max',
value=np.max(data),
min=0,
max=65536
)
slider_gamma = FloatSlider(
orientation='vertical',
description='Gamma',
value=1.0,
min=0.2,
max=5.0
)
slider_min = FloatSlider(
orientation='vertical',
description='Min',
value=np.min(data),
min=0,
max=65536
)
slider_max.layout.padding = '60px 0px 60px 0px' # Cuestiones de margenes y tamaños de los sliders
slider_max.layout.width = '80px'
slider_max.layout.height = '100%'
slider_gamma.layout.padding = '60px 0px 60px 0px'
slider_gamma.layout.width = '80px'
slider_gamma.layout.height = '100%'
slider_min.layout.padding = '60px 0px 60px 0px'
slider_min.layout.width = '80px'
slider_min.layout.height = '100%'
fig = plt.figure() # Creamos la gráfica
fig = plt.figure("matrix", figsize=[10, 5])
fig.canvas.toolbar_position = 'left'
fig.canvas.header_visible = False
image = plt.imshow(data, norm=colors.PowerNorm(gamma=1.0, vmin=np.min(data), vmax=np.max(data)), origin='lower')
plt.colorbar(label='Counts')
def update_max(change): # Función cuando cambiamos el slider max
newval = change.new
if newval <= slider_min.value:
slider_min.value = newval - 1
update_values()
def update_gamma(change): # Función cuando cambiamos el slider gamma
update_values()
def update_min(change): # Función cuando cambiamos el slider min
newval = change.new
if newval >= slider_max.value:
slider_max.value = newval + 1
update_values()
def update_values(): # Actualiza la escala de colores de la gráfica de acuerdo a los valores
# de los sliders
image.set_norm(norm=colors.PowerNorm(gamma=slider_gamma.value, vmin=slider_min.value, vmax=slider_max.value))
fig.canvas.draw()
fig.canvas.flush_events()
slider_max.observe(update_max, names='value') # Asignamos las funciones a llamar en cada cambio de un slider
slider_gamma.observe(update_gamma, names='value')
slider_min.observe(update_min, names='value')
grid = GridspecLayout(1, 3) # Situamos cada uno de los elementos (gráfica y 3 sliders)
grid[0, 0] = slider_min
grid[0, 1] = slider_gamma
grid[0, 2] = slider_max
AppLayout(
center=fig.canvas,
right_sidebar=grid,
pane_widths=[0,5,1.5]
)
[4]:
Se puede usar otros widgets dentro de Jupyter-Lab
: