دیتا ویژوالیزیشن اینتراکتیو روی نقشه به کمک plotly (بخش۲)

همونطور که در بخش اول خوندید ما تونستیم به کمک کتابخونه های plotly و mapbox نقشه اولیه رو بکشیم ولی هدف اصلی از انتخاب plotly این بود که بتونیم ویژوالیزیشن های انتراکتیو تر و متفاوت تر با بقیه ی کتابخونه ها و ابزار ها داشته باشیم , حالا ما در این بخش یک اسلایدر هم به نقشه اضافه می کنیم که البته فرایند اضافه کردنش به طوری هست که اگر این مدل رو یاد بفهمیم بقیه اونا هم مثل دکمه و دراپ باکس ها هم همینطور کار می کنن( البته این رو یادآور بشم که در واقع توی داکیومنت اصلی و مثال هایی که در مورد اسلایدر هست این موارد که من اینجا می نویسم نبودش و من سر این مورد که الان شاید ساده به نظر میرسه 1 هفته معطل بودم:)))) )

برای اینکه هممون کد اولیه درست رو داشته باشیم و اون رو تغییر بدیم می تونید کد بخش (static visualization) رو از گیتهاب دانلود کنید و بقیه تغییر ها رو با توجه به این آموزش بدین یا اینکه اگر کد کامل این بخش و دیتا های مورد استفاده من در این اموزش رو خواستید از بخش (interactive visualization) دانلود کنید.

یه نکته هم بگم قبل از شروع اینکه توی این متن بیشتر جاهای کد همون قبلی ها هستن و من بخش هایی از اون رو تغییر یا اضافه کردم و برای جلوگیری از طولانی شدن مطلب من اون هارو دیگه اینجا نمیارم

دیتا

خب دیتای این بخش دیتای بزرگتری هست از همون دیتایی که گفتم من دانلود و تمیزش کردم که بالا گفتم می تونید دانلودش کنید. ابتدا دیتای مورد نظر رو لود می کنیم و چون می خوایم از ستون های مختلفش استفاده کنیم اسم های ستون هارو میریزیم توی یه لیست تا بعدا استفاده کنیم

df = pd.read_csv("YOUR DATA PATH", index_col=0)
columns = df.columns.tolist() 

منطق کاری که از اینجا به بعد میکنیم این که با توجه به اینکه data ,layer ما با توجه به هر ستون دیتا تغییر می کنن پس باید با هم هماهنگ باشند که در ادامه می گم که این بخش چطور توی قسمت اسلایدر به کمک steps هندل میشه فعلا در ادامه ما لیست data هایی که می خوایم رو تولید میکنیم سپس با توجه به هر data layer اون رو تولید می کنیم و این دوتا میریزیم توی یه لیست که بعدا به اون ها نیاز داریم(data هایی که در ادامه استفاده می کنم منظور متغییر های به این اسم هستند

NEW DATA

خب یه حلقه میزاریم و بخش هایی که با توجه به دیتا تغییر می کنند رو میزاریم توش و data های تولید شده رو میریزیم توی یه لیست

data_slider = []
for age in columns[:3]:
        age_data = df[age]
        age_data.name = 'province'
        df_tmp = age_data.copy()
        df_tmp.index = df_tmp.index.map(match_dict)
        df_tmp = df_tmp[~df_tmp.index.duplicated(keep=False)]
        df_reindexed = df_tmp.reindex(index = provinces_names)
       
         colormap = 'Blues'
        cmin = df_reindexed.min()
         cmax = df_reindexed.max()
         sm = scalarmappable(colormap, cmin, cmax)
         scatter_colors = get_scatter_colors(sm, df_reindexed)
         colorscale = get_colorscale(sm, df_reindexed, cmin, cmax)
         hover_text = get_hover_text(df_reindexed)
         tickformat = ""
         data = dict(type='scattermapbox',
                             lat=lats,
                             lon=lons,
                             mode='markers',
                             text=hover_text,
                             marker=dict(size=1,
                                                 color=scatter_colors,
                                                 showscale = True,
                                                 cmin = df_reindexed.min(),
                                                 cmax = df_reindexed.max(),
                                                 colorscale = colorscale,
                                                 colorbar = dict(tickformat = tickformat)),
                               showlegend=False,
                               hoverinfo='text')
             data_slider.append(data)

توی این مرحله تابع get_data_layout رو تعریف میکنیم که توش یه لیست از دیتا هارو میگیره و با توجه به scatter_colors هر کدوم layer های مناسب رو برامون میسازه میریزه تو لیست (اگر یادتون باشه از بخش قبل گفتیم که scatter_colors توسط یه تابع به توجه به دیتای ما یه رنگی رو مناسب با اون دیتا درست می کنه)

def get_data_layout(df):
    layers = []
    for i in range(len(data_slider)):
            scatter_colors = df[i]['marker']['color']
            layer=([dict(sourcetype = 'geojson',
                                  source =sources[k],
                                  below="",
                                  type = 'line',
                                  line = dict(width = 1),
                                  color = 'black',
                                  ) for k in range(n_provinces)
             ] +
                        [dict(sourcetype = 'geojson',
                                 source =sources[k],
                                 below="water",
                                 type = 'fill',
                                 color = scatter_colors[k],
                                  opacity=0.8,
                                  ) for k in range(n_provinces)])
              layers.append(layer)
      return layers

خب میرسیم به بخش حساس و تیریکی قضیه, اول یه موضوعی رو توضیح بدم ببینید در واقع مرکز و هسته ی plotly که ما به پایتون داریم الان کد میزنیم javascript هست حالا چطور توضیح میدم

شاید براتون سوال باشه چرا زمانی که ما برنامه رو اجرا میکنیم یک فایل html تولید میشه و همینطور نمودار ها توی browser باز میشه . قضیه اینجاست که plotly به خاطر اینکه بتونه نمودار های بهتر و قابل استفاده بیشتر تولید کنه تمام کد هایی که به هر زبونی بهش میدیم رو اون به صورت html,css, js در میاره و اونارو نمایش میده به همین خاطر هم خیلی قدرتمند هست و باید توی بعضی از بخش ها برای اینکه موضوع رو بهتر بفهمید باید برید اصل قضیه رو بخونید تا متوجه بشید.

Slider

اگر داکیومنت slider رو بخونید میبینید که پارامتر های زیادی میگیره که اصلی ترینشون steps هست که در مرحله و گام با توجه به method وargs که داره data و layout رو تغییر میده

methods : restyle, relayout, update, skip

زمانی که method restyle باشه در هر مرحله پارامتری که ما ار طریق args براش میفرستیم رو توی data تغییر میده که در حالت default ما پارامتر visible رو میفرستیم تا با اون بگیم که در هر مرحله کدوم data رو نشون بده

زمانی که method relayout هست دقیقا مثله restyle عمل میکنه با این تفاوت که پارامتری که میفرستیم رو با پارامتر های layout جابجا میکنه

حالا زمانی که مثله الان method update هست ما می خوایم هم data رو تغییر بدیم هم layout . که دوتا دیکشنری رو به عنوان پارامتر میفرستیم اولی شامل پارامتری هست که مربوط به data هست(visible) و دومی هم پارامتر مورد نظر layout رو تغییر میده (mapbox.layer) اینطوری توی هر گام اون بخش ها تغییر میکنن

visibility = []
for i in range(len(data_slider)):
        list = [False] * len(data_slider)
        list[i] = True
        visibility.append(list)
steps = []
for i in range(len(data_slider)):
        step = dict(method='update',
                            args=[{'visible': visibility[i]},
                            {'mapbox.layers': layers[i]}],
                    label='Age {}' .format(i),)
        steps.append(step)
        
sliders = [dict(steps=steps)]

بخش layout هم مثله قبل می مونه فقط توی بخش mapbox باید layer رو پاک کنید.

کد کامل توی بخش (interactive visualization) هست . امیدوارم کامل و واضح توضیح داده باشم و کمکی کرده باشم شما مثله من توی این بخش از این کار نمونید ممنون که تا انتها خوندید:)))