Interactive map

Hello everyone,

I am new on this forum. I’m looking for help for a tool I try to create.
I am currently building a tool to download and merge meteorological data and merge all the files in one grib file. The user can select from a dropdown menu regions/altitude.

This part is already done, but now I want to make a “custom” button to allow the user to select the region he want. I want to do this by depicting a world map with wgs84 grid. the user would be able to click on one or multiple grid and each click would store the grid’s coordinates.

My problem is, I’m not be able to depict a map with the wgs84 grid that would be interactive. I tried with folium, arcGIS, but none worked yet. it seems for arcGIS that I would operate directly from the software, which can’t be possible, and for folium, it’s just download a .html map with the correct wgs84 grid, but as it is downloaded, I can’t interact with it.

Does someone already work on a same type of project and could help me?

Thanks for reading me and sorry for the long post.

Hello @SaltyBear,

I believe you can achieve this using dash-leaflet by utilizing events if you prefer a Python-only solution.

https://www.dash-leaflet.com/docs/events

Alternatively, you can use Leaflet with JavaScript directly. In this approach, you would set up a small REST API (using Flask, FastAPI, etc.) to handle interactions. The JavaScript part would be simple, such as onclick events to send coordinates to the backend, and you can handle the functionality with Python.

I hope this clarifies the information for you. Let me know if you have any questions!

1 Like

Hello cemrehancavdar,

Thank you for your answer, I will try that and come back.
I’m not against using js in addition to python. I will try both solution.

Hello,

So I have been able to depict a map on my web browser, now I’m just looking to make a complete wgs84 grid over the map. I think I’m gonna try with the Leaflet vector layer “Rectangle”. I’m not sure if it’s the best solution, but I’ll give it a try.
I will get each wgs84 cells coordinates to give it to each rectangle I’ll create.
If anyone have a better “easier” idea, please let me know.

So, after an entire day of work, I can’t find a proper way to do it, I depicted the map, but my grid doesn’t show up, I try with the coordinates stored in a .txt file, then in a .json and finally I came back to the .txt. nothing is working. I will let you see my code, maybe it could help. (I hope)

#!/usr/bin/env python3

import pandas as pd
import dash_leaflet as dl
from dash import Dash, Output, Input, State
from dash_extensions.javascript import assign

# Color selected state(s) red.
style_handle = assign('''function(feature, context){
    const {selected} = context.hideout;
    if(selected.includes(feature.properties.name)){
        return {fillColor: 'red', color: 'grey'}
    }
    return {fillColor: 'grey', color: 'grey'}
}''')

# Create small example app.
app = Dash()
dl.FullScreenControl()

file_path = '/home/saltybear/Bureau/Geopy/wgs84GridCells.txt'  # Change this to the path of your coordinates text file

# Read coordinates from a txt file and convert to float
def read_coordinates(file_path):
    with open(file_path, 'r') as file:
        lines = file.readlines()
        coordinates = []
        for line in lines:
            coords = [float(coord) for coord in line.strip().split(',')]
            coordinates.append(coords)
        print("Coordinates:", coordinates)
    return coordinates

# Function to create Rectangle components based on coordinates with unique IDs
def create_rectangles(coordinates):
    rectangles = []
    for i, bounds in enumerate(coordinates):
        rectangle_id = f"rectangle_{i}"
        rectangle = dl.Rectangle(bounds=bounds, id=rectangle_id)
        rectangles.append(rectangle)
    return rectangles

# Read coordinates from the file
coordinates = read_coordinates(file_path)
print("coordinates: ", coordinates)

# Create rectangles based on the coordinates with unique IDs
rectangles = create_rectangles(coordinates)
print("rectangles: ", rectangles)

app.layout = dl.Map([
    dl.TileLayer(),
    dl.GeoJSON(url='/path/to/your/worldMap.geo.json', zoomToBounds=True, id='geojson',
               hideout=dict(selected=[]), style=style_handle)
], style={'height': '100vh'}, center=[50.85045, 4.34878], zoom=2)

@app.callback(
    Output('geojson', 'hideout'),
    Input('geojson', 'n_clicks'),
    State('geojson', 'clickData'),
    State('geojson', 'hideout'),
    prevent_initial_call=True)
def toggle_select(_, feature, hideout):
    selected = hideout['selected']
    name = feature['properties']['name']
    if name in selected:
        selected.remove(name)
    else:
        selected.append(name)
    return hideout

if __name__ == '__main__':
    app.run_server()

my .txt is composed by 72 lines of coordinates organized like so:
90,180,60,150
60,180,30,150
30,180,00,150
00,180,-30,150

two lines equal one cell of the grid.

Good morning everyone,

So, I finally get a rectangle, but just one. here is the output:

here is my code, I don’t understand why it can’t depict all the rectangles. If anyone have an idea, would you please help me? I thought of putting all the coordinates in the code but it would be heavy…

#!/usr/bin/env python3

#import pandas as pd
import dash_leaflet as dl
from dash import Dash, Output, Input, State
from dash_extensions.javascript import assign

# Color selected state(s) red.
style_handle = assign('''function(feature, context){
    const {selected} = context.hideout;
    if(selected.includes(feature.properties.name)){
        return {fillColor: 'red', color: 'grey'}
    }
    return {fillColor: 'grey', color: 'grey'}
}''')

# Create app.
app = Dash()
dl.FullScreenControl()

file_path = '/home/saltybear/Bureau/Geopy/wgs84GridCells.txt'  # Change this to the path of your coordinates text file

# Read coordinates from a txt file and convert to float
def read_coordinates(file_path):
    with open(file_path, 'r') as file:
        lines = file.readlines()
        coordinates = []
        for line in lines:
            pairs = line.strip().split(';')
            # Extract pairs of numbers from each part separated by ','
            pairs_list = [[float(num) for num in pair.split(',')] for pair in pairs]
            coordinates.extend(pairs_list)
    return coordinates

coordinates = read_coordinates(file_path)
#print(coordinates) #DEBUG

app.layout = dl.Map([
    dl.TileLayer(noWrap = True),
    dl.Rectangle(bounds = coordinates),
    dl.GeoJSON(url='/path/to/your/worldMap.geo.json', zoomToBounds=True, id='geojson',
               hideout=dict(selected=[]), style=style_handle)
], style={'height': '100vh'}, center=[50.85045, 4.34878], zoom=1.5)

if __name__ == '__main__':
    app.run_server()

Thank you fr reading me.

Hi,
AFAIU using leaflet directly with and rest api would be easier, once you write your restapi you could easily do whatever you want.
After this thread i wondered for extending folium with websocket and using all python to manage folium, i could publish it if you want to check. It is an another direction but might be a bit harder to understand at first.

Hello,

Thank you for your reply, I succeeded, but I had to put all the coordinates in my python script…
It’s because the creation of the rectangles doesn’t take for loops. For now it will be okay, I will find a solution afterwards.
//////////////////////////////////////////////
!!! I am really sorry, I didn’t post the last message.

Just as you know, I used a totally different approach and I succeed that way.

Thank you again!