Axe secondaire de Matplotlib

Beginner

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

Introduction

Matplotlib est une bibliothèque populaire de visualisation de données en Python. Parfois, nous avons besoin de tracer deux échelles de données différentes sur le même graphique, c'est alors que le concept d'axe secondaire intervient. Dans ce laboratoire, nous allons apprendre à créer un axe secondaire dans Matplotlib.

Conseils sur la VM

Une fois le démarrage de la VM terminé, cliquez dans le coin supérieur gauche pour basculer vers l'onglet Notebook pour accéder à Jupyter Notebook pour la pratique.

Parfois, vous devrez peut-être attendre quelques secondes pour que Jupyter Notebook ait fini de charger. La validation des opérations ne peut pas être automatisée en raison des limitations de Jupyter Notebook.

Si vous rencontrez des problèmes pendant l'apprentissage, n'hésitez pas à demander à Labby. Donnez votre feedback après la session, et nous résoudrons rapidement le problème pour vous.

Importez les bibliothèques nécessaires

Nous allons commencer par importer les bibliothèques nécessaires, qui sont matplotlib, numpy et datetime.

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

Tracez les données

Nous allons créer une simple onde sinusoïdale pour démontrer l'utilisation d'un axe secondaire. Nous allons tracer l'onde sinusoïdale en utilisant les degrés comme axe des abscisses.

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('angle [degrees]')
ax.set_ylabel('signal')
ax.set_title('Sine wave')

Créez l'axe secondaire

Nous allons maintenant créer l'axe secondaire et convertir l'axe des abscisses des degrés en radians. Nous utiliserons deg2rad comme fonction de conversion directe et rad2deg comme fonction inverse.

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('angle [rad]')

Tracez un autre exemple

Nous allons maintenant tracer un autre exemple de conversion du nombre d'ondes en longueur d'onde dans une échelle log-log. Nous utiliserons un spectre aléatoire pour cet exemple.

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('Random spectrum')

Créez l'axe des abscisses secondaire

Nous allons créer l'axe des abscisses secondaire et convertir la fréquence en période. Nous utiliserons one_over comme fonction de conversion directe et inverse comme fonction inverse.

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

## the function "1/x" is its own inverse
inverse = one_over

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

Créez l'axe des ordonnées secondaire

Nous allons créer un troisième exemple de relation entre les axes dans une transformation qui est ad hoc à partir des données et est dérivée empiriquement. Dans ce cas, nous allons définir les fonctions de transformation directe et inverse comme étant des interpolations linéaires d'un ensemble de données à l'autre.

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

xold = np.arange(0, 11, 0.2)
## ensemble de données fictif reliant la coordonnée x à une autre coordonnée dérivée des données.
## xnew doit être monotone, donc nous le trions...
xnew = np.sort(10 * np.exp(-xold / 4) + np.random.randn(len(xold)) / 3)

ax.plot(xold[3:], xnew[3:], label='Transform data')
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_{other}$')

Créez plusieurs axes

Nous allons maintenant créer un dernier exemple qui convertit np.datetime64 en jour de l'année sur l'axe des abscisses et de degrés Celsius à degrés Fahrenheit sur l'axe des ordonnées. Nous allons également ajouter un troisième axe des ordonnées et le placer en utilisant un nombre flottant pour l'argument de position.

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):
    """Convertit un numérotateur de date de matplotlib en jours depuis le 01/01/2018."""
    y = x - mdates.date2num(datetime.datetime(2018, 1, 1))
    return y

def yday2date(x):
    """Retourne un numérotateur de date de matplotlib pour *x* jours après le 01/01/2018."""
    y = x + mdates.date2num(datetime.datetime(2018, 1, 1))
    return y

secax_x = ax.secondary_xaxis('top', functions=(date2yday, yday2date))
secax_x.set_xlabel('yday [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))

## utilisation d'un nombre flottant pour la position :
secax_y2 = ax.secondary_yaxis(
    1.2, functions=(celsius_to_anomaly, anomaly_to_celsius))
secax_y2.set_ylabel(r'$T - \overline{T}\ [^oC]$')

Sommaire

Dans ce laboratoire, nous avons appris à créer un axe secondaire dans Matplotlib. Nous avons utilisé divers exemples pour démontrer le concept d'un axe secondaire et la manière de le créer.