web-dev-qa-db-de.com

Seaborn Tsplot zeigt die Datumszeiten auf der x-Achse nicht gut

Nachfolgend habe ich das folgende Skript, das eine einfache Zeitreihendarstellung erstellt:

%matplotlib inline
import datetime
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

fig, ax = plt.subplots()

df = []
start_date = datetime.datetime(2015, 7, 1)
for i in range(10):
    for j in [1,2]:
        unit = 'Ones' if j == 1 else 'Twos'
        date = start_date + datetime.timedelta(days=i)

        df.append({
                'Date': date.strftime('%Y%m%d'),
                'Value': i * j,
                'Unit': unit
            })

df = pd.DataFrame(df)

sns.tsplot(df, time='Date', value='Value', unit='Unit', ax=ax)
fig.autofmt_xdate()

Und das Ergebnis davon ist folgendes:

enter image description here

Wie Sie sehen, hat die x-Achse merkwürdige Zahlen für die Datumszeit und nicht die üblichen "Nice" -Darstellungen, die mit matplotlib und anderen Plot-Dienstprogrammen geliefert werden. Ich habe viele Dinge ausprobiert, die Daten neu formatiert, aber sie kommen nie sauber heraus. Wer kennt sich aus?

12
sedavidw

Matplotlib stellt Datumsangaben als Gleitkommazahlen dar (in Tagen). Wenn Sie (oder Pandas oder Seaborns) nicht sagen, dass Ihre Werte Datumsangaben darstellen, werden die Ticks nicht als Datumsangaben formatiert. Ich bin kein Seaborn-Experte, aber es sieht so aus, als würde er (oder Pandas) die datetime-Objekte in matplotlib-Datumsangaben konvertieren, ordnet dann aber den Achsen keine richtigen Locators und Formatierer zu. Deshalb erhalten Sie diese seltsamen Zahlen, die eigentlich nur die Tage seit 0001.01.01 sind. Sie müssen sich also manuell um die Ticks kümmern (was in den meisten Fällen besser ist, da Sie mehr Kontrolle haben).

Sie müssen also einen date locator zuweisen, der entscheidet, wohin Ticks gesetzt werden sollen, und ein date formatatter , das dann die Zeichenfolgen für die Tick-Labels formatiert.

import datetime
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

# build up the data
df = []
start_date = datetime.datetime(2015, 7, 1)
for i in range(10):
    for j in [1,2]:
        unit = 'Ones' if j == 1 else 'Twos'
        date = start_date + datetime.timedelta(days=i)

        # I believe it makes more sense to directly convert the datetime to a
        # "matplotlib"-date (float), instead of creating strings and then let
        # pandas parse the string again
        df.append({
                'Date': mdates.date2num(date),
                'Value': i * j,
                'Unit': unit
            })
df = pd.DataFrame(df)

# build the figure
fig, ax = plt.subplots()
sns.tsplot(df, time='Date', value='Value', unit='Unit', ax=ax)

# assign locator and formatter for the xaxis ticks.
ax.xaxis.set_major_locator(mdates.AutoDateLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y.%m.%d'))

# put the labels at 45deg since they tend to be too long
fig.autofmt_xdate()
plt.show()

Ergebnis:

enter image description here

13
hitzg

Für mich führt die Antwort von @ hitzg in den Tiefen von DateFormatter zu "OverflowError: Vorzeichenlose Ganzzahl ist größer als das Maximum".

Wenn ich meinen Datenrahmen betrachte, sind meine Indizes datetime64 und nicht datetime. Pandas konvertieren diese jedoch gut. Folgendes funktioniert für mich großartig:

import matplotlib as mpl

def myFormatter(x, pos):
    return pd.to_datetime(x)

[ . . . ]

ax.xaxis.set_major_formatter(mpl.ticker.FuncFormatter(myFormatter))
11
T Smith

Hier ist eine potenziell inelegante Lösung, aber es ist die einzige, die ich habe ... Hoffe, es hilft!

    g = sns.pointplot(x, y, data=df, ci=False);

    unique_dates = sorted(list(df['Date'].drop_duplicates()))
    date_ticks = range(0, len(unique_dates), 5)

    g.set_xticks(date_ticks);
    g.set_xticklabels([unique_dates[i].strftime('%d %b') for i in date_ticks], rotation='vertical');
    g.set_xlabel('Date');

Lassen Sie mich wissen, wenn Sie Probleme sehen!

0
ltjds
def myFormatter(x, pos):
       return pd.to_datetime(x).strftime('%Y%m%d')
ax.xaxis.set_major_formatter(mpl.ticker.FuncFormatter(myFormatter))
0
peter254