Hvordan og hvorfor brugte jeg Plotly (i stedet for D3) til at visualisere mine Lollapalooza-data

D3.js er et fantastisk JavaScript-bibliotek, men det har en meget stejl indlæringskurve. Dette gør opgaven med at opbygge en værdifuld visualisering til noget, der kan kræve en stor indsats. Denne ekstra indsats er ok, hvis dit mål er at lave nye og kreative datavisualiseringer, men ofte er det ikke tilfældet.

Ofte kan dit mål bare være at opbygge en interaktiv visualisering med nogle kendte diagrammer . Og hvis du ikke er en front-end ingeniør, kan dette blive lidt vanskeligt.

Som dataforskere er en af ​​vores hovedopgaver databehandling. I dag er det vigtigste værktøj, jeg bruger til det, Pandas (Python). Hvad hvis jeg fortæller dig, at du kan oprette nogle smukke og interaktive diagrammer til internettet lige fra dine Pandas dataframes ? Nå, det kan du! Vi kan bruge Plotly til det.

For ordens skyld er der også Plotly API-biblioteker til Matlab, R og JavaScript, men vi holder os til Python-biblioteket her.

For at være retfærdig er Plotly bygget oven på d3.js (og stack.gl). Hovedforskellen mellem D3 og Plotly er, at Plotly specifikt er et kortbibliotek .

Lad os oprette et søjlediagram for at lære, hvordan Plotly fungerer.

Opbygning af et søjlediagram med plottet

Der er 3 hovedbegreber i Plotlys filosofi:

  • Data
  • Layout
  • Figur

Data

Dataobjektet definerer, hvad vi vil have vist i diagrammet (dvs. dataene). Vi definerer en indsamling af data og specifikationerne for at vise dem som et spor . Et dataobjekt kan have mange spor. Tænk på et linjediagram med to linjer, der repræsenterer to forskellige kategorier: hver linje er et spor.

Layout

Layout-objektet definerer funktioner, der ikke er relateret til data (som titel, titler på aksen osv.). Vi kan også bruge layoutet til at tilføje kommentarer og figurer til diagrammet.

Figur

Figurobjektet opretter det sidste objekt, der skal plottes. Det er et objekt, der indeholder både data og layout.

Plotly visualiseringer er bygget med plotly.js. Dette betyder, at Python API kun er en pakke til at interagere med plotly.js-biblioteket . Den plotly.graph_objsModulet indeholder de funktioner, der vil generere graf objekter for os.

Ok, nu er vi klar til at oprette et søjlediagram:

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)

Bemærk: i denne artikel taler vi ikke om, hvad jeg laver med dataframes. Men hvis du vil have et indlæg om det, så lad mig det vide i kommentarerne?

Okay, så først vil vi vise bjælkerne i en kategori (et sted kaldet "MICROBAR"). Så vi opretter et dataobjekt (en liste) med go.Bar()(et spor), der specificerer dataene for x- og y-akserne. Spor er en ordbog, og data er en liste over ordbøger. Her er trace_microbarindholdet (bemærk typetasten):

{'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}

I Layout-objektet indstiller vi titlen på diagrammet og showlegendeparameteren. Derefter pakker vi data og layout i en figur og kalder for plotly.offline.plot()at få vist diagrammet. Plotly har forskellige muligheder for at vise diagrammerne, men lad os holde os til offlineindstillingen her. Dette åbner et browservindue med vores diagram.

Jeg vil vise alt i et stablet søjlediagram, så vi opretter en dataliste med alle de spor (steder), vi vil have vist, og indstiller barmodeparameteren til at stakke .

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)

Og det er det grundlæggende i Plotly. For at tilpasse vores diagrammer indstiller vi forskellige parametre for spor og layout. Lad os nu gå videre og tale om Lollapalooza-visualiseringen.

Min Lollapalooza oplevelse

Til 2018-udgaven af ​​Lollapalooza Brazil blev alle køb foretaget via et RFID-aktiveret armbånd. De sender dataene til din e-mail-adresse, så jeg besluttede at se på det. Hvad kan vi lære om mig og min erfaring ved at analysere de køb, jeg foretog på festivalen?

Sådan ser dataene ud:

  • Købsdato
  • købetime
  • produkt
  • antal
  • scene
  • sted, hvor jeg købte

Baseret på disse data, lad os besvare nogle spørgsmål.

Hvor gik jeg hen under festivalen?

Dataene fortæller os kun navnet på det sted, hvor jeg købte, og festivalen fandt sted på Autódromo de Interlagos. Jeg tog kortet med etapperne herfra og brugte georeferencer-værktøjet fra georeference.com til at få bredde- og længdegradskoordinaterne til etaperne.

Vi skal vise et kort og markørerne for hvert køb, så vi bruger Mapbox og scattermapboxsporet. Lad os først plotte kun stadierne for at se, hvordan dette fungerer:

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)

Lad os lære et nyt layout parameter: updatemenus. Vi bruger dette til at vise markørerne efter dato. Der er fire mulige opdateringsmetoder:

  • "restyle": rediger data eller dataattributter
  • "relayout": rediger layoutattributter
  • "update": ændre data- og layoutattributter
  • "animate": start eller pause en animation)

For at opdatere markørerne behøver vi kun at ændre dataene, så vi bruger "restyle"metoden. Når du genindstiller, kan du indstille ændringerne for hvert spor eller for alle spor. Her indstiller vi hvert spor til kun at være synligt, når brugeren ændrer rullemenuindstillingen:

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)

Hvordan brugte jeg mine penge?

For at besvare det oprettede jeg et søjlediagram med mine udgifter til mad og drikke hver dag og byggede et varmekort til at vise, hvornår jeg købte ting. Vi har allerede set, hvordan man bygger et søjlediagram, så lad os nu oprette et varmekortdiagram:

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)

Hvilke koncerter så jeg?

Lad os nu gå til den sejeste del: kunne jeg gætte de koncerter, jeg deltog i, kun baseret på mine indkøb?

Ideelt set, når vi ser et show, vi er se showet (og ikke købe ting), så bør indkøbene før eller efter hver koncert. Derefter lavede jeg en liste over hver koncert, der fandt sted en time før, en time efter, og i henhold til det tidspunkt, hvor købet blev foretaget.

For at finde ud af, hvilken af ​​disse shows jeg deltog i, beregnede jeg afstanden fra købsstedet til hvert trin. De shows, jeg deltog i, skulle være dem, der havde den korteste afstand til indrømmelserne.

Som vi vil vise hvert datapunkt, er det bedste valg for en visualisering en tabel. Lad os bygge en:

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)

Tre koncerter manglede, og fire var ukorrekte, hvilket gav os en præcision på 67% og tilbagekaldelse på 72%.

Sætter det hele sammen: bindestreg

Vi har alle kortene, men målet er at sætte dem alle sammen på en side. For at gøre det bruger vi Dash (ved Plotly).

“Dash er en Python-ramme til opbygning af analytiske webapplikationer. Ingen JavaScript krævet. Dash er ideel til opbygning af datavisualiseringsapps med meget brugerdefinerede brugergrænseflader i ren Python. Det er især velegnet til alle, der arbejder med data i Python. ” - Plotlys websted

Dash er skrevet oven på Flask, Plotly.js og React.js. Det fungerer på en meget lignende måde til den måde, vi opretter 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)

Sejt, ikke?

Jeg var vært for den endelige visualisering her, og al koden er her.

Der er nogle alternativer til hosting af visualiseringer: Dash har en offentlig dash-app-hosting, og Plotly leverer også en webservice til hosting af grafer.

Fandt du denne artikel nyttig? Jeg prøver mit bedste for at skrive en dybdykartikel hver måned, du kan modtage en e-mail, når jeg offentliggør en ny.

Jeg havde en ret god oplevelse med Plotly, jeg vil helt sikkert bruge den til mit næste projekt. Hvad er dine tanker om det efter denne oversigt? Og hvilke andre værktøjer bruger du til at oprette visualiseringer til internettet? Del dem i kommentarerne! Og tak for læsningen! ?