Я использовал следующий пост для нанесения символов маки на графический блок отображения.
Маркеры графического блока не отображаются (кроме круга)
import dash
from dash import Dash, dcc, html, Input, Output
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objs as go
import numpy as np
import requests
import svgpath2mpl, shapely.geometry, shapely.affinity
from pathlib import Path
from zipfile import ZipFile
import pandas as pd
import geopandas as gpd
import json
# download maki icons
# https://github.com/mapbox/maki/tree/main/icons
f = Path.cwd().joinpath("maki")
if not f.is_dir():
f.mkdir()
f = f.joinpath("maki.zip")
if not f.exists():
r = requests.get("https://github.com/mapbox/maki/zipball/main")
with open(f, "wb") as f:
for chunk in r.iter_content(chunk_size=128):
f.write(chunk)
fz = ZipFile(f)
fz.extractall(f.parent)
def to_shapely(mpl, simplify=0):
p = shapely.geometry.MultiPolygon([shapely.geometry.Polygon(a).simplify(simplify) for a in mpl])
p = shapely.affinity.affine_transform(p,[1, 0, 0, -1, 0, 0],)
p = shapely.affinity.affine_transform(p,[1, 0, 0, 1, -p.centroid.x, -p.centroid.y],)
return p
# convert SVG icons to matplolib geometries and then into shapely geometries
# keep icons in dataframe for further access...
SIMPLIFY=.1
dfi = pd.concat(
[
pd.read_xml(sf).assign(
name=sf.stem,
mpl=lambda d: d["d"].apply(
lambda p: svgpath2mpl.parse_path(p).to_polygons()
),
shapely=lambda d: d["mpl"].apply(lambda p: to_shapely(p, simplify=SIMPLIFY)),
)
for sf in f.parent.glob("**/*.svg")
]
).set_index("name")
# build a geojson layer that can be used in plotly mapbox figure layout
def marker(df, marker="marker", size=1, color="green", lat=51.379997, lon=-0.406042):
m = df.loc[marker, "shapely"]
if isinstance(lat, float):
gs = gpd.GeoSeries(
[shapely.affinity.affine_transform(m, [size, 0, 0, size, lon, lat])]
)
elif isinstance(lat, (list, pd.Series, np.ndarray)):
gs = gpd.GeoSeries(
[
shapely.affinity.affine_transform(m, [size, 0, 0, size, lonm, latm])
for latm, lonm in zip(lat, lon)
]
)
return {"source":json.loads(gs.to_json()), "type":"fill", "color":color}
Это отлично работает при нанесении изображения прямо на карту с использованием метода, описанного в сообщении. Но я хочу включить компонент, который позволит пользователю включать и выключать эти символы.
Я пытаюсь добавить их в один слой и использовать его для обновления макета. Возможно ли это сделать?
us_cities = pd.read_csv(
'https://raw.githubusercontent.com/plotl ... top-1k.csv'
)
external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP]
app = dash.Dash(__name__, external_stylesheets = external_stylesheets)
app.layout = html.Div([
dcc.Checklist(
id="symbol_on",
options=[{"label": "Symbol", "value": True}],
value=[],
inline=True
),
html.Div([
dcc.Graph(id="the_graph")
]),
])
@app.callback(
Output("the_graph", "figure"),
Input('symbol_on', 'value')
)
def update_graph(symbol_on):
fig = go.Figure()
scatter = px.scatter_mapbox(data_frame = us_cities,
lat = 'lat',
lon = 'lon',
zoom = 0,
hover_data = ['State', 'lat', 'lon']
)
fig.add_traces(list(scatter.select_traces()))
fig.update_layout(
height = 750,
mapbox=dict(
style='carto-positron',
),
)
star = marker(
dfi, "star", size=.1, color="red", lon=[-70, -80, -90], lat=[30, 40, 45]
),
airport = marker(
dfi, "airport", size=.1, color="green", lon=[-70, -80, -90], lat=[30, 40, 45]
),
layers = []
for lyr in symbol_on:
layers.append(star)
layers.append(airport)
fig.update_layout(mapbox={"layers": layers})
return fig
if __name__ == '__main__':
app.run_server(debug=True, port = 8050)
Подробнее здесь: https://stackoverflow.com/questions/788 ... ash-mapbox