امروزه با گسترش اپلیکیشنهایی که اطلاعات مکانی کاربران را ذخیره میکنند، بسیاری از کسبوکارها به دادههای مکانی مشتریان نیز دسترسی پیدا کردند. به نمایش درآوردن دادههای مکانی، میتواند گام اول در بهرهگیری از این دادهها باشد. خوشبختانه امکانات خوبی در R و پایتون برای نمایش دادههای مکانی وجود دارد. در R کتابخانه Leaflet و در پایتون کتابخانه Folium امکانات بسیار زیادی برای نمایش دادهها فراهم میکنند.
در این مقاله، من از یک مثال ساده در حوزه لجستیک استفاده میکنم تا ابزارهای کاربردی کتابخانه Folium را در پایتون معرفی کنم. در این مثال، فرض بر این است که یک مرکز توزیع وجود دارد که سفارشهای روزانه ناحیه اطراف آن را باید به مشتریان برساند.
دادههای مربوط به این مثال در فایل data.csv آمده است. در کد زیر من این فایل را با استفاده از تابع read_csv از کتابخانه Pandas فراخوانی و محتویات آن را در دیتا فریم data ذخیره کردم.
1 2 3 4 5 | #Required library import pandas as pd #Read data from file data = pd.read_csv('data.csv') |
همانطور که از شکل-۱ پیداست، این دیتا فریم شامل ۸۱ ردیف و ۳ ستون است. ردیف آخر حاوی اطلاعات طول (Longitude) و عرض (Latitude) جغرافیایی مرکز توزیع است. بقیه ۸۰ ردیف، شامل طول و عرض جغرافیایی محل مشتریان به همراه شناسه یکتای سفارش است.
کتابخانه Folium پایتون برای خلق نقشههای تعاملی
کتابخانه Folium، کتابخانه قدرتمندی در پایتون است که امکان ایجاد نقشههای تعاملی را فراهم میکند. یکی از مزیتهای مهم کتابخانه Folium این است که نقشهها بهصورت فایلهای جداگانه HTML ایجاد میشوند که میتوان از آن برای ساخت داشبورد و سایر محصولات دادهمحور (Data Product) بهره گرفت.
من در این مقاله، گامبهگام مراحل ساخت یک نقشه تعاملی را با استفاده از این کتابخانه توضیح میدهم و هر مرحله، قسمت قبلی خود را تکمیل میکند تا به نقشه نهایی برسیم.
بخش اول: ایجاد نقشه
با فرض آنکه کتابخانه Folium را نصب کرده باشید، میتوانید آن را با دستور import فراخوانی کنید. در کد زیر برای ایجاد یک نمونه (Instance) از کلاس نقشه از Map استفاده کردم و آن را map_1 نامیدم. آرگومان اول Map مشخص میکند نقطه تمرکز نقشه حول کدام نقطه روی کره زمین است. برای این منظور مختصات عرض و طول جغرافیایی را در قالب لیست پایتون دادم. این نقطه را جایی در مرکز شهر تهران انتخاب کردم. آرگومان zoom_start مشخص میکند تا چه حد حول آن نقطه زوم شود. من این عدد را ۱۱ قرار دادم چون با این تنظیم تقریباً نقشه شهر تهران بهخوبی مشخص است. آرگومان control_scale تعیین میکند آیا روی نقشه مقیاس نشان داده شود یا خیر (به گوشه پایین سمت چپ نقشه نگاه کنید).
1 2 3 4 5 6 7 | #Create a map instance map_1 = folium.Map(location = [35.6892, 51.3890], zoom_start = 11, control_scale = True) #Show map map_1 |
اگر map_1 را فراخوانی کنید منجر به نمایش نقشه زیر میشود.
توجه کنید شما میتوانید با نقشه زیر تعامل کنید. گرچه در این مرحله تنها میتوانید روی بخش دلخواهی از نقشه زوم کنید (به علامت + و – گوشه بالا سمت چپ توجه کنید) و یا با کلیک چپ موشواره روی نقشه بگردید.
کتابخانه Folium بهطور پیشفرض از طریق API از نقشه Open Street Map بهره میگیرد. Open Street Map یک پروژه مشارکتی آزاد باهدف ایجاد نقشههای بهروز و دقیق از دنیا است که امکان دسترسی به دادههای آن بدون محدودیت وجود دارد. این پروژه نمونه موفقی از پروژههای دادههای باز (Open Data) است.
بخش دوم: مشخص کردن یک مکان جغرافیایی روی نقشه با Marker
در این گام، ابتدا مرحله اول را تکرار کردم با این تفاوت که نقشه را map_2 نامیدم. در لایه بعد، مرکز توزیع را که مختصات آن در ردیف آخر دیتا فریم data ذخیره شده، با استفاده از Marker روی نقشه انداختم. آرگومان اول Marker، مختصات عرض و طول جغرافیایی نقطهای است که میخواهیم نشان دهیم. آرگومان tooltip عنوانی است که به این مکان جغرافیایی دادم و اگر نشانگر موشواره را حوالی آن نقطه حرکت دهید، پدیدار میشود. آرگومان icon تنظیمات مربوط به نحوه نمایش آیکون است که بسته به سلیقه میتوان تغییر داد. تابع add_to این شیء را به map_2، اضافه میکند.
1 2 3 4 5 6 7 8 9 10 11 12 | #Create a map instance map_2 = folium.Map(location = [data.iloc[80, 0], data.iloc[80, 1]], zoom_start = 13, control_scale = True) #Add marker folium.Marker(location = [data.iloc[80, 0], data.iloc[80, 1]], tooltip = 'Distribution Center', icon = folium.Icon(color = 'green', icon = 'ok-sign')).add_to(map_2) #Show map map_2 |
بخش سوم: مشخص کردن چندین مکان جغرافیایی روی نقشه با Circle
در این گام، میخواهم در لایه بعد مختصات مکانی مقصد سفارشها را روی نقشه اضافه کنم . بنابراین مراحل قبلی را روی نقشه map_3 جلو رفتم.
برای نمایش مقصد سفارشها میتوانستم از Marker استفاده کنم که از دید من به لحاظ بصری جذاب نیست. من برای نمایش مقصد سفارشها از CircleMarker استفاده کردم که نقاط را با دایره نشان میدهد. تفاوت دیگر در اینجا است که من با این روش بهجای یک نقطه میخواهم ۸۰ نقطه را روی نقشه نشان دهم. به همین دلیل از حلقه for در پایتون استفاده کردم. در هر بار اجرای حلقه یک ردیف از دیتا فریم data را خواندم و مختصات خواندهشده را در آرگومان location قرار دادم. با آرگومان radius بزرگی و کوچکی دایرهها را تنظیم کردم. مشابه قبل آرگومان tooltip عنوانی است که به این مکان جغرافیایی دادم. عنوان هر محل را بر اساس شناسه سفارش تعیین کردم. رنگ نقاط را هم قرمز گذاشتم. درنهایت تابع add_to این دایرهها را به نقشه ایجادشده اضافه میکند.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #Create a map instance map_3 = folium.Map(location = [data.iloc[80, 0], data.iloc[80, 1]], zoom_start = 13, control_scale = True) #Add marker folium.Marker(location = (data.iloc[80, 0], data.iloc[80, 1]), tooltip = 'Distribution Center', icon = folium.Icon(color = 'green', icon = 'ok-sign')).add_to(map_3) #Add circles for i in range(data.shape[0] - 1): folium.CircleMarker(location = [data.iloc[i, 0], data.iloc[i, 1]], radius = 5, tooltip = 'order id: ' + data.iloc[i, 2], color = 'red', fill = True, fill_color = 'red').add_to(map_3) #Show map map_3 |
بخش چهارم: اضافه کردن امکان کنترل لایههای نقشه
یکی از امکانات جالب، اضافه کردن منو به نقشه است. ازآنجاکه اضافه کردن لایههای مختلف به نقشه میتواند آن را پیچیده و مخاطب را به خاطر وجود حجم زیادی از اطلاعات سرگشته کند، منوی نقشه میتواند به کاربر قدرت انتخاب لایههای مختلف را بدهد.
در کد زیر، با استفاده از FeatureGroup من دو لایه اصلی با عنوان fg_1 و fg_2 تعریف کردم. fg_1 مربوط به مرکز توزیع و fg_2 لایهای مربوط به نقاط مقصد است. سپس هرکدام از این لایهها را با تابع add_to به نقشه ایجادشده اضافه کردم.
همچنین توجه کنید که هنگام تعریف Marker و CricleMarker آنها را با استفاده از تابع add_to به fg_1 و fg_2 اضافه کردم. درنهایت با استفاده از LayerControl منو را به نقشه ایجادشده اضافه کردم. نتیجه را در زیر میبینید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #Create a map instance map_4 = folium.Map(location = [data.iloc[80, 0], data.iloc[80, 1]], zoom_start = 13, tiles = None, control_scale = True) #Change the default name of the map folium.raster_layers.TileLayer(tiles = 'OpenStreetMap', name = 'Orders Map').add_to(map_4) #Add feature groups fg_1 = folium.FeatureGroup(name = 'Dist. Center', overlay = True) fg_1.add_to(map_4) fg_2 = folium.FeatureGroup(name = 'Destinations', overlay = True) fg_2.add_to(map_4) #Add marker folium.Marker(location = (data.iloc[80, 0], data.iloc[80, 1]), tooltip = 'Distribution Center', icon = folium.Icon(color = 'green', icon = 'ok-sign')).add_to(fg_1) #Add circles for i in range(data.shape[0] - 1): folium.CircleMarker(location = [data.iloc[i, 0], data.iloc[i, 1]], radius = 5, tooltip = 'order id: ' + data.iloc[i, 2], color = 'red', fill = True, fill_color = 'red').add_to(fg_2) #Add layer control folium.LayerControl(collapsed = False).add_to(map_4) #Show map map_4 |
بخش پنجم: اضافه کردن چندضلعی روی نقشه
یکی دیگر از موارد کاربردی در کار با نقشهها اضافه کردن یک ناحیه در قالب چندضلعی (Polygon) است. من در این گام ابتدا یک لیست حاوی رئوس چندضلعی را ساختم. این چندضلعی یک محله در منطقه ستارخان را مشخص میکند.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | polygon = [(35.7199811, 51.3593432), (35.7288839, 51.3687658), (35.7291332, 51.3679424), (35.7291953, 51.3675991), (35.7292203, 51.3672504), (35.7292138, 51.3668749), (35.7290842, 51.3657376), (35.7290167, 51.3648216), (35.7288981, 51.3638641), (35.7282710, 51.3623366), (35.7281316, 51.3611993), (35.7281077, 51.3553977), (35.7279879, 51.3548304), (35.7267304, 51.3523869), (35.7266052, 51.3520328), (35.7264822, 51.3515635), (35.7263995, 51.3506971), (35.7263940, 51.3496202), (35.7247359, 51.3496122), (35.7208380, 51.3494378), (35.7203111, 51.3494970), (35.7197296, 51.3496953), (35.7191896, 51.3500226), (35.7188461, 51.3504365), (35.7181770, 51.3512430), (35.7175541, 51.3518223), (35.7169553, 51.3521039), (35.7144552, 51.3524848), (35.7147841, 51.3532117), (35.7152904, 51.3541035), (35.7160853, 51.3551898), (35.7166566, 51.3558067), (35.7183904, 51.3576789), (35.7199811, 51.3593432)] |
سپس از Polygon برای ایجاد این چندضلعی بهره بردم. توجه کنید بهمنظور ایجاد امکان نمایش یا عدم نمایش این چندضلعی، با استفاده از FeatureGroup، یک لایه با عنوان fg_3 ساختم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | #Create a Map instance map_5 = folium.Map(location = [data.iloc[80, 0], data.iloc[80, 1]], zoom_start = 13, tiles = None, control_scale = True) #Change the default name of the map folium.raster_layers.TileLayer(tiles = 'OpenStreetMap', name = 'Orders Map').add_to(map_5) #Add feature groups fg_1 = folium.FeatureGroup(name = 'Dist. Center', overlay = True) fg_1.add_to(map_5) fg_2 = folium.FeatureGroup(name = 'Destinations', overlay = True) fg_2.add_to(map_5) fg_3 = folium.FeatureGroup(name = 'SattarKhan Zone', overlay = True) fg_3.add_to(map_5) #Add marker folium.Marker(location = (data.iloc[80, 0], data.iloc[80, 1]), tooltip = 'Distribution Center', icon = folium.Icon(color = 'green', icon = 'ok-sign')).add_to(fg_1) #Add circles for i in range(data.shape[0] - 1): folium.CircleMarker(location = [data.iloc[i, 0], data.iloc[i, 1]], radius = 5, tooltip = 'order id: ' + data.iloc[i, 2], color = 'red', fill = True, fill_color = 'red').add_to(fg_2) #Add polygon folium.Polygon(locations = polygon, tooltip = 'SattarKhan Zone', color = 'blue', fill = True).add_to(fg_3) #Add layer control folium.LayerControl(collapsed = False).add_to(map_5) #Show map map_5 |
بخش ششم: انتشار نقشه بهصورت فایل HTML
این امکان وجود دارد که نقشه نهایی را در قالب فایل HTML ذخیره کنید و آن را با دیگران به اشتراک بگذارید.
1 2 | #Save map map_5.save('final_map.html') |
بهاینترتیب هر فردی در سیستم خودش بدون نیاز به آنکه کار با پایتون را بداند، میتواند آن را در نرمافزار مرورگر (Browser) مانند Google Chrome باز کند. همینطور میتوانید آن را در داخل محصولات دادهمحور تحت وب استفاده کنید. چنانکه در این مقاله دیدید من خروجی هر گام را داخل مقاله قرار دادم و شما میتوانید با نقشهها تعامل کنید.