Python científico y graficación · Licenciatura avanzada / posgrado inicial · 10 horas
Matplotlib: gráficas básicas y dinámica
Primeras gráficas, Figure y Axes, escalas, color, paneles, exportación, animación y representaciones de sistemas dinámicos.
Primera gráfica con Figure y Axes
Matplotlib es la biblioteca pública de graficación usada en este curso. La
instrucción import matplotlib.pyplot as plt carga su interfaz
pyplot bajo el alias plt. Antes de representar una
trayectoria, conviene aprender con una curva conocida y un bloque completo:
import numpy as np
import matplotlib.pyplot as plt
times = np.linspace(0.0, 8.0, 401)
signal = np.exp(-0.25 * times) * np.cos(2.0 * times)
fig, ax = plt.subplots(figsize=(7.2, 4.5), constrained_layout=True)
ax.plot(times, signal, color="#0e7490", linewidth=1.6, label="$x(t)$")
ax.set_xlabel("tiempo")
ax.set_ylabel("amplitud")
ax.set_title("Oscilación amortiguada")
ax.grid(alpha=0.2)
ax.legend(frameon=False)
plt.show()
plt.subplots() devuelve dos objetos: fig representa
la figura completa y ax representa el sistema de ejes.
ax.plot(x, y, …) recibe las coordenadas como argumentos
posicionales y el color, el grosor y la etiqueta como argumentos nombrados.
Los métodos set_xlabel, set_ylabel y
set_title modifican ese eje concreto. plt.show()
presenta la figura en Jupyter o en un intérprete interactivo.
La guía rápida oficial de Matplotlib
presenta la jerarquía principal. Una Figure es la figura completa;
cada Axes es una región con sistema de coordenadas. Los métodos de
los ejes controlan líneas, etiquetas, límites y escalas. En los apartados
siguientes se reemplaza la señal conocida por arreglos times y
states producidos por un integrador.
La interfaz orientada a objetos hace explícito qué panel recibe cada elemento. Usar llamadas globales es cómodo para un boceto, pero en una figura con varios ejes puede enviar etiquetas, leyendas o límites al panel activo equivocado.
Práctica interactiva. Ejecuta el bloque completo en Jupyter o en un entorno Python del navegador. Cambia primero solo la frecuencia, después solo el amortiguamiento y finalmente el intervalo temporal. Escribe debajo de cada figura qué cambió en la señal y qué llamada de Matplotlib modificaste. Guarda la animación para más adelante: esta práctica trabaja únicamente con una curva estática y no requiere archivos ni hardware externo.
Escalas y representación fiel
Un retrato de fase compara coordenadas. Si una unidad en ocupa una longitud visual distinta de una unidad en , círculos y ángulos se deforman:
fig, ax = plt.subplots(figsize=(5.5, 5.5), constrained_layout=True)
ax.plot(states[:, 0], states[:, 1], linewidth=0.8)
ax.set(xlabel="$x$", ylabel="$y$")
ax.set_aspect("equal", adjustable="box")
Para una trayectoria states con forma (n, 3), las
proyecciones planas y la vista tridimensional deben usar exactamente las mismas
filas. El siguiente procedimiento valida la geometría, conserva una muestra
común y fija la cámara:
import numpy as np
import matplotlib.pyplot as plt
states = np.asarray(states, dtype=float)
if states.ndim != 2 or states.shape[1] != 3:
raise ValueError("states debe tener forma (n, 3)")
if not np.isfinite(states).all():
raise ValueError("la trayectoria contiene valores no finitos")
sample = states[::5]
fig = plt.figure(figsize=(11, 4), constrained_layout=True)
ax_xy = fig.add_subplot(1, 3, 1)
ax_xz = fig.add_subplot(1, 3, 2)
ax_3d = fig.add_subplot(1, 3, 3, projection="3d")
ax_xy.plot(sample[:, 0], sample[:, 1], linewidth=0.6)
ax_xz.plot(sample[:, 0], sample[:, 2], linewidth=0.6)
ax_3d.plot(*sample.T, linewidth=0.55)
ax_xy.set(xlabel="$x$", ylabel="$y$")
ax_xz.set(xlabel="$x$", ylabel="$z$")
ax_3d.set(xlabel="$x$", ylabel="$y$", zlabel="$z$")
ax_3d.view_init(elev=24, azim=-58)
El muestreo reduce el costo de dibujo, no la integración, y su salto se registra junto con la figura. Un cruce en el panel no demuestra una intersección de órbitas: puntos con distinto pueden compartir la misma proyección. La vista 3D permite comprobar esa posibilidad, mientras que la cámara fija hace reproducible la comparación entre ejecuciones.
La relación igual es apropiada cuando interesa geometría euclidiana. No siempre es adecuada: una serie temporal con amplitud pequeña y duración grande sería ilegible. La decisión se liga a la pregunta y se declara en el pie.
Una escala logarítmica exige valores positivos y cambia la lectura de distancias. Para una curva de error:
ax.loglog(step_sizes, errors, "o-", label="error medido")
ax.loglog(step_sizes, 0.8 * step_sizes**4, "--", label=r"referencia $h^4$")
La línea de referencia debe usar una constante visible en la ventana y se presenta como pendiente esperada, no como ajuste. Recortar ejes puede revelar detalle, pero también ocultar saturación o cambios de signo. Los límites seleccionados forman parte del resultado.
Color, línea y contraste
El color codifica una variable cuando existe una leyenda o barra de color. No se usa únicamente para hacer la figura “más viva”. Dos curvas importantes también se distinguen con estilo de línea, marcador o grosor para conservar lectura en escala de grises y para personas con deficiencias de percepción del color.
Un mapa de cuencas usa colores categóricos: los números de etiqueta no tienen orden cuantitativo. Una densidad o exponente usa una paleta secuencial o divergente según el cero tenga significado. Cambiar paleta no debe cambiar la clasificación subyacente.
En una trayectoria larga, una línea gruesa puede rellenar huecos y fingir una superficie. Se compara una línea fina con puntos o una sección. La transparencia puede revelar densidad, pero depende del orden de dibujo. El pie debe aclarar si el color representa tiempo, velocidad, clase o simplemente identifica una curva.
Paneles coordinados de un experimento
Atlas reproducible de sistemas dinámicos Función: plot_spectrum
Se muestra el código fuente completo en Python. Las funciones indicadas arriba producen esta figura; el archivo declara las bibliotecas requeridas e incluye las funciones auxiliares. Este control no ejecuta código en el servidor.
El script se cargará al abrir este panel. Una figura de serie y espectro comparte datos, no necesariamente ejes:
fig, (ax_time, ax_psd) = plt.subplots(
1, 2, figsize=(10.5, 4.2), constrained_layout=True
)
ax_time.plot(times, x, color="#0e7490", linewidth=0.9)
ax_time.set(xlabel="tiempo", ylabel="$x(t)$")
ax_psd.semilogy(frequency, power, color="#be123c", linewidth=1.2)
ax_psd.set(xlabel="frecuencia", ylabel="densidad de potencia")
El eje logarítmico de potencia no autoriza a ocultar ceros sin documentarlo. La función que calcula el espectro devuelve frecuencia, potencia y parámetros; la función de dibujo solo presenta. Así es posible probar el cálculo sin comparar píxeles.
No se colocan títulos dentro de los paneles. Las etiquetas de los ejes, la leyenda y las marcas identifican las variables; el pie de la página nombra el objeto y explica procedencia, configuración y lectura. Así la gráfica conserva espacio para los datos sin repetir “Espectro de Fourier” dentro del panel y en el texto que la acompaña.
Escala común para comparaciones
Dos curvas solo pueden compararse visualmente si los ejes conservan el mismo significado. Al mostrar errores de Euler y RK4, cada serie debe usar el mismo intervalo temporal, estado inicial y definición de norma. Si cada panel ajusta automáticamente sus límites, errores de órdenes de magnitud distintos pueden parecer iguales. Compartir el eje vertical o declarar límites comunes evita esa equivalencia artificial; cuando una escala común vuelve invisible una curva, un segundo panel de cocientes puede aportar el detalle sin alterar el panel principal.
Las bandas también exigen una interpretación concreta. Una región sombreada
puede representar variación entre condiciones iniciales, incertidumbre de
medición, cuantiles o error estimado del método. fill_between solo
dibuja dos fronteras: la semántica procede del cálculo y del pie. No debe
presentarse como “incertidumbre” una envolvente de máximos y mínimos sin decir
cuántas corridas contiene ni cómo fueron elegidas.
Para una familia de parámetros, superponer cincuenta líneas suele ocultar más de lo que revela. Se puede seleccionar valores representativos con una regla previa, codificar el parámetro mediante una paleta continua y añadir una barra de color. Otra opción es resumir una observable —periodo, máximo o tasa de escape— contra el parámetro. La segunda figura responde una pregunta distinta: ya no muestra trayectorias individuales, sino una reducción calculada. Conviene conservar una trayectoria verificable para que esa reducción no parezca surgir directamente del color.
Las anotaciones deben marcar cantidades calculadas. Si se señala un máximo, su coordenada proviene de un índice o de una localización refinada y se guarda junto con los datos; colocar una flecha manualmente “cerca” del máximo rompe la reproducibilidad. Lo mismo vale para un cruce, una bifurcación aproximada o la pendiente de una recta logarítmica. Texto, marcador y valor numérico deben referirse al mismo objeto computado.
Una comprobación útil consiste en intercambiar deliberadamente el orden de las curvas y volver a exportar. Si la conclusión cambia por oclusión, transparencia o prioridad visual, la representación es frágil. Separar paneles, adelgazar líneas o mostrar una diferencia directa resuelve el problema mejor que elegir un orden favorable.
Exportación y trazabilidad
Una figura para web y otra para impresión pueden compartir datos y estructura, pero usar estilos diferentes:
def save_figure(fig, path, *, metadata):
fig.savefig(
path,
dpi=180,
bbox_inches="tight",
metadata=metadata,
)
save_figure(
fig,
"results/lorenz_series_psd.png",
metadata={"Creator": "figures.py", "Description": "config=lorenz-028"},
)
PNG conserva píxeles y funciona bien para mapas densos; SVG conserva vectores y es adecuado para líneas, texto y diagramas pequeños. Una trayectoria con millones de puntos puede producir un SVG pesado. La elección se prueba con el tamaño y el destino reales.
El parámetro de resolución no repara etiquetas diminutas. Se diseña primero el tamaño físico, tipografía y grosor; después se elige DPI. Antes de guardar se verifica que ningún elemento quede cortado y que la leyenda no cubra la región que sustenta la conclusión.
Para temas claro y oscuro se puede centralizar un diccionario de estilos. Los datos y límites permanecen iguales; cambian fondo, texto y colores. Si una variante necesita otra normalización para “verse bien”, ya no es solo un cambio de tema y debe justificarse.
Dimensión temporal en una animación
La referencia oficial de
animaciones de Matplotlib
explica el ciclo de cuadros. FuncAnimation llama a una función que
actualiza artistas existentes:
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots(figsize=(5.5, 5.5))
line, = ax.plot([], [], color="#be123c", linewidth=1.4)
point, = ax.plot([], [], "o", color="#0e7490")
ax.set_xlim(x.min(), x.max())
ax.set_ylim(y.min(), y.max())
def update(frame):
stop = frame + 1
line.set_data(x[:stop], y[:stop])
point.set_data([x[frame]], [y[frame]])
return line, point
animation = FuncAnimation(
fig,
update,
frames=range(0, len(x), 12),
interval=35,
blit=True,
)
La función devuelve los artistas modificados para que el modo
blit redibuje solo lo necesario. Los límites se fijan antes; si
cambian en cada cuadro, el movimiento aparente mezcla dinámica con una cámara
que reajusta la escala.
Una animación de telaraña puede variar el número de iteraciones manteniendo fijo. Otra puede variar manteniendo fijo. Responden preguntas distintas y no deben combinarse sin indicarlo. Una rotación tridimensional cambia la cámara, no la trayectoria.
El primer cuadro debe funcionar como alternativa estática. La duración, velocidad y salto entre cuadros se eligen para observar el mecanismo, no para imitar el tiempo físico salvo que exista una conversión declarada. Se conserva también el PNG porque el GIF puede no cargarse, no imprimirse o resultar inaccesible.
Mandelbrot y Julia: parámetros del experimento
La misma regla compleja
produce dos imágenes distintas según qué cantidad se mantenga fija. Para el conjunto de Mandelbrot se fija y cada píxel representa un parámetro . Para un conjunto de Julia se fija y cada píxel representa una condición inicial . Mezclar ambos planos en una sola explicación vuelve ambiguo qué significa el color. El volumen editado por Devaney y Keen organiza precisamente esa relación entre la dinámica de los conjuntos de Julia y la geografía del plano de parámetros Devaney, 1989 Robert L. Devaney y Linda Keen, editores (1989) Chaos and Fractals: The Mathematics Behind the Computer Graphics Proceedings of Symposia in Applied Mathematics, vol. 39 · American Mathematical Society Ubicación consultada: Linda Keen, «Julia Sets»; Bodil Branner, «The Mandelbrot Set» Abrir fuente .
El criterio computacional se apoya en una estimación sencilla. Si en alguna iteración , entonces la sucesión escapa al infinito. El recíproco no puede decidirse después de un número finito de pasos: un píxel que no escapó en iteraciones queda clasificado como no resuelto dentro del horizonte, no como miembro demostrado del conjunto. Un cálculo vectorizado conserva esa distinción:
import numpy as np
def escape_time(z0, c, max_iter=300):
z = np.asarray(z0, dtype=np.complex128).copy()
c = np.broadcast_to(c, z.shape)
escaped = np.zeros(z.shape, dtype=bool)
count = np.full(z.shape, max_iter, dtype=int)
for n in range(max_iter):
active = ~escaped
z[active] = z[active] ** 2 + c[active]
new = active & (np.abs(z) > 2.0)
count[new] = n + 1
escaped |= new
return count, escaped
En el plano de Mandelbrot, z0 es una matriz de ceros y c contiene la malla
compleja. Para Julia se intercambian los papeles: z0 contiene la malla y c
es constante. Addison desarrolla la relación entre la
fórmula iterada y su representación visual Addison, 1997 Paul S. Addison (1997) Fractals and Chaos: An Illustrated Course Institute of Physics Publishing Ubicación consultada: §§5.9–5.10.5, pp. 106–113 .
Visuales reproducibles de fractales Función: make_escape_figure
Se muestra el código fuente completo en Python. Las funciones indicadas arriba producen esta figura; el archivo declara las bibliotecas requeridas e incluye las funciones auxiliares. Este control no ejecuta código en el servidor.
El script se cargará al abrir este panel. Para interpretar el color hacen falta extent, origen, relación de aspecto,
colormap, normalización y valor de max_iter. Una paleta espectacular puede
crear bandas que parecen fronteras dinámicas aunque sólo sean intervalos del
mapa de color. Pickover reúne exploraciones computacionales donde eficiencia,
selección de región y codificación cromática forman parte del experimento; la
lección útil es separar la matriz de tiempos de escape de la función que la
dibuja Pickover, 1998 Clifford A. Pickover, editor (1998) Chaos and Fractals: A Computer Graphical Journey Ten Year Compilation of Advanced Research · Elsevier Science Ubicación consultada: parte IV, pp. 219–346; tutorial de Rojas, pp. 225–234 .
Una comprobación mínima calcula primero una malla pequeña con casos conocidos: no escapa desde , mientras supera el radio de escape. Luego se duplica la resolución sin cambiar la ventana. Si aparecen estructuras nuevas por el mayor detalle es esperable; si se desplazan los ejes o cambia la clasificación de puntos que escapaban pronto, hay un error de implementación.
Telaraña del mapa logístico
La función logística y la diagonal se dibujan una sola vez. Los segmentos se generan como parejas vertical-horizontal:
def cobweb_segments(fun, x0, count):
xs, ys = [], []
x = float(x0)
for _ in range(count):
y = float(fun(x))
xs.extend((x, x, y))
ys.extend((x, y, y))
x = y
return np.asarray(xs), np.asarray(ys)
Cada trío contiene el punto en la diagonal, la evaluación vertical y el regreso horizontal. La línea que los une no es una trayectoria continua. Strogatz usa la geometría de mapas para hacer visible estabilidad, ciclos y duplicación Strogatz, 2015 Steven H. Strogatz (2015) Nonlinear Dynamics and Chaos: With Applications to Physics, Biology, Chemistry, and Engineering 2.ª ed. · Westview Press Ubicación consultada: cap. 10 . El libro aporta el experimento matemático; la guía oficial de Matplotlib aporta la implementación visual.
Se prueban casos conocidos: para la telaraña converge al punto fijo; para llega a un ciclo de periodo dos. Una prueba de la función comprueba el número de coordenadas y los primeros segmentos; una revisión visual comprueba relación de aspecto, diagonal y etiquetas.
Práctica ejecutable
Gráfica de una oscilación amortiguada
Ejecuta la gráfica, cambia la tasa de amortiguamiento y verifica que título, ejes, leyenda y unidades sigan describiendo los datos.
Listo para ejecutar.
Salida
Todavía no se ha ejecutado el programa.
Ejecución, privacidad y límites
El programa se ejecuta en un Web Worker dentro de este navegador. No usa la Raspberry Pi ni un proceso Python del servidor de Fyskode. Al pulsar Ejecutar por primera vez, el navegador descarga Pyodide y las bibliotecas importadas desde el CDN oficial de jsDelivr; esas solicitudes siguen la política de privacidad del CDN. El código escrito aquí no se envía a Fyskode.
Cada ejecución dispone de hasta 60 segundos, 200 000 caracteres de salida y seis gráficas; las figuras excesivamente grandes se omiten. El tiempo se cuenta después de cargar el motor y las bibliotecas. Detener o agotar el tiempo elimina el Worker y su memoria. El entorno no tiene acceso directo a los archivos del equipo, pero un programa puede solicitar recursos de red si se le ordena; no pegues contraseñas ni credenciales.
Control visual de la telaraña y el espectro
- Comprueba ejes, unidades, límites y relación de aspecto.
- Verifica la lectura en claro, oscuro y escala de grises.
- Separa cálculo de datos y función de dibujo.
- Exporta PNG y SVG y compara nitidez, peso y uso previsto.
- Reproduce la figura desde una configuración, no desde variables ocultas.
- Revisa que la animación varíe una idea y conserve alternativa estática.
El espectro debe conservar sus parámetros de muestreo y la telaraña su regla de iteración. Con esos datos en el pie y en el manifiesto, ambas figuras pueden leerse sin abrir el código y reconstruirse sin adivinar decisiones gráficas.
Fuentes consultadas
Obras citadas en el desarrollo; los localizadores indican los capítulos o secciones consultados.Steven H. Strogatz (2015). Nonlinear Dynamics and Chaos: With Applications to Physics, Biology, Chemistry, and Engineering. 2.ª ed. Westview Press. ISBN 978-0-8133-4910-7.
caps. 9–12 · Experimentos geométricos de Lorenz, mapas, fractales y Rössler.Kathleen T. Alligood, Tim D. Sauer y James A. Yorke (1996). Chaos: An Introduction to Dynamical Systems. Springer. ISBN 0-387-94677-2.
caps. 1, 4 y 13 · Telarañas, dimensión y series temporales usadas como casos visuales.- Linda Keen, «Julia Sets»; Bodil Branner, «The Mandelbrot Set» · Relación entre iteración compleja, conjuntos de Julia y plano de parámetros.
Paul S. Addison (1997). Fractals and Chaos: An Illustrated Course. Institute of Physics Publishing. ISBN 0-7503-0400-6.
§§5.9–5.10.5, pp. 106–113 · Construcción computacional de Julia, Mandelbrot e IFS mediante gráficos de escape.Clifford A. Pickover, editor (1998). Chaos and Fractals: A Computer Graphical Journey. Ten Year Compilation of Advanced Research Elsevier Science. ISBN 0-444-50002-2.
parte IV, pp. 219–346; tutorial de Rojas, pp. 225–234 · Decisiones algorítmicas y visuales para explorar fractales en computadora.