简体   繁体   中英

Plot bar charts on a map in plotly

I want to plot a bar chart on a map created with plotly, similar to the QGIS plot here . Ideally, the bar chart would be stacked and grouped instead of just grouped. So far, I only found examples for pie charts on plotly maps, for instance here .

  • with plotly mapbox you can add layers
  • with plotly you can generate images from figures
  • using above two facts you can add URI encoded images to a mapbox figure
  • you have not provided any sample geometry or data. Have used a subset geopandas sample geometry plus generated random data for each country (separate graph)
  • the real key to this solution is layer-coordinates
    • get centroid of a country
    • add a buffer around this and get envelope (bounding rectangle)
    • arrange co-ordinates of envelope to meet requirements stated in link
import geopandas as gpd
import plotly.express as px
import numpy as np
import base64, io

# create an encocded image of graph...
# change to generate graph you want
def b64image(vals=np.random.randint(1, 25, 5)):
    fig = px.bar(
        pd.DataFrame({"y": vals}).pipe(
            lambda d: d.assign(category=d.index.astype(str))
        ),
        y="y",
        color="category",
    ).update_layout(
        showlegend=False,
        xaxis_visible=False,
        yaxis_visible=False,
        bargap=0,
        margin={"l": 0, "r": 0, "t": 0, "b": 0},
        autosize=False,
        height=100,
        width=100,
        paper_bgcolor="rgba(0,0,0,0)",
        plot_bgcolor="rgba(0,0,0,0)",
    )

    b = io.BytesIO(fig.to_image(format="png"))
    b64 = base64.b64encode(b.getvalue())
    return "data:image/png;base64," + b64.decode("utf-8"), fig

# get some geometry
world = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
# let's just work with a bounded version of europe
eur = world.loc[
    lambda d: d["continent"].eq("Europe")
    & ~d["iso_a3"].isin(["RUS", "NOR", "FRA", "ISL"])
]


px.choropleth_mapbox(
    eur,
    geojson=eur.__geo_interface__,
    locations="iso_a3",
    featureidkey="properties.iso_a3",
    color_discrete_sequence=["lightgrey"],
).update_layout(
    margin={"l": 0, "r": 0, "t": 0, "b": 0},
    showlegend=False,
    mapbox_style="carto-positron",
    mapbox_center={
        "lon": eur.unary_union.centroid.x,
        "lat": eur.unary_union.centroid.y,
    },
    mapbox_zoom=3,
    # add a plotly graph per country...
    mapbox_layers=[
        {
            "sourcetype": "image",
            # no data provided, use random values for each country
            "source": b64image(vals=np.random.randint(1, 25, 5))[0],
            # https://plotly.com/python/reference/layout/mapbox/#layout-mapbox-layers-items-layer-coordinates
            # a few hops to get 4 cordinate pairs to meet mapbox requirement
            "coordinates": [
                list(p) for p in r.geometry.centroid.buffer(1.1).envelope.exterior.coords
            ][0:-1][::-1],
        }
        for i, r in eur.iterrows()
    ],
)

output

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM