使用python在scattermapbox中的点周围绘制一个多边形 [英] Draw a polygon around point in scattermapbox using python

查看:31
本文介绍了使用python在scattermapbox中的点周围绘制一个多边形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

I am using plotlys scattermapbox to plot points on a map. I'd like to draw the polygon that cover 'x' mile radius from a POI.

dcc.Graph(id="map-graph"),

@application.callback([

                         Output("map-graph", "figure"),
                      
                      ],
                      [

                         Input("address", "value"),
                         Input("type", "value")
                      ]
                      
                     )
def update_graph(address, type):
    
    for i, row in df.iterrows():

        lat = row["Lat"]
        lng = row["Long"]

        data.append({

                     "type": "scattermapbox",
                     "lat": [lat],
                     "lon": [lng],
                     "name": "Location",
                     "showlegend": False,
                     "hoverinfo": "text",
                     "mode": "markers",
                     "marker": {
                                "symbol": "circle",
                                "size": 8,
                                "opacity": 0.8,
                                "color": "black"
                               }
                      }
        )

     # Plot POI 
     POI_Lat = 37.785908
     POI_Long = -122.400803

     data.append({
                    "type": "scattermapbox",
                    "lat": [POI_Lat],
                    "lon": [POI_Long],
                     "marker": {
                        "symbol": "circle,
                        "size": 28,
                        "opacity": 0.7,
                        "color": "rgb(128, 128, 128)"
                        }
                    }
        )

df is a pandas dataframe that includes coordinates for locations within x miles of POI. How do I update the map-graph to draw a polygon that covers all the points?

Adding a layer to layout dictionary:

gdf = circles(Lat, Long, radius=1609.34)

print(gdf['geometry'][0])

POLYGON ((385272.0167249573 3768678.19769511, 385264.2673129799 3768520.454790493,.......))


layout = {

                        "autosize": True,
                        "hovermode": "closest",
                        "mapbox": {

                            "accesstoken": MAPBOX_KEY,
                            "bearing": 0,
                            "center": {
                                "lat": layout_lat,
                                "lon": layout_lon
                            },
                            "layers": [
                                         {
                                             "source": json.loads(gdf.geometry.to_json()),
                                             "below": "traces",
                                             "type": "line",
                                             "color": "purple",
                                             "line": {"width": 1.5},
                                         }
                            ],
                            "pitch": 0,
                            "zoom": zoom,
                            "style": "outdoors",

                        },

                        "margin": {
                           "r": 0,
                           "t": 0,
                           "l": 0,
                           "b": 0,
                           "pad": 0
                       }

           }

解决方案

  • based on answer to this duplicate question Obtain coordinates of a Polygon / Multi-polygon around a point in python
  • no sample data provided in question, so I've used UK hospital data
  • have created a helper function poi_poly(). NB radius is in meters as per UTM geometry
  • UTM geometry is used to create a polygon of specified radius
  • markers are then intersected with this polygon. Then get the convex hull
  • have provided option to return radius polygon as well, in example below I've returned this to demonstrate that the convex hull polygon is within the radius of the POI

import shapely.geometry
import pandas as pd
import geopandas as gpd
import requests, io, json
import plotly.express as px
import random


def poi_poly(
    df,
    radius=10 ** 5,
    poi={"Longitude": 0.06665166467428207, "Latitude": 51.19034957885742},
    lon_col="Longitude",
    lat_col="Latitude",
    include_radius_poly=False,
):

    # generate a geopandas data frame of the POI
    gdfpoi = gpd.GeoDataFrame(
        geometry=[shapely.geometry.Point(poi["Longitude"], poi["Latitude"])],
        crs="EPSG:4326",
    )
    # extend point to radius defined (a polygon).  Use UTM so that distances work, then back to WSG84
    gdfpoi = (
        gdfpoi.to_crs(gdfpoi.estimate_utm_crs())
        .geometry.buffer(radius)
        .to_crs("EPSG:4326")
    )

    # create a geopandas data frame of all the points / markers
    if not df is None:
        gdf = gpd.GeoDataFrame(
            geometry=df.loc[:, ["Longitude", "Latitude"]]
            .dropna()
            .apply(
                lambda r: shapely.geometry.Point(r["Longitude"], r["Latitude"]), axis=1
            )
            .values,
            crs="EPSG:4326",
        )
    else:
        gdf = gpd.GeoDataFrame(geometry=gdfpoi)

    # create a polygon around the edges of the markers that are within POI polygon
    return pd.concat(
        [
            gpd.GeoDataFrame(
                geometry=[
                    gpd.sjoin(
                        gdf, gpd.GeoDataFrame(geometry=gdfpoi), how="inner"
                    ).unary_union.convex_hull
                ]
            ),
            gpd.GeoDataFrame(geometry=gdfpoi if include_radius_poly else None),
        ]
    )


# get some public addressess - hospitals.  data that can be scattered
dfhos = pd.read_csv(
    io.StringIO(
        requests.get("http://media.nhschoices.nhs.uk/data/foi/Hospital.csv").text
    ),
    sep="¬",
    engine="python",
)


# generate polygon of markers within 5 mile radius of Point of Interest
poi = dfhos.loc[random.randint(0, len(dfhos) - 1), ["Longitude", "Latitude"]].to_dict()
gdf = poi_poly(dfhos, poi=poi, radius=1609.34 * 5, include_radius_poly=True)

fig = (
    px.scatter_mapbox(
        dfhos,
        lat="Latitude",
        lon="Longitude",
        color="Sector",
        hover_data=["OrganisationName", "Postcode"],
    )
    .update_traces(marker={"size": 10})
    .update_layout(
        mapbox={
            "style": "open-street-map",
            "zoom": 9,
            "center": {"lat": poi["Latitude"], "lon": poi["Longitude"]},
            "layers": [
                {
                    "source": json.loads(gdf.geometry.to_json()),
                    "below": "traces",
                    "type": "line",
                    "color": "purple",
                    "line": {"width": 1.5},
                }
            ],
        },
        margin={"l": 0, "r": 0, "t": 0, "b": 0},
    )
)
fig.show()

draw just a circle polygon

  • poi_poly() has been updated. DataFrame is no longer mandatory for finding markers within POI
  • simple example of creating a circle (actually a polygon) centred on a single set of GPS co-ordinates

import plotly.graph_objects as go

poi = {"Latitude": 37.785908, "Longitude": -122.400803}

go.Figure(go.Scattermapbox()).update_layout(
    mapbox={
        "style": "open-street-map",
        "zoom": 9,
        "center": {"lat": poi["Latitude"], "lon": poi["Longitude"]},
        "layers": [
            {
                "source": json.loads(poi_poly(None, poi=poi, radius=1609).to_json()),
                "below": "traces",
                "type": "line",
                "color": "purple",
                "line": {"width": 1.5},
            }
        ],
    },
    margin={"l": 0, "r": 0, "t": 0, "b": 0},
)

这篇关于使用python在scattermapbox中的点周围绘制一个多边形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆