matplotlib Geoplot分布图-属性错误:“Point”对象没有属性“exterior”

r7s23pms  于 2023-03-13  发布在  其他
关注(0)|答案(1)|浏览(201)

我正在尝试使用Geoplot创建一个区域分布图。数据以CSV格式提供,我正在尝试创建一个在特定区域(在本例中是佛罗里达州坦帕地区)上创建的格网的区域分布图。我希望最终的Map如下所示
This is what I am attempting to create
其中配色方案由列['InitialResponse']的值确定。每行表示坦帕地区中具有纬度/经度属性的点坐标。
当我奔跑
gplt.choropleth(dfsjoin, hue="InitialResponse", linewidth=.1, scheme=scheme, cmap='inferno_r', legend=True, edgecolor='black', ax=ax );
出现以下错误:

`---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
File D:\Anaconda\lib\site-packages\geoplot\geoplot.py:982, in choropleth.<locals>.ChoroplethPlot.draw(self)
    981 try:  # Duck test for MultiPolygon.
--> 982     for subgeom in geom:
    983         feature = GeopandasPolygonPatch(
    984             subgeom, facecolor=color, **self.kwargs
    985         )

TypeError: 'Point' object is not iterable

During handling of the above exception, another exception occurred:

AttributeError                            Traceback (most recent call last)
Cell In[94], line 1
----> 1 gplt.choropleth(dfsjoin, 
      2     hue="InitialResponse", 
      3     linewidth=.1,
      4     scheme=scheme, cmap='inferno_r',
      5     legend=True,
      6     edgecolor='black',
      7     ax=ax
      8 )

File D:\Anaconda\lib\site-packages\geoplot\geoplot.py:1001, in choropleth(df, projection, hue, cmap, norm, scheme, legend, legend_kwargs, legend_labels, legend_values, extent, figsize, ax, **kwargs)
    993         return ax
    995 plot = ChoroplethPlot(
    996     df, figsize=figsize, ax=ax, extent=extent, projection=projection,
    997     hue=hue, scheme=scheme, cmap=cmap, norm=norm,
    998     legend=legend, legend_values=legend_values, legend_labels=legend_labels,
    999     legend_kwargs=legend_kwargs, **kwargs
   1000 )
-> 1001 return plot.draw()

File D:\Anaconda\lib\site-packages\geoplot\geoplot.py:988, in choropleth.<locals>.ChoroplethPlot.draw(self)
    986                 ax.add_patch(feature)
    987         except (TypeError, AssertionError):  # Shapely Polygon.
--> 988             feature = GeopandasPolygonPatch(
    989                 geom, facecolor=color, **self.kwargs
    990             )
    991             ax.add_patch(feature)
    993 return ax

File D:\Anaconda\lib\site-packages\geopandas\plotting.py:120, in _PolygonPatch(polygon, **kwargs)
    116 from matplotlib.patches import PathPatch
    117 from matplotlib.path import Path
    119 path = Path.make_compound_path(
--> 120     Path(np.asarray(polygon.exterior.coords)[:, :2]),
    121     *[Path(np.asarray(ring.coords)[:, :2]) for ring in polygon.interiors],
    122 )
    123 return PathPatch(path, **kwargs)

AttributeError: 'Point' object has no attribute 'exterior'
`

我已经将CSV文件作为Pandas Dataframe 导入,然后将其转换为geopandas Dataframe 。
df_call_details = pd.read_csv("Model Rerun 50k Calls Masked.csv", index_col=False) df_call_details.keys()

Index(['Date', 'NatureCode', 'Address', 'CallID', 'FirstIn', 'ProcessingTime',
       'InitialResponse', 'FullComplement', 'IsFullOverwhelm',
       'IsPartialOverwhelm', 'HasResponses', 'Remarks', 'Level1Cause',
       'Level2Cause', 'CustomContent1', 'RegionName', 'DispatchRule',
       'ResponsePlan', 'XCoordinate', 'YCoordinate', 'Longitude', 'Latitude',
       'Call (Custom)', 'FirstResponding (Custom)', 'FirstArrival (Custom)',
       'FullComplement (Custom)', 'STEMI_Timestamp (Custom)', 'Grid (Custom)',
       'EMS_Area (Custom)', 'City (Custom)', 'FDID (Custom)',
       'Downgrade_ (Custom)', 'First_Due_Station (Custom)',
       'Area_Chief (Custom)', 'PD_Determinant (Custom)', 'PD_Acuity (Custom)',
       'PD_AnatPath (Custom)', 'Priority_Dispatch_Code (Custom)',
       'COVID_Flag (Custom)', 'RIP_Flag (Custom)', 'Downgrade_Time (Custom)',
       'Brain_Attack_Time (Custom)', 'STEMI_Time (Custom)',
       'Alarm_Count (Custom)'],
      dtype='object')

然后创建了一个地理 Dataframe

gdf_call_details = gpd.GeoDataFrame(df_call_details, geometry=gpd.points_from_xy(df_call_details['Longitude'],df_call_details['Latitude']))
gdf_call_details.crs='EPSG:4326'

这似乎正确地创建了一个带有WKT的几何列。
我还创建了一个使用导入的grid polygon in QGIS
gridData = gpd.read_file("shp\Grid Polygon 4326.shp")
我在包含点面和要显示的属性的数据框与格网之间执行了空间连接
dfsjoin = gpd.sjoin(gdf_call_details, gridData, how='inner')
当我运行代码时,我希望网格根据每行的初始响应值使网格区域变暗。
我的代码:

import pandas as pd, matplotlib, datetime, re, numpy as np, geopandas as gpd, geoplot as gplt, matplotlib.pyplot as plt, contextily as cx, folium, seaborn as sns
import cartopy.crs as ccrs, mapclassify as mc
import cartopy.io.img_tiles as cimgt
from IPython.display import display, HTML
display(HTML("<style>.container { width:95% !important; }</style>"))

gridData = gpd.read_file("shp\Grid Polygon 4326.shp")
gplt.polyplot(gridData, edgecolor='darkgrey', facecolor='lightgrey', linewidth=.3,
figsize=(12, 8))

df_call_details = pd.read_csv("Model Rerun 50k Calls Masked.csv", index_col=False)
df_call_details.keys()

gdf_call_details = gpd.GeoDataFrame(df_call_details, geometry=gpd.points_from_xy(df_call_details['Longitude'],df_call_details['Latitude']))
gdf_call_details.crs='EPSG:4326'
gdf_call_details.keys()

sns.histplot(responses['InitialResponse'], kde=True, stat='count')

dfsjoin = gpd.sjoin(gdf_call_details, gridData, how='inner')
dfsjoin.head(2)

scheme = mc.Quantiles(dfsjoin['InitialResponse'], k=15)

gplt.choropleth(dfsjoin, 
    hue="InitialResponse", 
    linewidth=.1,
    scheme=scheme, cmap='inferno_r',
    legend=True,
    edgecolor='black',
    ax=ax
);

我可以看到它与点数据有问题,但是我不能弄清楚是否需要尝试将其制作成带有点的多边形,或者我在空间连接方面犯了错误。

xkftehaa

xkftehaa1#

我想出了一个解决办法,但我认为它很笨重,运行速度很慢。

gdfjoin = gpd.sjoin(gdf_call_details, gridData, how='inner', predicate='intersects')
gdfjoin.drop(columns='index_right', inplace=True)
gdf_shapes = gdfjoin.merge(gridData, on='id')
gdf_shapes = gpd.GeoDataFrame(gdf_shapes, geometry= gdf_shapes['geometry_y'])
gdf_shapes.drop(columns='geometry_y', inplace=True)
gdf_shapes.head(2)

我发现,通过在.sjoin上创建的新 Dataframe 和包含形状网格的 Dataframe 之间执行常规 Dataframe 合并,将多边形几何体合并到所需的 Dataframe 中,我将其重命名为gdf_shape。
然而,我找不到一种方法来执行合并,同时保持一个Geopandas Dataframe ,而是成为一个常规的Pandas Dataframe ,所以我重新创建了一个geodataframe与geometry = geometry(新列创建时,我合并的shapefile Dataframe 到我的数据 Dataframe )。
如果有人有关于如何在.sjoin函数中执行这些步骤而不必执行合并、删除列和重新创建geopandas Dataframe 的建议,我很想知道!

相关问题