আমি মিউনিখ থেকে ভেনিস পর্যন্ত হাইকিং এবং সুন্দর আল্পস জুড়ে ট্রেক করার স্বপ্ন দেখি। কিন্তু যেহেতু আমাকে এখনও আমার দৈনন্দিন জীবন যাপন করতে হবে, আমার যাত্রা একাধিক পর্যায় নিয়ে গঠিত, প্রতিটি দুঃসাহসিক কাজের মধ্যে সপ্তাহ, মাস বা এমনকি বছরগুলি সহ। এটি ঠিক আছে, কারণ এটি গন্তব্যের চেয়ে যাত্রা সম্পর্কে বেশি। যাইহোক, আমি সর্বদা এই পথগুলিকে চাক্ষুষভাবে রিট্রেস করার একটি উপায় চেয়েছিলাম, দেখতে আমি কতদূর এসেছি এবং আমি আমার লক্ষ্যের কতটা কাছে এসেছি। আমি যে অগ্রগতি করেছি তা উদযাপন করার এবং যাত্রাকে আরও এগিয়ে নিতে নিজেকে অনুপ্রাণিত করার একটি উপায় চেয়েছিলাম।
সৌভাগ্যবশত, অনেক আউটডোর এবং স্পোর্টস অ্যাপ, যেমন Adidas Running, Komoot, Strava, এবং অন্যান্য, অনুগ্রহপূর্বক আমাদের GPX ফাইল হিসাবে আমাদের কার্যক্রম রপ্তানি করার অনুমতি দেয়। যাইহোক, সেই GPX ফাইলগুলির সাথে কোথাও যাওয়ার জায়গা নেই৷
এখানেই পাইথন এবং ফোলিয়াম খেলায় আসে। আমি সম্প্রতি ফোলিয়ামে হোঁচট খেয়েছি, ইন্টারেক্টিভ মানচিত্র তৈরি করার জন্য একটি শক্তিশালী পাইথন লাইব্রেরি। এটি সহজেই ভৌগলিক ডেটা অন্তর্ভুক্ত করতে পারে, যেমন GPX ফাইল, এবং কাস্টমাইজেশন এবং অন্বেষণের অনুমতি দেয়। আমার সংগ্রহ করা GPS ডেটার সম্পদের উপর অঙ্কন করে, আমি একটি মানচিত্র তৈরি করতে Folium-এর সাথে পরীক্ষা শুরু করেছি যা আমার বহিরঙ্গন ভ্রমণকে প্রাণবন্ত করে।
কিছু গবেষণা এবং অনেক পরীক্ষার পরে, আমি একটি মানচিত্র নিয়ে এসেছি যা আমাকে আমার অতীতের বহিরঙ্গন ক্রিয়াকলাপগুলিকে পুনরায় দেখার অনুমতি দেয়:
সুতরাং, আপনি যদি আমার মতো কিছু হন এবং কোনো উদ্দেশ্য ছাড়াই আপনার কাছে জিপিএস ডেটার ভান্ডার থাকে, আপনি ভাবতে পারেন যে আমি সেখানে কীভাবে পৌঁছলাম। সুতরাং, এই নিবন্ধে, আমি ব্যাখ্যা করব কিভাবে আপনার 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' } }
### 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
অন্বেষণ এবং ম্যাপিংয়ের এই যাত্রায়, আমরা শিখেছি কিভাবে পাইথন এবং ফোলিয়াম ব্যবহার করে জাগতিক GPX ফাইলগুলিকে একটি গতিশীল এবং ইন্টারেক্টিভ মানচিত্রে রূপান্তর করতে হয়। এখন, আপনি আপনার আউটডোর অ্যাডভেঞ্চারগুলিকে পুনরুজ্জীবিত করতে পারেন, আপনার অগ্রগতি উদযাপন করতে পারেন এবং আপনার যাত্রার পরবর্তী পর্যায়ে অনুপ্রাণিত থাকতে পারেন।
যাইহোক, আপনার মানচিত্র কাস্টমাইজ, প্রসারিত এবং উন্নত করার অনেক উপায় আছে। তাই আপনার GPX ফাইলগুলি ধরুন, Jupyter Notebook জ্বালিয়ে দিন এবং আপনার অতীতের বহিরঙ্গন কার্যকলাপগুলিকে মানচিত্রে জীবন্ত হতে দিন!
হ্যাপি ম্যাপিং!
সাথে থাকুন কারণ সামনে আরো অনেক কিছু আছে:
এছাড়াও এখানে প্রকাশিত.