Добавьте ff.create_quiver в go.Scattermapbox в качестве трассировки в Plotly Python

#python #plotly #plotly-python

#python #plotly #plotly-python

Вопрос:

Я пытаюсь добавить векторы ветра на свою карту Plotly. Это упрощенная версия кода:

 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(),
            },
        },
    )
 

Однако сгенерированный график — это не то, что я ищу. В итоге карта перекрывает график колчана, поэтому я вообще не вижу стрелок. Есть ли какой-либо способ исправить это, чтобы стрелки были четко показаны над картой?

Ответ №1:

  • использование стандартных трассировок и трассировок mapbox на одном рисунке проблематично
  • если подумать со стороны, вы можете создать quiver из геометрии и использовать https://shapely.readthedocs.io/en/stable/manual.html#affine-transformations чтобы задать размер и направление вектора
 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})
 

введите описание изображения здесь