Hogyan és miért használtam a Plotly-t (a D3 helyett) a Lollapalooza-adatok vizualizálásához

A D3.js egy fantasztikus JavaScript könyvtár, de nagyon meredek a tanulási görbe. Ez egy értékes látványterv elkészítésének feladatává teszi azt, ami sok erőfeszítést igényel. Ez a további erőfeszítés rendben van, ha új és kreatív adatmegjelenítésekre törekszik a célja, de gyakran ez nem így van.

Gyakran előfordulhat, hogy a cél csak egy interaktív látványterv elkészítése néhány jól ismert táblázattal . És ha nem vagy front-end mérnök, ez kissé trükkössé válhat.

Adattudósként az egyik fő feladatunk az adatkezelés. Ma a fő eszköz, amelyet ehhez használok, a Pandas (Python). Mi van, ha azt mondom, hogy akkor lehet építeni néhány szép és interaktív grafikonok az interneten közvetlenül a Panda dataframes ? Nos, lehet! A Plotly- t arra használhatjuk.

A nyilvántartáshoz a Plotly API könyvtárak vannak a Matlab, R és JavaScript számára is, de itt maradunk a Python könyvtárnál.

Igazság szerint a Plotly a d3.js (és a stack.gl) tetejére épül. A fő különbség a D3 és a Plotly között az, hogy a Plotly kifejezetten diagramkészítő könyvtár .

Készítsünk oszlopdiagramot, hogy megismerjük a Plotly működését.

Sávdiagram elkészítése plotly-val

A Plotly filozófiájában 3 fő fogalom található:

  • Adat
  • Elrendezés
  • Ábra

Adat

Az Data objektum meghatározza, hogy mit szeretnénk megjeleníteni a diagramban (vagyis az adatokat). Meghatározzuk az adatok gyűjteményét és a specifikációkat nyomkövetésként történő megjelenítéshez . Egy Data objektumnak sok nyoma lehet. Gondoljon egy vonaldiagramra, amelynek két vonala két különböző kategóriát képvisel: mindegyik vonal nyom.

Elrendezés

Az Elrendezés objektum olyan tulajdonságokat határoz meg, amelyek nem kapcsolódnak az adatokhoz (például cím, tengelycímek stb.). Az Elrendezés segítségével feljegyzéseket és alakzatokat is hozzáadhatunk a diagramhoz.

Ábra

Az ábra objektum létrehozza az ábrázolni kívánt utolsó objektumot. Ez egy objektum, amely adatokat és elrendezést is tartalmaz.

A teljeskörű vizualizációk a plotly.js fájl segítségével épülnek fel. Ez azt jelenti, hogy a Python API csak egy csomag, amely interakcióba lép a plotly.js könyvtárral . A plotly.graph_objsmodul azokat a függvényeket tartalmazza, amelyek grafikonobjektumokat generálnak számunkra.

Ok, most készen állunk a sávdiagram felépítésére:

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)

Megjegyzés: ebben a cikkben nem beszélünk arról, hogy mit csinálok az adatkeretekkel. De ha szeretne erről szóló bejegyzést, tudassa velem a megjegyzéseket?

Rendben, tehát először egy kategória (az úgynevezett hely "MICROBAR") oszlopait szeretnénk megmutatni . Tehát létrehozunk egy adatobjektumot (egy listát) go.Bar()(nyomkövetéssel), amely meghatározza az x és y tengely adatait. A Trace egy szótár, az adatok pedig a szótárak listája. Itt van a trace_microbartartalom (vegye figyelembe a típuskulcsot):

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

Az Elrendezés objektumban megadjuk a diagram címét és a showlegend paramétert. Ezután az Adatokat és az Elrendezést ábrázoljuk és felhívjuk plotly.offline.plot()a diagram megjelenítését. A Plotly-nak különböző lehetőségei vannak a diagramok megjelenítésére, de itt maradjunk az offline opció mellett. Ez megnyitja a böngészőablakot a diagramunkkal.

Mindent halmozott oszlopdiagramon szeretnék megjeleníteni, ezért létrehozunk egy adatlistát az összes megjeleníteni kívánt nyomról (helyről), és beállítjuk a barmodeparamétert egymásra .

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)

És ez a Plotly alapjai. Diagramjaink testreszabásához különböző paramétereket állítunk be a nyomokra és az elrendezésre. Most folytassuk és beszéljünk a Lollapalooza vizualizációról.

Lollapalooza-élményem

A Brazil Lollapalooza 2018-as kiadásának minden vásárlása RFID-kompatibilis karszalagon keresztül történt. Az Ön e-mail címére küldik az adatokat, ezért úgy döntöttem, hogy megnézem. Mit tanulhatunk rólam és a tapasztalataimról a fesztiválon vásárolt elemzések elemzésével?

Így néznek ki az adatok:

  • Vásárlás időpontja
  • vásárlási óra
  • termék
  • Mennyiség
  • színpad
  • ahol vásároltam

Ezen adatok alapján válaszoljunk néhány kérdésre.

Hová mentem a fesztivál alatt?

Az adatok csak azt a helyet nevezik meg nekünk, ahol vásároltam, és a fesztiválra az Autódromo de Interlagos-ban került sor. Innen vettem a térképet a szakaszokkal, és a georeference.com georeferencer eszközével megkaptam a szakaszok szélességi és hosszúsági koordinátáit.

We need to display a map and the markers for each purchase, so we will use Mapbox and the scattermapbox trace. First let’s plot only the stages to see how this works:

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)

Let’s learn a new Layout parameter: updatemenus. We will use this to display the markers by date. There are four possible update methods:

  • "restyle": modify data or data attributes
  • "relayout": modify layout attributes
  • "update": modify data and layout attributes
  • "animate": start or pause an animation)

To update the markers, we only need to modify the data, so we will use the "restyle" method. When restyling you can set the changes for each trace or for all traces. Here we set each trace to be visible only when the user changes the dropdown menu option:

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)

How did I spend my money?

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.

Hogy megtudjam, melyik műsoron vettem részt, kiszámoltam az egyes szakaszok távolságát a vásárlás helyétől. Azoknak a műsoroknak, amelyeken részt vettem, a legrövidebb távolságra kell lenniük az engedményektől.

Mivel minden egyes adatpontot meg akarunk mutatni, a vizualizáció legjobb választása egy táblázat. Építsünk egyet:

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)

Három koncert hiányzott és négy hibás volt, ez 67% -os pontosságot és 72% -os visszahívást eredményezett.

Az egészet összerakva: kötőjel

Minden diagram megtalálható nálunk, de a cél az, hogy mindet egy oldalra állítsuk. Ehhez a Dash-t fogjuk használni (Plotly által).

„A Dash egy Python keretrendszer analitikus webalkalmazások felépítésére. Nincs szükség JavaScript-re. A Dash ideális adat-vizualizációs alkalmazások készítéséhez rendkívül egyedi felhasználói felülettel a tiszta Pythonban. Különösen alkalmas mindenki számára, aki Python-ban dolgozik. " - Plotly helyszíne

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! ?