I'm trying to add wind vectors to my Plotly map. This is a simplified version of the code:
import plotly.graph_objects as go
import plotly.figure_factory as ff
fig = go.Figure(go.Scattermapbox(
mode = "markers",
lon = df['lon'],
lat = df['lat'],
marker = {'size': 5, 'color':'black'},
x, y = np.meshgrid(np.arange(0,2,.2), np.arange(0,2,.2))
u = np.cos(x) * y
v = np.sin(x) * y
vec_field = ff.create_quiver(x, y, u, v)
fig.add_traces(data = vec_field.data[0])
fig.update_layout(
margin={"l": 0, "r": 0, "t": 15, "b": 0},
mapbox={
"style": "carto-positron",
"zoom": 5,
"center": {
"lon": df['lon'].mean(),
"lat": df['lat'].mean(),
},
},
)
However, the plot generated is not what I'm looking for. The map ends up overlaying the quiver plot, so I can't see the arrows at all. Is there any way to rectify this, such that the arrows are shown clearly above the map?
import math
import geopandas as gpd
import pandas as pd
import plotly.express as px
import shapely.geometry
import numpy as np
from shapely.affinity import affine_transform as T
from shapely.affinity import rotate as R
# some geometry for an arrow
a = shapely.wkt.loads(
"POLYGON ((-0.6227064947841563 1.890841205238906, -0.3426264166591566 2.156169330238906, -0.07960493228415656 2.129731830238906, 1.952059130215843 0.022985736488906, -0.2085619635341561 -2.182924419761094, -0.6397611822841562 -1.872877544761094, -0.6636088385341563 -1.606053326011095, 0.5862935052158434 -0.400158794761094, -2.312440869784157 -0.3993228572610942, -2.526870557284156 -0.1848931697610945, -2.517313916659156 0.2315384708639062, -2.312440869784157 0.3990052677389059, 0.5862935052158434 0.399841205238906, -0.6363314947841564 1.565763080238906, -0.6227064947841563 1.890841205238906))"
)
gdf = (
gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
.set_crs("EPSG:4326")
)
# generate some data that has GPS co-ordinates, direction and magnitude of wind
df_wind = pd.concat(
[
pd.DataFrame(
{
"lat": np.linspace(*b[[0, 2]], 20),
"lon": np.linspace(*b[[1, 3]], 20),
"d": np.random.uniform(0, math.pi *2, 20),
"s": np.linspace(0.3, 1.5, 20),
}
)
for b in [gdf.sample(2)["geometry"].total_bounds for _ in range(5)]
]
).reset_index(drop=True)
# scatter points
t = (
px.scatter_mapbox(df_wind, lat="lon", lon="lat")
.update_layout(mapbox={"style": "carto-positron"})
.data
)
# wind direction and strength
px.choropleth_mapbox(
df_wind,
geojson=gpd.GeoSeries(
df_wind.loc[:, ["lat", "lon", "d", "s"]].apply(
lambda r: R(
T(a, [r["s"], 0, 0, r["s"], r["lat"], r["lon"]]),
r["d"],
origin=(r["lat"], r["lon"]),
use_radians=True,
),
axis=1,
)
).__geo_interface__,
locations=df_wind.index,
color="d",
).add_traces(t).update_layout(mapbox={"style": "carto-positron", "zoom": 1}, margin={"l":0,"r":0,"t":0,"b":0})