Nota
Fare clic qui per scaricare il codice di esempio completo
Data Precisione ed Epoche #
Matplotlib può gestire datetime
oggetti e numpy.datetime64
oggetti utilizzando un convertitore di unità che riconosce queste date e le converte in numeri in virgola mobile.
Prima di Matplotlib 3.3, l'impostazione predefinita per questa conversione restituisce un float che era giorni da "0000-12-31T00:00:00". A partire da Matplotlib 3.3, l'impostazione predefinita è giorni da "1970-01-01T00:00:00". Ciò consente una maggiore risoluzione per le date moderne. "2020-01-01" con la vecchia epoca convertita in 730120 e un numero in virgola mobile a 64 bit ha una risoluzione di 2^{-52}, o circa 14 microsecondi, quindi la precisione del microsecondo è stata persa. Con la nuova epoca predefinita "2020-01-01" è 10957.0, quindi la risoluzione ottenibile è di 0,21 microsecondi.
import datetime
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
def _reset_epoch_for_tutorial():
"""
Users (and downstream libraries) should not use the private method of
resetting the epoch.
"""
mdates._reset_epoch_test_example()
Data e ora #
Gli oggetti Python datetime
hanno una risoluzione in microsecondi, quindi con le vecchie date matplotlib predefinite non è possibile eseguire il round trip di oggetti datetime a piena risoluzione.
old_epoch = '0000-12-31T00:00:00'
new_epoch = '1970-01-01T00:00:00'
_reset_epoch_for_tutorial() # Don't do this. Just for this tutorial.
mdates.set_epoch(old_epoch) # old epoch (pre MPL 3.3)
date1 = datetime.datetime(2000, 1, 1, 0, 10, 0, 12,
tzinfo=datetime.timezone.utc)
mdate1 = mdates.date2num(date1)
print('Before Roundtrip: ', date1, 'Matplotlib date:', mdate1)
date2 = mdates.num2date(mdate1)
print('After Roundtrip: ', date2)
Before Roundtrip: 2000-01-01 00:10:00.000012+00:00 Matplotlib date: 730120.0069444446
After Roundtrip: 2000-01-01 00:10:00.000020+00:00
Nota che questo è solo un errore di arrotondamento e non ci sono problemi per le date più vicine alla vecchia epoca:
date1 = datetime.datetime(10, 1, 1, 0, 10, 0, 12,
tzinfo=datetime.timezone.utc)
mdate1 = mdates.date2num(date1)
print('Before Roundtrip: ', date1, 'Matplotlib date:', mdate1)
date2 = mdates.num2date(mdate1)
print('After Roundtrip: ', date2)
Before Roundtrip: 0010-01-01 00:10:00.000012+00:00 Matplotlib date: 3288.006944444583
After Roundtrip: 0010-01-01 00:10:00.000012+00:00
Se un utente desidera utilizzare date moderne con precisione al microsecondo, può modificare l'epoca utilizzando set_epoch
. Tuttavia, l'epoca deve essere impostata prima di qualsiasi operazione di data per evitare confusione tra epoche diverse. Cercare di cambiare l'epoca in un secondo momento genererà un RuntimeError
.
try:
mdates.set_epoch(new_epoch) # this is the new MPL 3.3 default.
except RuntimeError as e:
print('RuntimeError:', str(e))
RuntimeError: set_epoch must be called before dates plotted.
Per questo tutorial, reimpostiamo la sentinella utilizzando un metodo privato, ma gli utenti dovrebbero impostare l'epoca solo una volta, se non del tutto.
_reset_epoch_for_tutorial() # Just being done for this tutorial.
mdates.set_epoch(new_epoch)
date1 = datetime.datetime(2020, 1, 1, 0, 10, 0, 12,
tzinfo=datetime.timezone.utc)
mdate1 = mdates.date2num(date1)
print('Before Roundtrip: ', date1, 'Matplotlib date:', mdate1)
date2 = mdates.num2date(mdate1)
print('After Roundtrip: ', date2)
Before Roundtrip: 2020-01-01 00:10:00.000012+00:00 Matplotlib date: 18262.006944444583
After Roundtrip: 2020-01-01 00:10:00.000012+00:00
dataora64 #
numpy.datetime64
gli oggetti hanno una precisione di microsecondi per uno spazio temporale molto più ampio degli datetime
oggetti. Tuttavia, attualmente il tempo Matplotlib viene riconvertito solo in oggetti datetime, che hanno una risoluzione in microsecondi e anni che vanno solo da 0000 a 9999.
_reset_epoch_for_tutorial() # Don't do this. Just for this tutorial.
mdates.set_epoch(new_epoch)
date1 = np.datetime64('2000-01-01T00:10:00.000012')
mdate1 = mdates.date2num(date1)
print('Before Roundtrip: ', date1, 'Matplotlib date:', mdate1)
date2 = mdates.num2date(mdate1)
print('After Roundtrip: ', date2)
Before Roundtrip: 2000-01-01T00:10:00.000012 Matplotlib date: 10957.006944444583
After Roundtrip: 2000-01-01 00:10:00.000012+00:00
Trama #
Tutto questo ovviamente ha un effetto sulla trama. Con la vecchia epoca predefinita i tempi venivano arrotondati durante la date2num
conversione interna, portando a salti nei dati:
_reset_epoch_for_tutorial() # Don't do this. Just for this tutorial.
mdates.set_epoch(old_epoch)
x = np.arange('2000-01-01T00:00:00.0', '2000-01-01T00:00:00.000100',
dtype='datetime64[us]')
# simulate the plot being made using the old epoch
xold = np.array([mdates.num2date(mdates.date2num(d)) for d in x])
y = np.arange(0, len(x))
# resetting the Epoch so plots are comparable
_reset_epoch_for_tutorial() # Don't do this. Just for this tutorial.
mdates.set_epoch(new_epoch)
fig, ax = plt.subplots(constrained_layout=True)
ax.plot(xold, y)
ax.set_title('Epoch: ' + mdates.get_epoch())
ax.xaxis.set_tick_params(rotation=40)
plt.show()
Per le date tracciate utilizzando l'epoca più recente, la trama è liscia:
fig, ax = plt.subplots(constrained_layout=True)
ax.plot(x, y)
ax.set_title('Epoch: ' + mdates.get_epoch())
ax.xaxis.set_tick_params(rotation=40)
plt.show()
_reset_epoch_for_tutorial() # Don't do this. Just for this tutorial.
Riferimenti
L'uso delle seguenti funzioni, metodi, classi e moduli è mostrato in questo esempio: