Wind rose for each gps position in a map

I would like to create a plotly map with different gps positions.

And then I would like to overlay a wind rose/polar chart or an arrow for speed and wind direction on the map for each gps position.

I tried this but it’s not working:

import pandas as pd
import plotly.graph_objects as go
import plotly.express as px

# Define windrose data
wind_data = px.data.wind()

# Define locations
locations = {
    "Vienna": (48.2082, 16.3738),
    "Salzburg": (47.8095, 13.055),
    "Innsbruck": (47.2692, 11.4041),
    "Graz": (47.0707, 15.4395),
    "Linz": (48.3064, 14.2936)
}

# Create a DataFrame from the locations dictionary
df_locations = pd.DataFrame(locations.values(), index=locations.keys(), columns=['lat', 'lon'])

# Create a map figure
fig_map = px.scatter_mapbox(df_locations, lat="lat", lon="lon", zoom=7,
                            mapbox_style="carto-positron")

# Define windrose trace
fig_windrose = px.bar_polar(wind_data, r="frequency", theta="direction",
                            color="strength", template="plotly_dark",
                            color_discrete_sequence=px.colors.sequential.Plasma_r)

# Add windrose trace to the map
fig_map.add_trace(go.Barpolar(
    r=fig_windrose.data[0]['r'],
    theta=fig_windrose.data[0]['theta'],
    width=fig_windrose.data[0]['width'],
    marker=dict(color=fig_windrose.data[0]['marker']['color']),
    name='Windrose',
    thetaunit='degrees',
))

# Update map layout
fig_map.update_layout(
    mapbox=dict(
        center=dict(lon=13, lat=47),
        style="carto-positron",
        zoom=4,
    ),
    showlegend=False,
)

# Show the figure
fig_map.show()

Do any of you have an idea how to do this in Plotly? Thank you very much.

Okay, I tried this. But it only shows me my traces without an arrow:

import pandas as pd
import plotly.express as px
import math
import plotly.graph_objects as go

locations = {
    "Vienna": (48.2082, 16.3738),
    "Salzburg": (47.8095, 13.055),
    "Innsbruck": (47.2692, 11.4041),
    "Graz": (47.0707, 15.4395),
    "Linz": (48.3064, 14.2936)
}

# Create a DataFrame from the locations dictionary
df = pd.DataFrame(locations.values(), index=locations.keys(), columns=['lat', 'lon'])

fig = px.scatter_mapbox(df, lat="lat", lon="lon", zoom=7,
                        mapbox_style="carto-positron")

# Wind vectors (speed and direction)
wind_vectors = {
    "Vienna": (10, 45),     # (speed, direction in degrees)
    "Salzburg": (8, 120),
    "Innsbruck": (12, 270),
    "Graz": (7, 180),
    "Linz": (9, 60)
}

for city, (speed, direction) in wind_vectors.items():
    lat, lon = locations[city]
    # Calculate components of the wind vector
    u = speed * math.cos(math.radians(direction))
    v = speed * math.sin(math.radians(direction))
    # Add wind vector arrow
    fig.add_trace(go.Scattermapbox(
        mode="lines+markers",
        lon=[lon, lon + u * 0.01],  # Adjust length of arrow for visualization
        lat=[lat, lat + v * 0.01],
        line=dict(width=2, color="red"),
        marker=dict(size=10, color='red', symbol='arrow'),
        hoverinfo='skip'
    ))

# Adjust the height and width of the map
fig.update_layout(height=720, width=1280)

fig.show()

When I use symbol=‘circle’ than it works but not with symbol=‘arrow’.

I found here a solution Windrose Notebook example.

Is it work with Plotly? Does anyone know this?

Have you looked at the doc at this link?

@davidharris thank you for the Link. I am not able to add multiple wind roses in a plotly map.

I’ve not tried it, but I’d expected there might be a way to take the code from that link and use fig.add_trace() to add the wind roses to an existing figure. But I’d also expected there would be challenges along the way (positioning / sizing / zindex / … maybe). If you’ve tried this approach do you run into any specific problems? Or is it a complete non-starter?

@DreamBio
To place a wind rose on a map, first you should plot it within a go.Figure. Then that image is put on the map like in the second example (local image) in this answer:
https://community.plotly.com/t/plotly-equivalent-to-matplotlib-pcolormesh-for-plotting-raster-image-on-map/68685/7

@davidharris and @empet tanks for your help!

Now I used a different method (a folium map) and I get a result that I like to use:

import folium
import numpy as np
import pandas as pd

# Create a pandas DataFrame with GPS coordinates, wind speed, and direction
data = {
    "Latitude": [48.2082, 47.8095, 47.2692, 47.0707, 48.3064],
    "Longitude": [16.3738, 13.055, 11.4041, 15.4395, 14.2936],
    "Label": ["Vienna", "Salzburg", "Innsbruck", "Graz", "Linz"],
    "Wind_Speed": [50, 80, 60, 70, 40],
    "Wind_Direction": [45, 120, 210, 320, 90]
}

df = pd.DataFrame(data)

length_multiplier = 150  # Multiplier for the length of the lines

# Function to calculate new coordinates based on wind speed and direction
def calculate_new_coords(lat, lon, wind_speed, wind_direction, length_multiplier):
    wind_direction_rad = np.deg2rad(wind_direction)
    delta_lat = wind_speed * length_multiplier * np.cos(wind_direction_rad)
    delta_lon = wind_speed * length_multiplier * np.sin(wind_direction_rad)
    new_lat = lat + (delta_lat * 0.0000089)
    new_lon = lon + (delta_lon * 0.0000089 / np.cos(np.deg2rad(lat)))
    return new_lat, new_lon

# Calculate mean latitude and longitude
mean_lat = df['Latitude'].mean()
mean_lon = df['Longitude'].mean()

# Create a Folium map centered around the mean latitude and longitude with a specific zoom level
fig_map = folium.Map(location=[mean_lat, mean_lon], zoom_start=6)  # Adjust zoom level as needed

# Iterate over rows of the DataFrame
for index, row in df.iterrows():
    lat, lon = row['Latitude'], row['Longitude']
    label = row['Label']
    wind_speed = row['Wind_Speed']
    wind_direction = row['Wind_Direction']

    folium.Marker([lat, lon], popup=label).add_to(fig_map)

    new_lat, new_lon = calculate_new_coords(lat, lon, wind_speed, wind_direction, length_multiplier)
    folium.PolyLine([(lat, lon), (new_lat, new_lon)], color="red", dash_array='5,5').add_to(fig_map)

fig_map