Eje secundario en Matplotlib

PythonPythonBeginner
Practicar Ahora

This tutorial is from open-source community. Access the source code

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

Matplotlib es una popular biblioteca de visualización de datos en Python. A veces, necesitamos trazar dos escalas diferentes de datos en la misma gráfica, y es entonces cuando entra en juego el concepto de un eje secundario. En este laboratorio, aprenderemos cómo crear un eje secundario en Matplotlib.

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 las 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

Comenzaremos importando las bibliotecas necesarias, que son matplotlib, numpy y datetime.

import datetime
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.dates as mdates
from matplotlib.ticker import AutoMinorLocator

Trazar los datos

Crearemos una simple onda senoidal para demostrar el uso de un eje secundario. Trazaremos la onda senoidal utilizando grados como el eje x.

fig, ax = plt.subplots(layout='constrained')
x = np.arange(0, 360, 1)
y = np.sin(2 * x * np.pi / 180)
ax.plot(x, y)
ax.set_xlabel('ángulo [grados]')
ax.set_ylabel('señal')
ax.set_title('Onda senoidal')

Crear el eje secundario

Ahora crearemos el eje secundario y convertiremos el eje x de grados a radianes. Usaremos deg2rad como función directa y rad2deg como función inversa.

def deg2rad(x):
    return x * np.pi / 180

def rad2deg(x):
    return x * 180 / np.pi

secax = ax.secondary_xaxis('top', functions=(deg2rad, rad2deg))
secax.set_xlabel('ángulo [rad]')

Trazar otro ejemplo

Ahora trazaremos otro ejemplo de conversión de número de onda a longitud de onda en una escala log-log. Usaremos un espectro aleatorio para este ejemplo.

fig, ax = plt.subplots(layout='constrained')
x = np.arange(0.02, 1, 0.02)
np.random.seed(19680801)
y = np.random.randn(len(x)) ** 2
ax.loglog(x, y)
ax.set_xlabel('f [Hz]')
ax.set_ylabel('PSD')
ax.set_title('Espectro aleatorio')

Crear el eje x secundario

Crearemos el eje x secundario y convertiremos de frecuencia a período. Usaremos one_over como función directa y inverse como función inversa.

def one_over(x):
    """Vectorized 1/x, treating x==0 manually"""
    x = np.array(x, float)
    near_zero = np.isclose(x, 0)
    x[near_zero] = np.inf
    x[~near_zero] = 1 / x[~near_zero]
    return x

## la función "1/x" es su propia inversa
inverse = one_over

secax = ax.secondary_xaxis('top', functions=(one_over, inverse))
secax.set_xlabel('período [s]')

Crear el eje y secundario

Crearemos un tercer ejemplo de relación entre los ejes en una transformación que es ad-hoc a partir de los datos y se deriva empíricamente. En este caso, estableceremos las funciones de transformación directa e inversa para ser interpolaciones lineales de un conjunto de datos al otro.

fig, ax = plt.subplots(layout='constrained')
xdata = np.arange(1, 11, 0.4)
ydata = np.random.randn(len(xdata))
ax.plot(xdata, ydata, label='Datos trazados')

xold = np.arange(0, 11, 0.2)
## Conjunto de datos ficticio que relaciona la coordenada x con otra coordenada derivada de los datos.
## xnew debe ser monotónico, así que lo ordenamos...
xnew = np.sort(10 * np.exp(-xold / 4) + np.random.randn(len(xold)) / 3)

ax.plot(xold[3:], xnew[3:], label='Datos de transformación')
ax.set_xlabel('X [m]')
ax.legend()

def forward(x):
    return np.interp(x, xold, xnew)

def inverse(x):
    return np.interp(x, xnew, xold)

secax = ax.secondary_xaxis('top', functions=(forward, inverse))
secax.xaxis.set_minor_locator(AutoMinorLocator())
secax.set_xlabel('$X_{otro}$')

Crear múltiples ejes

Ahora crearemos un ejemplo final que convierte np.datetime64 a día del año en el eje x y de Celsius a Fahrenheit en el eje y. También agregaremos un tercer eje y y lo colocaremos usando un flotante para el argumento de ubicación.

dates = [datetime.datetime(2018, 1, 1) + datetime.timedelta(hours=k * 6)
         for k in range(240)]
temperature = np.random.randn(len(dates)) * 4 + 6.7
fig, ax = plt.subplots(layout='constrained')

ax.plot(dates, temperature)
ax.set_ylabel(r'$T\ [^oC]$')
plt.xticks(rotation=70)

def date2yday(x):
    """Convertir datenum de matplotlib a días desde 2018-01-01."""
    y = x - mdates.date2num(datetime.datetime(2018, 1, 1))
    return y

def yday2date(x):
    """Devolver un datenum de matplotlib para *x* días después de 2018-01-01."""
    y = x + mdates.date2num(datetime.datetime(2018, 1, 1))
    return y

secax_x = ax.secondary_xaxis('top', functions=(date2yday, yday2date))
secax_x.set_xlabel('día del año [2018]')

def celsius_to_fahrenheit(x):
    return x * 1.8 + 32

def fahrenheit_to_celsius(x):
    return (x - 32) / 1.8

secax_y = ax.secondary_yaxis(
    'right', functions=(celsius_to_fahrenheit, fahrenheit_to_celsius))
secax_y.set_ylabel(r'$T\ [^oF]$')

def celsius_to_anomaly(x):
    return (x - np.mean(temperature))

def anomaly_to_celsius(x):
    return (x + np.mean(temperature))

## uso de un flotante para la posición:
secax_y2 = ax.secondary_yaxis(
    1.2, functions=(celsius_to_anomaly, anomaly_to_celsius))
secax_y2.set_ylabel(r'$T - \overline{T}\ [^oC]$')

Resumen

En este laboratorio, aprendimos cómo crear un eje secundario en Matplotlib. Usamos varios ejemplos para demostrar el concepto de un eje secundario y cómo crearlo.