paint-brush
কিভাবে আমি আমার বহিরঙ্গন ক্রিয়াকলাপ কল্পনা করতে পাইথন এবং ফোলিয়াম ব্যবহার করেছিদ্বারা@lukaskrimphove
7,709 পড়া
7,709 পড়া

কিভাবে আমি আমার বহিরঙ্গন ক্রিয়াকলাপ কল্পনা করতে পাইথন এবং ফোলিয়াম ব্যবহার করেছি

দ্বারা Lukas Krimphove14m2023/09/06
Read on Terminal Reader
Read this story w/o Javascript

অতিদীর্ঘ; পড়তে

অন্বেষণ এবং ম্যাপিংয়ের একটি অভিযান শুরু করুন! কীভাবে আপনার GPX ফাইলগুলিতে প্রাণ শ্বাস নিতে হয় এবং Folium ব্যবহার করে ইন্টারেক্টিভ মানচিত্র তৈরি করতে হয় তা শিখুন।
featured image - কিভাবে আমি আমার বহিরঙ্গন ক্রিয়াকলাপ কল্পনা করতে পাইথন এবং ফোলিয়াম ব্যবহার করেছি
Lukas Krimphove HackerNoon profile picture
0-item

আমি মিউনিখ থেকে ভেনিস পর্যন্ত হাইকিং এবং সুন্দর আল্পস জুড়ে ট্রেক করার স্বপ্ন দেখি। কিন্তু যেহেতু আমাকে এখনও আমার দৈনন্দিন জীবন যাপন করতে হবে, আমার যাত্রা একাধিক পর্যায় নিয়ে গঠিত, প্রতিটি দুঃসাহসিক কাজের মধ্যে সপ্তাহ, মাস বা এমনকি বছরগুলি সহ। এটি ঠিক আছে, কারণ এটি গন্তব্যের চেয়ে যাত্রা সম্পর্কে বেশি। যাইহোক, আমি সর্বদা এই পথগুলিকে চাক্ষুষভাবে রিট্রেস করার একটি উপায় চেয়েছিলাম, দেখতে আমি কতদূর এসেছি এবং আমি আমার লক্ষ্যের কতটা কাছে এসেছি। আমি যে অগ্রগতি করেছি তা উদযাপন করার এবং যাত্রাকে আরও এগিয়ে নিতে নিজেকে অনুপ্রাণিত করার একটি উপায় চেয়েছিলাম।


সৌভাগ্যবশত, অনেক আউটডোর এবং স্পোর্টস অ্যাপ, যেমন Adidas Running, Komoot, Strava, এবং অন্যান্য, অনুগ্রহপূর্বক আমাদের GPX ফাইল হিসাবে আমাদের কার্যক্রম রপ্তানি করার অনুমতি দেয়। যাইহোক, সেই GPX ফাইলগুলির সাথে কোথাও যাওয়ার জায়গা নেই৷


এখানেই পাইথন এবং ফোলিয়াম খেলায় আসে। আমি সম্প্রতি ফোলিয়ামে হোঁচট খেয়েছি, ইন্টারেক্টিভ মানচিত্র তৈরি করার জন্য একটি শক্তিশালী পাইথন লাইব্রেরি। এটি সহজেই ভৌগলিক ডেটা অন্তর্ভুক্ত করতে পারে, যেমন GPX ফাইল, এবং কাস্টমাইজেশন এবং অন্বেষণের অনুমতি দেয়। আমার সংগ্রহ করা GPS ডেটার সম্পদের উপর অঙ্কন করে, আমি একটি মানচিত্র তৈরি করতে Folium-এর সাথে পরীক্ষা শুরু করেছি যা আমার বহিরঙ্গন ভ্রমণকে প্রাণবন্ত করে।


কিছু গবেষণা এবং অনেক পরীক্ষার পরে, আমি একটি মানচিত্র নিয়ে এসেছি যা আমাকে আমার অতীতের বহিরঙ্গন ক্রিয়াকলাপগুলিকে পুনরায় দেখার অনুমতি দেয়:

সুতরাং, আপনি যদি আমার মতো কিছু হন এবং কোনো উদ্দেশ্য ছাড়াই আপনার কাছে জিপিএস ডেটার ভান্ডার থাকে, আপনি ভাবতে পারেন যে আমি সেখানে কীভাবে পৌঁছলাম। সুতরাং, এই নিবন্ধে, আমি ব্যাখ্যা করব কিভাবে আপনার GPX ফাইলগুলিতে প্রাণ শ্বাস নেওয়া যায়।


আসুন অনুসন্ধান এবং ম্যাপিংয়ের একটি অভিযান শুরু করি!

জুপিটার নোটবুক দিয়ে শুরু করা

এই অ্যাডভেঞ্চার শুরু করতে, আমরা জুপিটার নোটবুক ব্যবহার করব। কেন জুপিটার নোটবুক? এটি একটি চমত্কার ইন্টারেক্টিভ কম্পিউটিং পরিবেশ যা আমাদের কোড, ভিজ্যুয়ালাইজেশন এবং পাঠ্যকে একত্রিত করতে দেয়, এটি আমাদের ডেটা এবং ফোলিয়াম লাইব্রেরির সাথে পরীক্ষা করার জন্য নিখুঁত করে তোলে।


আপনি যদি এখনও জুপিটার নোটবুক ইনস্টল না করে থাকেন তবে তাদের অফিসিয়াল ওয়েবসাইটের নির্দেশাবলী অনুসরণ করুন। একবার ইনস্টল হয়ে গেলে, আপনি একটি নতুন জুপিটার নোটবুক তৈরি করতে পারেন এবং আপনার ভ্রমণের জন্য প্রস্তুত হতে পারেন।

ট্রেল ডেটার জন্য GPX ফাইল পার্স করা হচ্ছে

এর পরে, আমাদের মানচিত্রের জন্য আমাদের কাঁচামাল দরকার — GPX ফাইলগুলি৷ জিপিএক্স (জিপিএস এক্সচেঞ্জ ফরম্যাট) একটি বহুল ব্যবহৃত ফাইল ফরম্যাট যা অবস্থানের ডেটা সংরক্ষণ করে, যেমন অক্ষাংশ, দ্রাঘিমাংশ, উচ্চতা এবং সময়, এটি বহিরঙ্গন কার্যকলাপ ট্র্যাক করার জন্য আদর্শ করে তোলে।


আপনি যদি একজন আগ্রহী হাইকার, রানার, সাইক্লিস্ট, বা স্কিয়ার হন, তাহলে সম্ভাবনা আপনি ইতিমধ্যেই একটি আউটডোর বা স্পোর্টস অ্যাপ ব্যবহার করে বিভিন্ন ভ্রমণ ট্র্যাক করেছেন৷ এই অ্যাপগুলির মধ্যে অনেকগুলি আপনাকে আপনার ক্রিয়াকলাপগুলিকে GPX ফর্ম্যাটে রপ্তানি করার অনুমতি দেয়৷ তাই সেই GPX ফাইলগুলি সংগ্রহ করুন এবং শুরু করা যাক!


আমাদের পাইথন কোডে , আমরা GPX ফাইলগুলি পার্স করতে এবং অক্ষাংশ, দ্রাঘিমাংশ, উচ্চতা, গতি এবং দূরত্বের মতো প্রয়োজনীয় ট্রেল ডেটা বের করতে gpxpy লাইব্রেরি ব্যবহার করব। parse_gpx() ফাংশন আমাদের জন্য সমস্ত ভারী উত্তোলন করবে:


 ### READ GPX FILES import gpxpy import pandas as pd import numpy as np import haversine as hs from pathlib import Path def parse_gpx(file_path): # parse gpx file to pandas dataframe gpx = gpxpy.parse(open(file_path), version='1.0') data = [] points = [] for track in gpx.tracks: for segment in track.segments: for point_idx, point in enumerate(segment.points): points.append(tuple([point.latitude, point.longitude])) # calculate distances between points if point_idx == 0: distance = np.nan else: distance = hs.haversine( point1=points[point_idx-1], point2=points[point_idx], unit=hs.Unit.METERS ) data.append([point.longitude, point.latitude,point.elevation, point.time, segment.get_speed(point_idx), distance]) columns = ['Longitude', 'Latitude', 'Elevation', 'Time', 'Speed', 'Distance'] gpx_df = pd.DataFrame(data, columns=columns) return points, gpx_df activities = {} frames = [] for activity_type in ACTIVITY_TYPES: activities[activity_type] = {} pathlist = Path(activity_type).glob('**/*.gpx') for path in pathlist: # exclude hidden directories and files # will lead to performance issues if there are lots of hidden files if any(part.startswith('.') for part in path.parts): continue activity_group = path.parts[1] activity_name = path.parts[2] if activity_group not in activities[activity_type]: activities[activity_type][activity_group] = [] points, gpx_df = parse_gpx(path) gpx_df['Elevation_Diff'] = np.round(gpx_df['Elevation'].diff(), 2) gpx_df['Cum_Elevation'] = np.round(gpx_df['Elevation_Diff'].cumsum(), 2) gpx_df['Cum_Distance'] = np.round(gpx_df['Distance'].cumsum(), 2) gpx_df['Gradient'] = np.round(gpx_df['Elevation_Diff'] / gpx_df['Distance'] * 100, 1) activities[activity_type][activity_group].append({ 'name': activity_name.replace('.gpx', '').replace('_', ' '), 'points': points, 'gpx_df': gpx_df }) frames.append(gpx_df) df = pd.concat(frames) df

এটি একটি কার্যকলাপের সমস্ত প্রয়োজনীয় ডেটা আমাদেরকে ছেড়ে দেয়: সমস্ত জিপিএস স্থানাঙ্কের একটি তালিকা এবং সমস্ত ধরণের মেট্রিক্স ধারণকারী একটি পান্ডাস ডেটাফ্রেম৷

ইন্টারেক্টিভ ম্যাপে জিপিএক্স ট্রেইল প্লট করা

আমাদের GPS ডেটা এখন একটি পান্ডাস ডেটাফ্রেমে সংগঠিত, আমরা একটি ইন্টারেক্টিভ মানচিত্রে আমাদের বহিরঙ্গন ক্রিয়াকলাপগুলি কল্পনা করতে পারি৷ ফোলিয়াম এই কাজটিকে একটি হাওয়া করে তোলে:


 ### CONFIG # LOCATION = None LOCATION = [48.13743, 11.57549] # latitude, longitude ZOOM_START = 10 ACTIVITY_TYPES = { 'Hiking': { 'icon': 'person-hiking', 'color': 'green' }, 'Running': { 'icon': 'person-running', 'color': 'orange' }, 'Biking': { 'icon': 'person-biking', 'color': 'red' }, 'Skiing': { 'icon': 'person-skiing', 'color': 'blue' } }
  • আমরা একটি নির্দিষ্ট স্থানে কেন্দ্রীভূত একটি মানচিত্র তৈরি করব (আপনি একটি চয়ন করতে পারেন বা কোডটিকে আপনার ডেটার উপর ভিত্তি করে কেন্দ্র নির্ধারণ করতে দিতে পারেন)।
  • হাইকিং, দৌড়ানো, বাইক চালানো বা স্কিইং-এর মতো প্রতিটি ক্রিয়াকলাপের জন্য আমরা অনন্য রঙ এবং আইকন বরাদ্দ করব। ACTIVITY_TYPES অভিধান এতে আমাদের সাহায্য করবে৷
 ### READ GPX FILES import gpxpy import pandas as pd import numpy as np import haversine as hs from pathlib import Path def parse_gpx(file_path): # parse gpx file to pandas dataframe gpx = gpxpy.parse(open(file_path), version='1.0') data = [] points = [] for track in gpx.tracks: for segment in track.segments: for point_idx, point in enumerate(segment.points): points.append(tuple([point.latitude, point.longitude])) # calculate distances between points if point_idx == 0: distance = np.nan else: distance = hs.haversine( point1=points[point_idx-1], point2=points[point_idx], unit=hs.Unit.METERS ) data.append([point.longitude, point.latitude,point.elevation, point.time, segment.get_speed(point_idx), distance]) columns = ['Longitude', 'Latitude', 'Elevation', 'Time', 'Speed', 'Distance'] gpx_df = pd.DataFrame(data, columns=columns) return points, gpx_df activities = {} frames = [] for activity_type in ACTIVITY_TYPES: activities[activity_type] = {} pathlist = Path(activity_type).glob('**/*.gpx') for path in pathlist: # exclude hidden directories and files # will lead to performance issues if there are lots of hidden files if any(part.startswith('.') for part in path.parts): continue activity_group = path.parts[1] activity_name = path.parts[2] if activity_group not in activities[activity_type]: activities[activity_type][activity_group] = [] points, gpx_df = parse_gpx(path) gpx_df['Elevation_Diff'] = np.round(gpx_df['Elevation'].diff(), 2) gpx_df['Cum_Elevation'] = np.round(gpx_df['Elevation_Diff'].cumsum(), 2) gpx_df['Cum_Distance'] = np.round(gpx_df['Distance'].cumsum(), 2) gpx_df['Gradient'] = np.round(gpx_df['Elevation_Diff'] / gpx_df['Distance'] * 100, 1) activities[activity_type][activity_group].append({ 'name': activity_name.replace('.gpx', '').replace('_', ' '), 'points': points, 'gpx_df': gpx_df }) frames.append(gpx_df) df = pd.concat(frames) df That leaves us with all the necessary data of an activity: a list of all the GPS coordinates and a Pandas DataFrame containing all kinds of metrics. Plotting GPX Trails on the Interactive Map With our GPS data now organized in a Pandas DataFrame, we can visualize our outdoor activities on an interactive map. Folium makes this task a breeze: ### CONFIG # LOCATION = None LOCATION = [48.13743, 11.57549] # latitude, longitude ZOOM_START = 10 ACTIVITY_TYPES = { 'Hiking': { 'icon': 'person-hiking', 'color': 'green' }, 'Running': { 'icon': 'person-running', 'color': 'orange' }, 'Biking': { 'icon': 'person-biking', 'color': 'red' }, 'Skiing': { 'icon': 'person-skiing', 'color': 'blue' } } We'll create a map centered at a specific location (you can choose one or let the code determine the center based on your data). We'll assign unique colors and icons to each activity type, such as hiking, running, biking, or skiing. The ACTIVITY_TYPES dictionary will help us with this. ### CREATE MAP import folium from folium import plugins as folium_plugins if LOCATION: location = LOCATION else: location=[df.Latitude.mean(), df.Longitude.mean()] map = folium.Map(location=location, zoom_start=ZOOM_START, tiles=None) folium.TileLayer('OpenStreetMap', name='OpenStreet Map').add_to(map) folium.TileLayer('Stamen Terrain', name='Stamen Terrain').add_to(map) ### MAP TRAILS def timedelta_formatter(td): td_sec = td.seconds hour_count, rem = divmod(td_sec, 3600) hour_count += td.days * 24 minute_count, second_count = divmod(rem, 60) return f'{hour_count}h, {minute_count}min, {second_count}s' def create_activity_popup(activity): df = activity['gpx_df'] attributes = { 'Date': { 'value': df['Time'][df.index[0]].strftime("%m/%d/%Y"), 'icon': 'calendar' }, 'Start': { 'value': df['Time'][df.index[0]].strftime("%H:%M:%S"), 'icon': 'clock' }, 'End': { 'value': df['Time'][df.index[-1]].strftime("%H:%M:%S"), 'icon': 'flag-checkered' }, 'Duration': { 'value': timedelta_formatter(df['Time'][df.index[-1]]-df['Time'][df.index[0]]), 'icon': 'stopwatch' }, 'Distance': { 'value': f"{np.round(df['Cum_Distance'][df.index[-1]] / 1000, 2)} km", 'icon': 'arrows-left-right' }, 'Average Speed': { 'value': f'{np.round(df.Speed.mean() * 3.6, 2)} km/h', 'icon': 'gauge-high' }, 'Max. Elevation': { 'value': f'{np.round(df.Elevation.max(), 2)} m', 'icon': 'mountain' }, 'Uphill': { 'value': f"{np.round(df[df['Elevation_Diff']>0]['Elevation_Diff'].sum(), 2)} m", 'icon': 'arrow-trend-up' }, 'Downhill': { 'value': f"{np.round(abs(df[df['Elevation_Diff']<0]['Elevation_Diff'].sum()), 2)} m", 'icon': 'arrow-trend-down' }, } html = f"<h4>{activity['name'].upper()}</h4>" for attribute in attributes: html += f'<i class="fa-solid fa-{attributes[attribute]["icon"]}" title="{attribute}"> {attributes[attribute]["value"]}</i></br>' return folium.Popup(html, max_width=300) feature_groups = {} for activity_type in activities: color = ACTIVITY_TYPES[activity_type]['color'] icon = ACTIVITY_TYPES[activity_type]['icon'] for activity_group in activities[activity_type]: # create and store feature groups # this allows different activity types in the same feature group if activity_group not in feature_groups: # create new feature group fg = folium.FeatureGroup(name=activity_group, show=True) feature_groups[activity_group] = fg map.add_child(fg) else: # use existing fg = feature_groups[activity_group] for activity in activities[activity_type][activity_group]: # create line on map points = activity['points'] line = folium.PolyLine(points, color=color, weight=4.5, opacity=.5) fg.add_child(line) # create marker marker = folium.Marker(points[0], popup=create_activity_popup(activity), icon=folium.Icon(color=color, icon_color='white', icon=icon, prefix='fa')) fg.add_child(marker) map.add_child(folium.LayerControl(position='bottomright')) folium_plugins.Fullscreen(position='topright').add_to(map) map
  • আমরা তাদের গোষ্ঠীর নামের উপর ভিত্তি করে ট্রেলগুলিকে গোষ্ঠীবদ্ধ করতে Foliums FeatureGroup ধারণাগুলি ব্যবহার করব৷ এটি আমাদের পরে কিছু কার্যকলাপ গোষ্ঠী দেখাতে এবং লুকানোর অনুমতি দেবে৷
  • এখন, আমরা আমাদের পার্স করা ডেটার মাধ্যমে পুনরাবৃত্তি করব এবং ফোলিয়ামের পলিলাইন এবং মার্কার অবজেক্ট ব্যবহার করে মানচিত্রে প্রতিটি ট্রেইল প্লট করব। পলিলাইন প্রকৃত পথের প্রতিনিধিত্ব করবে, যখন মার্কার প্রতিটি কার্যকলাপের জন্য একটি সূচনা পয়েন্ট হিসাবে কাজ করবে। আপনি যখন একটি মার্কারে ক্লিক করেন, একটি পপআপ সংশ্লিষ্ট ট্রেইল সম্পর্কে প্রাসঙ্গিক তথ্য প্রদর্শন করবে।

উপসংহার

অন্বেষণ এবং ম্যাপিংয়ের এই যাত্রায়, আমরা শিখেছি কিভাবে পাইথন এবং ফোলিয়াম ব্যবহার করে জাগতিক GPX ফাইলগুলিকে একটি গতিশীল এবং ইন্টারেক্টিভ মানচিত্রে রূপান্তর করতে হয়। এখন, আপনি আপনার আউটডোর অ্যাডভেঞ্চারগুলিকে পুনরুজ্জীবিত করতে পারেন, আপনার অগ্রগতি উদযাপন করতে পারেন এবং আপনার যাত্রার পরবর্তী পর্যায়ে অনুপ্রাণিত থাকতে পারেন।


যাইহোক, আপনার মানচিত্র কাস্টমাইজ, প্রসারিত এবং উন্নত করার অনেক উপায় আছে। তাই আপনার GPX ফাইলগুলি ধরুন, Jupyter Notebook জ্বালিয়ে দিন এবং আপনার অতীতের বহিরঙ্গন কার্যকলাপগুলিকে মানচিত্রে জীবন্ত হতে দিন!

হ্যাপি ম্যাপিং!

এরপর কি?

সাথে থাকুন কারণ সামনে আরো অনেক কিছু আছে:


  • AWS ব্যবহার করে আপনার মানচিত্রের সাথে একটি ওয়েবসাইট স্থাপন করা
  • পাইথন এবং প্লটলি ব্যবহার করে উচ্চতা এবং গতির প্রোফাইল প্লট করা
  • এক দিকে তোলা ছবি সহ ট্রেইল উন্নত করা
  • এবং আরো অনেক কিছু

তথ্যসূত্র


এছাড়াও এখানে প্রকাশিত.