Hinweis
Gehen Sie zum Ende, um den vollständigen Beispielcode herunterzuladen.
Sekundärachse#
Manchmal möchten wir eine sekundäre Achse auf einem Diagramm haben, zum Beispiel um Radiant in Grad auf demselben Diagramm umzurechnen. Wir können dies tun, indem wir eine untergeordnete Achse mit nur einer sichtbaren Achse über axes.Axes.secondary_xaxis und axes.Axes.secondary_yaxis erstellen. Diese sekundäre Achse kann eine andere Skalierung als die Hauptachse haben, indem sowohl eine Vorwärts- als auch eine Umkehrfunktion in einem Tupel dem Argument functions übergeben wird.
import datetime
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.dates as mdates
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')
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]')
plt.show()

Standardmäßig wird die sekundäre Achse im Koordinatenraum der Achsen gezeichnet. Wir können auch eine benutzerdefinierte Transformation bereitstellen, um sie in einem anderen Koordinatenraum zu platzieren. Hier platzieren wir die Achse bei Y = 0 in Datenkoordinaten.
fig, ax = plt.subplots(layout='constrained')
x = np.arange(0, 10)
np.random.seed(19680801)
y = np.random.randn(len(x))
ax.plot(x, y)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_title('Random data')
# Pass ax.transData as a transform to place the axis relative to our data
secax = ax.secondary_xaxis(0, transform=ax.transData)
secax.set_xlabel('Axis at Y = 0')
plt.show()

Hier ist der Fall der Umrechnung von Wellenzahl in Wellenlänge auf einer logarithmischen Skala.
Hinweis
In diesem Fall ist die x-Skala des Elternteils logarithmisch, daher wird auch das Kind logarithmisch gemacht.
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')
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]')
plt.show()

Manchmal möchten wir die Achsen in einer Transformation in Beziehung setzen, die ad hoc aus den Daten abgeleitet und empirisch ermittelt wird. Oder eine Achse könnte eine komplizierte nichtlineare Funktion der anderen sein. In diesen Fällen können wir die Vorwärts- und Umkehrtansformationsfunktionen als lineare Interpolationen von der einen Menge unabhängiger Variablen zur anderen setzen.
Hinweis
Um die Datenränder ordnungsgemäß zu behandeln, müssen die Abbildungsfunktionen (forward und inverse in diesem Beispiel) über die nominalen Plotgrenzen hinaus definiert sein. Diese Bedingung kann erzwungen werden, indem die Interpolation über die geplotteten Werte hinaus, sowohl nach links als auch nach rechts, ausgedehnt wird, siehe x1n und x2n unten.
fig, ax = plt.subplots(layout='constrained')
x1_vals = np.arange(2, 11, 0.4)
# second independent variable is a nonlinear function of the other.
x2_vals = x1_vals ** 2
ydata = 50.0 + 20 * np.random.randn(len(x1_vals))
ax.plot(x1_vals, ydata, label='Plotted data')
ax.plot(x1_vals, x2_vals, label=r'$x_2 = x_1^2$')
ax.set_xlabel(r'$x_1$')
ax.legend()
# the forward and inverse functions must be defined on the complete visible axis range
x1n = np.linspace(0, 20, 201)
x2n = x1n**2
def forward(x):
return np.interp(x, x1n, x2n)
def inverse(x):
return np.interp(x, x2n, x1n)
# use axvline to prove that the derived secondary axis is correctly plotted
ax.axvline(np.sqrt(40), color="grey", ls="--")
ax.axvline(10, color="grey", ls="--")
secax = ax.secondary_xaxis('top', functions=(forward, inverse))
secax.set_xticks([10, 20, 40, 60, 80, 100])
secax.set_xlabel(r'$x_2$')
plt.show()

Ein letztes Beispiel übersetzt np.datetime64 in Tag des Jahres auf der x-Achse und von Celsius in Fahrenheit auf der y-Achse. Beachten Sie die Hinzufügung einer dritten y-Achse und dass sie mithilfe einer Gleitkommazahl für das Positionsargument platziert werden kann.
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]$')
ax.xaxis.set_tick_params(rotation=70)
def date2yday(x):
"""Convert matplotlib datenum to days since 2018-01-01."""
y = x - mdates.date2num(datetime.datetime(2018, 1, 1))
return y
def yday2date(x):
"""Return a matplotlib datenum for *x* days after 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('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))
# use of a float for the position:
secax_y2 = ax.secondary_yaxis(
1.2, functions=(celsius_to_anomaly, anomaly_to_celsius))
secax_y2.set_ylabel(r'$T - \overline{T}\ [^oC]$')
plt.show()

Referenzen
Die Verwendung der folgenden Funktionen, Methoden, Klassen und Module wird in diesem Beispiel gezeigt
Gesamtlaufzeit des Skripts: (0 Minuten 5,575 Sekunden)