Introducción
En este laboratorio, aprenderemos cómo crear histogramas con relleno de sombreado utilizando Matplotlib. Un histograma es una representación gráfica de datos que utiliza barras para mostrar la frecuencia de datos numéricos. Un histograma con relleno de sombreado es un histograma en el que las barras están llenas con un patrón de líneas, puntos u otros símbolos.
Consejos sobre la VM
Una vez finalizada la inicialización de la VM, haga clic en la esquina superior izquierda para cambiar a la pestaña Cuaderno y acceder a Jupyter Notebook para practicar.
A veces, es posible que tenga que esperar unos segundos a que Jupyter Notebook termine de cargarse. La validación de operaciones no se puede automatizar debido a las limitaciones de Jupyter Notebook.
Si tiene problemas durante el aprendizaje, no dude en preguntar a Labby. Deje sus comentarios después de la sesión y lo resolveremos rápidamente para usted.
Importar las bibliotecas necesarias
Importaremos las bibliotecas necesarias para este laboratorio. Necesitamos las siguientes bibliotecas:
numpypara generar datos aleatoriosmatplotlib.pyplotpara crear gráficosmatplotlib.tickerpara establecer las ubicaciones de las marcas de los ejescyclerpara crear ciclos de estilofunctools.partialpara crear una función parcial
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
from cycler import cycler
from functools import partial
Definir la función de histograma
Definiremos una función para dibujar un histograma como un parche escalonado. La función tomará los siguientes parámetros:
ax: los Ejes en los que se dibujaráedges: una matriz de longitud n+1 que da los bordes izquierdos de cada intervalo y el borde derecho del último intervalovalues: una matriz de longitud n de conteos o valores de intervalosbottoms: un flotante o matriz, opcional, una matriz de longitud n de la base de las barras. Si es None, se utiliza cero.orientation: una cadena, opcional, la orientación del histograma. 'v' (por defecto) hace que las barras crezcan en la dirección y positiva.
def filled_hist(ax, edges, values, bottoms=None, orientation='v', **kwargs):
"""
Dibuja un histograma como un parche escalonado.
Parámetros
----------
ax : Ejes
Los ejes en los que se dibujará
edges : matriz
Una matriz de longitud n+1 que da los bordes izquierdos de cada intervalo y el
borde derecho del último intervalo.
values : matriz
Una matriz de longitud n de conteos o valores de intervalos
bottoms : flotante o matriz, opcional
Una matriz de longitud n de la base de las barras. Si es None, se utiliza cero.
orientation : {'v', 'h'}
Orientación del histograma. 'v' (por defecto) hace que
las barras crezcan en la dirección y positiva.
**kwargs
Argumentos de palabras clave adicionales se transmiten a `.fill_between`.
Devuelve
-------
ret : PolyCollection
Artista agregado a los Ejes
"""
if orientation not in 'hv':
raise ValueError(f"orientation must be in {{'h', 'v'}} not {orientation}")
kwargs.setdefault('step', 'post')
kwargs.setdefault('alpha', 0.7)
edges = np.asarray(edges)
values = np.asarray(values)
if len(edges) - 1!= len(values):
raise ValueError(f'Must provide one more bin edge than value not: {len(edges)=} {len(values)=}')
if bottoms is None:
bottoms = 0
bottoms = np.broadcast_to(bottoms, values.shape)
values = np.append(values, values[-1])
bottoms = np.append(bottoms, bottoms[-1])
if orientation == 'h':
return ax.fill_betweenx(edges, values, bottoms, **kwargs)
elif orientation == 'v':
return ax.fill_between(edges, values, bottoms, **kwargs)
else:
raise AssertionError("you should never be here")
Definir la función de histograma apilado
Definiremos una función para crear un histograma apilado. La función tomará los siguientes parámetros:
ax: los ejes a los que se agregarán los artistasstacked_data: una matriz con forma (M, N). La primera dimensión se iterará para calcular los histogramas fila por filasty_cycle: un Cycler o objeto operable de diccionarios, el estilo que se aplicará a cada conjuntobottoms: una matriz, valor predeterminado: 0, las posiciones iniciales de las baseshist_func: una función llamada, opcional. Debe tener la firmabin_vals, bin_edges = f(data). Se espera quebin_edgessea una unidad más larga quebin_valslabels: una lista de cadenas, opcional, la etiqueta para cada conjunto. Si no se da y los datos apilados son una matriz, el valor predeterminado es 'conjunto predeterminado {n}'. Sistacked_dataes un mapeo ylabelses None, el valor predeterminado es las claves. Sistacked_dataes un mapeo y se danlabels, entonces solo se graficarán las columnas listadasplot_func: una función llamada, opcional, función que se llamará para dibujar el histograma. Debe tener la firmaret = plot_func(ax, edges, top, bottoms=bottoms, label=label, **kwargs)plot_kwargs: un diccionario, opcional, cualquier argumento de palabras clave adicional que se transmitirá a la función de trazado. Esto será el mismo para todas las llamadas a la función de trazado y sobrescribirá los valores ensty_cycle.
def stack_hist(ax, stacked_data, sty_cycle, bottoms=None, hist_func=None, labels=None, plot_func=None, plot_kwargs=None):
"""
Parámetros
----------
ax : axes.Axes
Los ejes a los que se agregarán los artistas
stacked_data : matriz o Mapeo
Una matriz con forma (M, N). La primera dimensión se iterará para
calcular los histogramas fila por fila
sty_cycle : Cycler o objeto operable de diccionarios
Estilo que se aplicará a cada conjunto
bottoms : matriz, valor predeterminado: 0
Las posiciones iniciales de las bases.
hist_func : callable, opcional
Debe tener la firma `bin_vals, bin_edges = f(data)`.
Se espera que `bin_edges` sea una unidad más larga que `bin_vals`
labels : lista de str, opcional
La etiqueta para cada conjunto.
Si no se da y los datos apilados son una matriz, el valor predeterminado es 'conjunto predeterminado {n}'
Si *stacked_data* es un mapeo, y *labels* es None, el valor predeterminado es las
claves.
Si *stacked_data* es un mapeo y *labels* se da, entonces solo se graficarán las
columnas listadas.
plot_func : callable, opcional
Función que se llamará para dibujar el histograma debe tener la firma:
ret = plot_func(ax, edges, top, bottoms=bottoms,
label=label, **kwargs)
plot_kwargs : dict, opcional
Cualquier argumento de palabras clave adicional que se transmitirá a la función de trazado.
Esto será el mismo para todas las llamadas a la función de trazado y sobrescribirá los valores en *sty_cycle*.
Devuelve
-------
arts : dict
Diccionario de artistas con sus etiquetas como claves
"""
## manejar la función de agrupamiento de intervalos predeterminada
if hist_func is None:
hist_func = np.histogram
## manejar la función de trazado predeterminada
if plot_func is None:
plot_func = filled_hist
## manejar el predeterminado
if plot_kwargs is None:
plot_kwargs = {}
try:
l_keys = stacked_data.keys()
label_data = True
if labels is None:
labels = l_keys
except AttributeError:
label_data = False
if labels is None:
labels = itertools.repeat(None)
if label_data:
loop_iter = enumerate((stacked_data[lab], lab, s) for lab, s in zip(labels, sty_cycle))
else:
loop_iter = enumerate(zip(stacked_data, labels, sty_cycle))
arts = {}
for j, (data, label, sty) in loop_iter:
if label is None:
label = f'dflt set {j}'
label = sty.pop('label', label)
vals, edges = hist_func(data)
if bottoms is None:
bottoms = np.zeros_like(vals)
top = bottoms + vals
sty.update(plot_kwargs)
ret = plot_func(ax, edges, top, bottoms=bottoms, label=label, **sty)
bottoms = top
arts[label] = ret
ax.legend(fontsize=10)
return arts
Configurar la función de histograma con intervalos fijos
Configuraremos una función de histograma con intervalos fijos utilizando numpy.histogram. Crearemos 20 intervalos que van desde -3 hasta 3.
edges = np.linspace(-3, 3, 20, endpoint=True)
hist_func = partial(np.histogram, bins=edges)
Configurar ciclos de estilo
Configuraremos ciclos de estilo para los histogramas utilizando cycler. Crearemos tres ciclos de estilo: uno para el color de fondo, uno para la etiqueta y uno para el patrón de sombreado.
color_cycle = cycler(facecolor=plt.rcParams['axes.prop_cycle'][:4])
label_cycle = cycler(label=[f'set {n}' for n in range(4)])
hatch_cycle = cycler(hatch=['/', '*', '+', '|'])
Generar datos aleatorios
Generaremos datos aleatorios utilizando numpy.random.randn. Generaremos 4 conjuntos de datos con 12250 puntos cada uno.
np.random.seed(19680801)
stack_data = np.random.randn(4, 12250)
Crear el histograma con sombreado
Crearemos un histograma con sombreado utilizando la función stack_hist que definimos anteriormente. Utilizaremos los stack_data, color_cycle y hist_func que definimos anteriormente. También estableceremos plot_kwargs para incluir el color del borde y la orientación.
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 4.5), tight_layout=True)
arts = stack_hist(ax1, stack_data, color_cycle + label_cycle + hatch_cycle, hist_func=hist_func)
arts = stack_hist(ax2, stack_data, color_cycle, hist_func=hist_func, plot_kwargs=dict(edgecolor='w', orientation='h'))
ax1.set_ylabel('conteos')
ax1.set_xlabel('x')
ax2.set_xlabel('conteos')
ax2.set_ylabel('x')
Crear el histograma con sombreado y etiquetas
Crearemos un histograma con sombreado y etiquetas utilizando la función stack_hist que definimos anteriormente. Utilizaremos el dict_data, color_cycle y hist_func que definimos anteriormente. También estableceremos labels en ['set 0','set 3'] para graficar solo el primer y el último conjunto.
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 4.5), tight_layout=True, sharey=True)
dict_data = dict(zip((c['label'] for c in label_cycle), stack_data))
arts = stack_hist(ax1, dict_data, color_cycle + hatch_cycle, hist_func=hist_func)
arts = stack_hist(ax2, dict_data, color_cycle + hatch_cycle, hist_func=hist_func, labels=['set 0','set 3'])
ax1.xaxis.set_major_locator(mticker.MaxNLocator(5))
ax1.set_xlabel('conteos')
ax1.set_ylabel('x')
ax2.set_ylabel('x')
Resumen
En este laboratorio, aprendimos cómo crear histogramas con sombreado utilizando Matplotlib. Definimos dos funciones: filled_hist para dibujar un histograma como un parche escalonado y stack_hist para crear un histograma apilado. También configuramos una función de histograma con bins fijos utilizando numpy.histogram y definimos tres ciclos de estilo para los histogramas utilizando cycler. Finalmente, generamos datos aleatorios y creamos dos histogramas con sombreado utilizando la función stack_hist.