Wie und warum ich Plotly (anstelle von D3) verwendet habe, um meine Lollapalooza-Daten zu visualisieren

D3.js ist eine großartige JavaScript-Bibliothek, hat aber eine sehr steile Lernkurve. Dies macht die Aufgabe, eine wertvolle Visualisierung zu erstellen, zu einem Aufwand. Dieser zusätzliche Aufwand ist in Ordnung, wenn Sie neue und kreative Datenvisualisierungen erstellen möchten. Dies ist jedoch häufig nicht der Fall.

Oft besteht Ihr Ziel darin, eine interaktive Visualisierung mit einigen bekannten Diagrammen zu erstellen . Und wenn Sie kein Front-End-Ingenieur sind, kann dies etwas schwierig werden.

Als Datenwissenschaftler ist eine unserer Hauptaufgaben die Datenmanipulation. Heute benutze ich hauptsächlich Pandas (Python). Was ist, wenn ich Ihnen sage, dass Sie einige schöne und interaktive Diagramme für das Web direkt aus Ihren Pandas-Datenrahmen erstellen können ? Nun, du kannst! Dafür können wir Plotly verwenden .

Für die Aufzeichnung gibt es auch Plotly-API-Bibliotheken für Matlab, R und JavaScript, aber wir bleiben hier bei der Python-Bibliothek.

Um fair zu sein, wird Plotly auf d3.js (und stack.gl) aufgebaut. Der Hauptunterschied zwischen D3 und Plotly besteht darin, dass Plotly speziell eine Diagrammbibliothek ist .

Lassen Sie uns ein Balkendiagramm erstellen, um zu erfahren, wie Plotly funktioniert.

Erstellen eines Balkendiagramms mit Plotly

In Plotlys Philosophie gibt es drei Hauptkonzepte:

  • Daten
  • Layout
  • Zahl

Daten

Das Datenobjekt definiert, was im Diagramm angezeigt werden soll (dh die Daten). Wir definieren eine Sammlung von Daten und die Spezifikationen, um sie als Trace anzuzeigen . Ein Datenobjekt kann viele Spuren haben. Stellen Sie sich ein Liniendiagramm mit zwei Linien vor, die zwei verschiedene Kategorien darstellen: Jede Linie ist eine Kurve.

Layout

Das Layout-Objekt definiert Features, die sich nicht auf Daten beziehen (z. B. Titel, Achsentitel usw.). Wir können das Layout auch verwenden, um dem Diagramm Anmerkungen und Formen hinzuzufügen.

Zahl

Das Figure-Objekt erstellt das endgültige zu zeichnende Objekt. Es ist ein Objekt, das sowohl Daten als auch Layout enthält.

Plotly-Visualisierungen werden mit plotly.js erstellt. Dies bedeutet, dass die Python-API nur ein Paket für die Interaktion mit der Bibliothek plotly.js ist . Das plotly.graph_objsModul enthält die Funktionen, die für uns Diagrammobjekte generieren.

Ok, jetzt können wir ein Balkendiagramm erstellen:

import plotly.graph_objs as goimport pandas as pdimport plotly.offline as offline
df = pd.read_csv("data.csv")
df_purchases_by_type = df.pivot_table( index = "place", columns = "date", values = "price", aggfunc = "sum" ).fillna(0)
trace_microbar = go.Bar( x = df_purchases_by_type.columns, y = df_purchases_by_type.loc["MICROBAR"])
data = [trace_microbar]
layout = go.Layout(title = "Purchases by place", showlegend = True)
figure = go.Figure(data = data, layout = layout)
offline.plot(figure)

Hinweis: In diesem Artikel wird nicht darüber gesprochen, was ich mit den Datenrahmen mache. Aber wenn Sie einen Beitrag dazu wünschen, lassen Sie es mich in den Kommentaren wissen?

Okay, also wollen wir zuerst die Balken einer Kategorie anzeigen (ein Ort namens "MICROBAR"). Also erstellen wir ein Datenobjekt (eine Liste) mit go.Bar()(einer Kurve), das die Daten für die x- und y-Achse angibt. Trace ist ein Wörterbuch und Daten sind eine Liste von Wörterbüchern. Hier ist der trace_microbarInhalt (beachten Sie den Typschlüssel):

{'type': 'bar', 'x': Index(['23/03/2018', '24/03/2018', '25/03/2018'], dtype="object", name="date"), 'y': date 23/03/2018 0.0 24/03/2018 0.0 25/03/2018 56.0 Name: MICROBAR, dtype: float64}

Im Layout-Objekt legen wir den Titel des Diagramms und den Parameter showlegend fest. Dann wickeln wir Daten und Layout in eine Abbildung ein und rufen plotly.offline.plot()auf, um das Diagramm anzuzeigen. Plotly hat verschiedene Optionen zum Anzeigen der Diagramme, aber bleiben wir hier bei der Offline-Option. Dies öffnet ein Browserfenster mit unserem Diagramm.

Ich möchte alles in einem gestapelten Balkendiagramm anzeigen, daher erstellen wir eine Datenliste mit allen Spuren (Orten), die wir anzeigen möchten, und setzen den barmodeParameter auf Stapel .

import plotly.graph_objs as goimport pandas as pdimport plotly.offline as offline
df = pd.read_csv("data.csv")
df_purchases_by_place = df.pivot_table(index="place",columns="date",values="price",aggfunc="sum").fillna(0)
data = []
for index,place in df_purchases_by_place.iterrows(): trace = go.Bar( x = df_purchases_by_place.columns, y = place, name=index ) data.append(trace)
layout = go.Layout(, showlegend=True, barmode="stack" )
figure = go.Figure(data=data, layout=layout)
offline.plot(figure)

Und das sind die Grundlagen von Plotly. Um unsere Diagramme anzupassen, legen wir verschiedene Parameter für Traces und das Layout fest. Lassen Sie uns nun über die Lollapalooza-Visualisierung sprechen.

Meine Lollapalooza Erfahrung

Für die Ausgabe 2018 von Lollapalooza Brazil wurden alle Einkäufe über ein RFID-fähiges Armband getätigt. Sie senden die Daten an Ihre E-Mail-Adresse, also habe ich beschlossen, sie mir anzusehen. Was können wir über mich und meine Erfahrungen lernen, indem wir die Einkäufe analysieren, die ich auf dem Festival getätigt habe?

So sehen die Daten aus:

  • Kaufdatum
  • Kaufstunde
  • Produkt
  • Menge
  • Bühne
  • Ort, an dem ich den Kauf getätigt habe

Beantworten wir anhand dieser Daten einige Fragen.

Wohin bin ich während des Festivals gegangen?

Die Daten geben nur den Namen des Ortes an, an dem ich den Kauf getätigt habe, und das Festival fand im Autódromo de Interlagos statt. Ich habe die Karte mit den Etappen von hier genommen und das Georeferencer-Tool von georeference.com verwendet, um die Längen- und Breitengradkoordinaten für die Etappen zu ermitteln.

Wir müssen für jeden Kauf eine Karte und die Markierungen anzeigen, damit wir Mapbox und die scattermapboxAblaufverfolgung verwenden. Zeichnen wir zunächst nur die Stufen, um zu sehen, wie dies funktioniert:

import plotly.graph_objs as goimport plotly.offline as offlineimport pandas as pd
mapbox_token = "" #//www.mapbox.com/help/define-access-token/
df = pd.read_csv("stages.csv")
trace = go.Scattermapbox( lat = df["latitude"], lon = df["longitude"], text=df["stage"], marker=go.Marker(size=10), mode="markers+text", textposition="top" )
data = [trace]
layout = go.Layout( mapbox=dict( accesstoken=mapbox_token, center=dict( lat = -23.701057, lon = -46.6970635 ), zoom=14.5 ) )
figure = go.Figure(data = data, layout = layout)
offline.plot(figure)

Lernen wir einen neuen Layout-Parameter : updatemenus. Wir werden dies verwenden, um die Markierungen nach Datum anzuzeigen. Es gibt vier mögliche Aktualisierungsmethoden:

  • "restyle": Daten oder Datenattribute ändern
  • "relayout": Layoutattribute ändern
  • "update": Daten und Layoutattribute ändern
  • "animate": Animation starten oder anhalten)

Um die Markierungen zu aktualisieren, müssen wir nur die Daten ändern, daher verwenden wir die "restyle"Methode. Beim Restyling können Sie die Änderungen für jede Ablaufverfolgung oder für alle Ablaufverfolgungen festlegen. Hier setzen wir jede Ablaufverfolgung so, dass sie nur sichtbar ist, wenn der Benutzer die Dropdown-Menüoption ändert:

import plotly.graph_objs as goimport plotly.offline as offlineimport pandas as pdimport numpy as np
mapbox_token = ""
df = pd.read_csv("data.csv")
df_markers = df.groupby(["latitude","longitude","date"]).agg(dict(product = lambda x: "%s" % ", ".join(x), hour = lambda x: "%s" % ", ".join(x)))df_markers.reset_index(inplace=True)
data = []update_buttons = []
dates = np.unique(df_markers["date"])
for i,date in enumerate(dates): df_markers_date = df_markers[df_markers["date"] == date] trace = go.Scattermapbox( lat = df_markers_date["latitude"], lon = df_markers_date["longitude"], name = date, text=df_markers_date["product"]+"

"+df_markers_date["hour"], visible=False ) data.append(trace)

 visible_traces = np.full(len(dates), False) visible_traces[i] = True
 button = dict( label=date, method="restyle", args=[dict(visible = visible_traces)] ) update_buttons.append(button)
updatemenus = [dict(active=-1, buttons = update_buttons)]
layout = go.Layout( mapbox=dict( accesstoken=mapbox_token, center=dict( lat = -23.701057, lon = -46.6970635), zoom=14.5), updatemenus=updatemenus )
figure = go.Figure(data = data, layout = layout)
offline.plot(figure)

Wie habe ich mein Geld ausgegeben?

To answer that, I created a bar chart with my spendings for food and beverage by each day and built a heatmap to show when I bought stuff. We already saw how to build a bar chart, so now let’s build a heatmap chart:

import plotly.graph_objs as goimport pandas as pdimport plotly.offline as offline
df = pd.read_csv("data.csv")
df_purchases_by_type = df.pivot_table(index="place",columns="date",values="price",aggfunc="sum").fillna(0)df["hour_int"] = pd.to_datetime(df["hour"], format="%H:%M", errors="coerce").apply(lambda x: int(x.hour))
df_heatmap = df.pivot_table(index="date",values="price",columns="hour", aggfunc="sum").fillna(0)
trace_heatmap = go.Heatmap( x = df_heatmap.columns, y = df_heatmap.index, z = [df_heatmap.iloc[0], df_heatmap.iloc[1], df_heatmap.iloc[2]] )
data = [trace_heatmap]
layout = go.Layout(title="Purchases by place", showlegend=True)
figure = go.Figure(data=data, layout=layout)
offline.plot(figure)

Which concerts did I watch?

Now let’s go to the coolest part: could I guess the concerts I attended based only on my purchases?

Ideally, when we are watching a show, we are watching the show (and not buying stuff), so the purchases should be made before or after each concert. I then made a list of each concert happening one hour before, one hour after, and according to the time the purchase was made.

Um herauszufinden, an welcher dieser Shows ich teilgenommen habe, habe ich die Entfernung vom Ort des Kaufs zu jeder Etappe berechnet. Die Shows, an denen ich teilgenommen habe, sollten diejenigen sein, die den kürzesten Abstand zu den Konzessionen haben.

Da wir jeden Datenpunkt anzeigen möchten, ist eine Tabelle die beste Wahl für eine Visualisierung. Lassen Sie uns eines bauen:

import plotly.graph_objs as goimport plotly.offline as offlineimport pandas as pd
df_table = pd.read_csv("concerts_I_attended.csv")
def colorFont(x): if x == "Yes": return "rgb(0,0,9)" else: return "rgb(178,178,178)"
df_table["color"] = df_table["correct"].apply(lambda x: colorFont(x))
trace_table = go.Table( header=dict( values=["Concert","Date","Correct?"], fill=dict( color=("rgb(82,187,47)")) ), cells=dict( values= [df_table.concert,df_table.date,df_table.correct], font=dict(color=([df_table.color]))) )
data = [trace_table]
figure = go.Figure(data = data)
offline.plot(figure)

Drei Konzerte fehlten und vier waren falsch, was uns eine Genauigkeit von 67% und einen Rückruf von 72% bescherte.

Alles zusammen: Strich

Wir haben alle Diagramme, aber das Ziel ist es, sie alle auf einer Seite zusammenzufassen. Dazu verwenden wir Dash (von Plotly).

„Dash ist ein Python-Framework zum Erstellen analytischer Webanwendungen. Kein JavaScript erforderlich. Dash ist ideal zum Erstellen von Datenvisualisierungs-Apps mit hochgradig benutzerdefinierten Benutzeroberflächen in reinem Python. Es ist besonders für alle geeignet, die mit Daten in Python arbeiten. “ - Plotlys Seite

Dash is written on top of Flask, Plotly.js, and React.js. It works in a very similar way to the way we create Plotly charts:

import dashimport dash_core_components as dccimport dash_html_components as htmlimport plotly.graph_objs as goimport pandas as pd app = dash.Dash()
df_table = pd.read_csv("concerts_I_attended.csv").dropna(subset=["concert"])def colorFont(x): if x == "Yes": return "rgb(0,0,9)" else: return "rgb(178,178,178)"
df_table["color"] = df_table["correct"].apply(lambda x: colorFont(x))
trace_table = go.Table(header=dict(values=["Concert","Date","Correct?"],fill=dict(color=("rgb(82,187,47)"))),cells=dict(values=[df_table.concert,df_table.date,df_table.correct],font=dict(color=([df_table.color]))))
data_table = [trace_table]
app.layout = html.Div(children=[ html.Div( [ dcc.Markdown( """ ## My experience at Lollapalooza Brazil 2018 *** """.replace(' ', ''), className="eight columns offset-by-two" ) ], className="row", style=dict(textAlign="center",marginBottom="15px") ),
html.Div([ html.Div([ html.H5('Which concerts did I attend?', style=dict(textAlign="center")), html.Div('People usually buy things before or after a concert, so I took the list of concerts, got the distances from the location of the purchases to the stages and tried to guess which concerts did I attend. 8 concerts were correct and 3 were missing from a total of 12 concerts.', style=dict(textAlign="center")), dcc.Graph(id='table', figure=go.Figure(data=data_table,layout=go.Layout(margin=dict(t=30)))), ], className="twelve columns"), ], className="row")])
app.css.append_css({ 'external_url': '//codepen.io/chriddyp/pen/bWLwgP.css'})
if __name__ == '__main__': app.run_server(debug=True)

Cool right?

I hosted the final visualization here and the all the code is here.

There are some alternatives to hosting the visualizations: Dash has a public dash app hosting and Plotly also provides a web-service for hosting graphs.

Did you found this article helpful? I try my best to write a deep dive article each month, you can receive an email when I publish a new one.

I had a pretty good experience with Plotly, I’ll definitely use it for my next project. What are your thoughts about it after this overview? And what other tools do you use to build visualizations for the web? Share them in the comments! And thank you for reading! ?