web-dev-qa-db-fra.com

pandas nuage de points de traçage datetime

J'ai une trame de données avec deux colonnes de datetime.time. Je voudrais les disperser. J'aimerais aussi que les axes affichent les heures, idéalement. Mais

df.plot(kind='scatter', x='T1', y='T2')

vide un tas d'erreurs de tracé internes se terminant par une erreur KeyError sur "T1".

Alternativement, j'essaye

plt.plot_date(x=df.loc[:,'T1'], y=df.loc[:,'T2'])
plt.show()

et j'obtiens "Exception dans le rappel Tkinter" avec une longue analyse de pile se terminant par

return _from_ordinalf(x, tz)
  File "/usr/lib/python3/dist-packages/matplotlib/dates.py", line 224, in _from_ordinalf
microsecond, tzinfo=UTC).astimezone(tz)
TypeError: tzinfo argument must be None or of a tzinfo subclass, not type 'str'

Des pointeurs?

25
jma

Pas une vraie réponse mais une solution de contournement, comme suggéré par Tom Augspurger, est que vous pouvez simplement utiliser le type de tracé de ligne de travail et spécifier des points au lieu de lignes:

df.plot(x='x', y='y', style=".")
35
Aaron Schumacher

Pas une réponse, mais je ne peux pas éditer la question ou mettre autant dans un commentaire, je pense.

Voici un exemple reproductible:

from datetime import datetime
import pandas as pd
df = pd.DataFrame({'x': [datetime.now() for _ in range(10)], 'y': range(10)})
df.plot(x='x', y='y', kind='scatter')

Cela donne KeyError: 'x'.

Fait intéressant, vous obtenez un tracé avec juste df.plot(x='x', y='y'); il choisit mal pour la plage x par défaut car les temps ne sont séparés que de quelques nanosecondes, ce qui est bizarre, mais c'est un problème distinct. Il semble que si vous pouvez faire un graphique linéaire, vous devriez également pouvoir faire un nuage de points.

Il y a a pandas github issue à propos de ce problème, mais il a été fermé pour une raison quelconque. Je vais aller commenter là-bas et voir si nous pouvons redémarrer cette conversation.

Existe-t-il des solutions intelligentes pour cela? Si oui, quoi?

5
Aaron Schumacher

en s'appuyant sur la réponse de Mike N ... convertissez-vous en temps unix pour vous disperser correctement, puis retransformez vos étiquettes d'axe des int64 en chaînes:

type(df.ts1[0])

pandas.tslib.Timestamp

df['t1'] = df.ts1.astype(np.int64)
df['t2'] = df.ts2.astype(np.int64)

fig, ax = plt.subplots(figsize=(10,6))
df.plot(x='t1', y='t2', kind='scatter', ax=ax)
ax.set_xticklabels([datetime.fromtimestamp(ts / 1e9).strftime('%H:%M:%S') for ts in ax.get_xticks()])
ax.set_yticklabels([datetime.fromtimestamp(ts / 1e9).strftime('%H:%M:%S') for ts in ax.get_yticks()])
plt.show()

enter image description here

4
dvmlls

Voici un travail de base pour vous aider à démarrer.

import matplotlib, datetime
import matplotlib.pyplot as plt

def scatter_date(df, x, y, datetimeformat):
  if not isinstance(y, list):
      y = [y]
  for yi in y:
      plt.plot_date(df[x].apply(
          lambda z: matplotlib.dates.date2num(
              datetime.datetime.strptime(z, datetimeformat))), df[yi], label=yi)
  plt.legend()
  plt.xlabel(x)

# Example Usage
scatter_date(data, x='date', y=['col1', 'col2'], datetimeformat='%Y-%m-%d')
2
J Wang

Ce n'est pas joli, mais comme un hack rapide, vous pouvez convertir votre DateTime en un horodatage en utilisant .timestamp() avant de le charger dans Pandas et les dispersions fonctionneront très bien (bien qu'un x complètement inutilisable -axe).

1
Mike N