كيف ولماذا استخدمت Plotly (بدلاً من D3) لتصور بيانات Lollapalooza الخاصة بي

D3.js هي مكتبة JavaScript رائعة ، لكنها تحتوي على منحنى تعليمي شديد الانحدار. هذا يجعل مهمة بناء تصور قيمة أمرًا يمكن أن يتطلب الكثير من الجهد. هذا الجهد الإضافي لا بأس به إذا كان هدفك هو عمل تصورات جديدة ومبتكرة للبيانات ، ولكن في كثير من الأحيان ليس هذا هو الحال.

في كثير من الأحيان ، قد يكون هدفك هو بناء تصور تفاعلي مع بعض الرسوم البيانية المعروفة . وإذا لم تكن مهندس الواجهة الأمامية ، فقد يصبح هذا الأمر معقدًا بعض الشيء.

بصفتنا علماء بيانات ، فإن إحدى مهامنا الرئيسية هي معالجة البيانات. اليوم الأداة الرئيسية التي أستخدمها لذلك هي Pandas (Python). ماذا لو أخبرتك أنه يمكنك إنشاء بعض المخططات الجميلة والتفاعلية للويب مباشرة من إطارات بيانات Pandas الخاصة بك ؟ حسنًا ، يمكنك ذلك! يمكننا استخدام Plotly لذلك.

للتسجيل ، توجد أيضًا مكتبات Plotly API لـ Matlab و R و JavaScript ، لكننا سنلتزم بمكتبة Python هنا.

لكي نكون منصفين ، تم إنشاء Plotly أعلى d3.js (و stack.gl). الفرق الرئيسي بين D3 و Plotly هو أن Plotly هي على وجه التحديد مكتبة رسوم بيانية .

لنقم ببناء مخطط شريطي للتعرف على كيفية عمل Plotly.

بناء مخطط شريطي بالرسم

هناك 3 مفاهيم رئيسية في فلسفة بلوتلي:

  • البيانات
  • نسق
  • الشكل

البيانات

يحدد كائن البيانات ما نريد عرضه في المخطط (أي البيانات). نحدد مجموعة من البيانات والمواصفات لعرضها كتتبع . يمكن أن يكون لكائن البيانات آثار كثيرة. فكر في مخطط خطي يتكون من سطرين يمثلان فئتين مختلفتين: كل سطر هو أثر.

نسق

يحدد كائن التخطيط الميزات التي لا تتعلق بالبيانات (مثل العنوان وعناوين المحاور وما إلى ذلك). يمكننا أيضًا استخدام التخطيط لإضافة التعليقات التوضيحية والأشكال إلى المخطط.

الشكل

ينشئ كائن الشكل الكائن النهائي المراد رسمه. إنه كائن يحتوي على كل من البيانات والتخطيط.

تصورات المؤامرة مبنية باستخدام plotly.js. هذا يعني أن Python API هي مجرد حزمة للتفاعل مع مكتبة plotly.js . و plotly.graph_objsحدة تحتوي على وظائف من شأنها أن تولد كائنات الرسم البياني بالنسبة لنا.

حسنًا ، نحن الآن جاهزون لإنشاء مخطط شريطي:

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)

ملاحظة: في هذه المقالة لن نتحدث عما أفعله مع أطر البيانات. ولكن إذا كنت ترغب في مشاركة حول ذلك ، فأخبرني في التعليقات؟

حسنًا ، نريد أولاً إظهار أشرطة فئة واحدة (مكان يسمى "MICROBAR"). لذلك نقوم بإنشاء كائن بيانات (قائمة) مع go.Bar()(تتبع) لتحديد البيانات الخاصة بالمحور x و y. التتبع هو قاموس والبيانات عبارة عن قائمة من القواميس. ها هي trace_microbarالمحتويات (لاحظ مفتاح النوع):

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

في كائن Layout ، قمنا بتعيين عنوان المخطط والمعلمة showlegend. ثم نلف البيانات والتخطيط في شكل وندعو plotly.offline.plot()لعرض المخطط. يحتوي Plotly على خيارات مختلفة لعرض المخططات ، لكن دعنا نتمسك بخيار وضع عدم الاتصال هنا. سيؤدي هذا إلى فتح نافذة متصفح مع مخططنا.

أريد عرض كل شيء في مخطط شريطي مكدس ، لذلك سننشئ قائمة بيانات تحتوي على جميع الآثار (الأماكن) التي نريد عرضها وتعيين barmodeالمعلمة لتكديسها .

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)

وهذه هي أساسيات Plotly. لتخصيص مخططاتنا ، قمنا بتعيين معلمات مختلفة للتتبعات والتخطيط. الآن دعنا نمضي قدمًا ونتحدث عن تصور Lollapalooza.

تجربتي في Lollapalooza

بالنسبة لإصدار 2018 من Lollapalooza Brazil ، تم إجراء جميع عمليات الشراء من خلال سوار معصم مزود بتقنية RFID. يرسلون البيانات إلى عنوان بريدك الإلكتروني ، لذلك قررت أن ألقي نظرة عليها. ما الذي يمكن أن نتعلمه عني وعن تجربتي من خلال تحليل المشتريات التي قمت بها في المهرجان؟

هكذا تبدو البيانات:

  • تاريخ الشراء
  • ساعة الشراء
  • المنتج
  • كمية
  • المسرح
  • المكان الذي قمت فيه بالشراء

بناءً على هذه البيانات ، دعنا نجيب على بعض الأسئلة.

أين ذهبت خلال المهرجان؟

تخبرنا البيانات فقط باسم الموقع الذي أجريت فيه عملية الشراء ، وأقيم المهرجان في Autódromo de Interlagos. أخذت الخريطة بالمراحل من هنا واستخدمت أداة georeferencer من georeference.com للحصول على إحداثيات خطوط الطول والعرض للمراحل.

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.

لمعرفة أي من هذه العروض حضرت ، قمت بحساب المسافة من موقع الشراء إلى كل مرحلة. يجب أن تكون العروض التي حضرتها هي ذات أقصر مسافة من الامتيازات.

نظرًا لأننا نريد إظهار كل نقطة بيانات ، فإن أفضل خيار للتمثيل المرئي هو الجدول. لنبني واحدًا:

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)

كانت ثلاث حفلات مفقودة وأربع كانت غير صحيحة ، مما أعطانا دقة 67٪ واسترجاع 72٪.

ضع كل ذلك معًا: اندفاعة

لدينا جميع المخططات ، ولكن الهدف هو تجميعها جميعًا على صفحة واحدة. للقيام بذلك سوف نستخدم داش (بواسطة Plotly).

"Dash هو إطار عمل Python لبناء تطبيقات الويب التحليلية. لا حاجة لجافا سكريبت. تعتبر Dash مثالية لإنشاء تطبيقات تصور البيانات باستخدام واجهات مستخدم مخصصة للغاية في لغة Python الخالصة. إنها مناسبة بشكل خاص لأي شخص يعمل مع البيانات في Python ". - موقع Plotly

Dash مكتوبة أعلى Flask و Plotly.js و React.js. إنه يعمل بطريقة مشابهة جدًا للطريقة التي ننشئ بها مخططات Plotly:

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)

رائع ، أليس كذلك؟

لقد استضفت التصور النهائي هنا وكل الشفرة هنا.

هناك بعض البدائل لاستضافة التصورات: لدى Dash تطبيق داش عام مضيف كما يوفر Plotly خدمة ويب لاستضافة الرسوم البيانية.

هل وجدت هذه المقالة مفيدة؟ أبذل قصارى جهدي لكتابة مقال عميق كل شهر ، يمكنك تلقي بريد إلكتروني عندما أنشر مقالة جديدة.

كانت لدي تجربة جيدة مع Plotly ، سأستخدمها بالتأكيد لمشروعي التالي. ما هي أفكارك حول هذا الموضوع بعد هذه النظرة العامة؟ وما هي الأدوات الأخرى التي تستخدمها لإنشاء تصورات للويب؟ مشاركتها في التعليقات! وأشكركم على القراءة! ؟