绘制出的Choroplethmapbox不会显示所有多边形

时间:2019-10-20 22:01:04

标签: python plotly mapbox geopandas choropleth

我在Plotly方面遇到了一个奇怪的问题,下图将给出一些背景信息:

This is the map made with Bokeh

This is the map made with Plotly

相同的转换步骤适用于两个版本,但是由于某些原因,Plotly将排除某些形状。

这些是我正在使用的转换步骤:

import pandas as pd
import plotly.io as pio
import plotly.graph_objs as go
import json
import geopandas as gpd
import matplotlib.pyplot as plt
from shapely import wkt
from bokeh.plotting import save, figure
from bokeh.models import GeoJSONDataSource, LinearColorMapper, ColorBar
from bokeh.io import show, output_file
from bokeh.palettes import brewer

df_test = pd.read_csv(f'{filepath}')
df_blocks = pd.read_csv(f'{filepath}')
group_2 = df_test[['geo_name', 'edited_characteristics', 'total', 'male', 'female']]
group_2 = group_2.pivot(index='geo_name', columns='edited_characteristics', values=['total', 'male', 'female'])
cat = 'Total - Low-income status in 2015 for the population in private households to whom low-income concepts are applicable - 100% data'
group_2['LIM 0-17 percent'] = (
        group_2[( 'total', f'{cat}//0 to 17 years')] /
        group_2[( 'total', cat)]
        )
group_2.reset_index(inplace=True)
g2 = group_2[['geo_name', 'LIM 0-17 percent']]
g2.rename(columns={'geo_name': 'DAUID'}, inplace=True)
df_g2 = pd.merge(g2, df_blocks, on='DAUID')
df_g2['geometry'] = df_g2['geometry'].apply(wkt.loads)

geo_df_g2 = gpd.GeoDataFrame(df_g2, geometry='geometry')
geo_df_g2.crs = {'init': 'epsg:3347'}
geo_df_g2 = geo_df_g2.to_crs({'init': 'epsg:4326'})
geo_df_g2 = geo_df_g2[geo_df_g2[('LIM 0-17 percent', '')] < 1]
mean = geo_df_g2[('LIM 0-17 percent', '')].mean()
std = geo_df_g2[('LIM 0-17 percent', '')].std()
geo_df_g2 = geo_df_g2[(geo_df_g2[('LIM 0-17 percent', '')] < (mean - 1 
    * std)) | (geo_df_g2[('LIM 0-17 percent', '')] > (mean + 1 * std))]
geo_df_g2.columns = [x[0] if type(x) is tuple else x for x in 
    geo_df_g2.columns]
geo_df_g2 = geo_df_g2.loc[:, ~geo_df_g2.columns.duplicated()]
geo_df_g2_j = geo_df_g2.copy()
geo_df_g2_j['DAUID'] = geo_df_g2_j['DAUID'].astype(str)
geo_df_g2_j.set_index('DAUID', inplace=True)
geo_df_g2_json = json.loads(geo_df_g2_j.to_json())

完全使用

geo_df_g2 = geo_df_g2[['DAUID', 'LIM 0-17 percent']]
geo_df_g2['DAUID'] = geo_df_g2['DAUID'].astype(str)
fig = go.Figure(go.Choroplethmapbox(geojson=geo_df_g2_json,
                                    locations=geo_df_g2['DAUID'],
                                    z=geo_df_g2['LIM 0-17 percent'],
                                    colorscale='Viridis',
                                    zauto=True,
                                    marker_opacity=0.5,
                                    marker_line_width=0.5)
                )
fig.update_layout(mapbox_style='white-bg',
                  #mapbox_accesstoken=mapbox_token,
                  mapbox_zoom=12,
                  mapbox_center={'lat': 45.41117, 'lon': -75.69812})
fig.update_layout(margin={'r':0, 't':0, 'l':0, 'b':0})
pio.renderers.default = 'browser'
fig.show()

使用预订

json_data = json.dumps(geo_df_g2_json)

geosource = GeoJSONDataSource(geojson=json_data)
palette = brewer['YlGnBu'][8]
palette = palette[::-1]
color_mapper = LinearColorMapper(palette = palette, low = 0, high = 40)
    tick_labels = {'0': '0%', '5': '5%', '10':'10%', '15':'15%', 
    '20':'20%', '25':'25%', '30':'30%','35':'35%', '40': '>40%'}
color_bar = ColorBar(color_mapper=color_mapper, label_standoff=8,width 
    = 500, height = 20,
    border_line_color=None,location = (0,0), orientation = 
    'horizontal', major_label_overrides = tick_labels)
p = figure(title='LIM', plot_height=600, plot_width=950, 
    toolbar_location=None)
p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None
p.patches('xs', 'ys', source=geosource, fill_color={'field': 'LIM 0-17 percent', 'transform': color_mapper}, line_color='black', line_width=0.25, fill_alpha=1)
output_file('test_bokeh.html')
show(p)

如您所见,它们都使用相同的投影,相同的数据框转换和相同的类别。有没有办法来解决这个问题?

TIA

编辑:形状处于正确的位置,图中只缺少许多形状。

更新:希望看到其他Plotly模块是否可以解决问题,我将范围缩小了。使用Plotly上的教程创建Scattermapbox时,他们调用mapbox功能的方式比显示Choroplethmapbox上的教程更好地揭示了继承问题。显然正在发生的是,Plotly(或Mapbox)无法将附近的几组点识别为多边形的坐标,因此将它们排除在外,直到您指定希望它们出现为止。这是通过将“类型”的地图框字典值设置为“填充”,“线”或“圆”来完成的。当然,这会导致另一个问题,即这些新形状的颜色或标记方式与原始多边形不同,因为默认情况下它们不存在。

下面的代码示例有助于显示多边形点未形成完整形状的问题:

fig = go.Figure(go.Choroplethmapbox(geojson=geo_df_g2_json,

                                    locations=geo_df_g2['DAUID'],
                                    z=geo_df_g2['LIM 0-17 percent'],
                                    below='traces',
                                    colorscale='Viridis',
                                    zauto=True,
                                    marker_opacity=0.5,
                                    marker_line_width=0.5)
                        )
fig.update_layout(
        mapbox = {
            'style': 'carto-positron',
            'center': {'lat': 45.41117, 'lon': -75.69812},
            'zoom': 12, 'layers': [{
                'source': {
                    'type': "FeatureCollection",
                    'features': geo_df_g2_json['features']
                },
            'type': 'fill', 'below': 'traces', 'color': 'lightblue'}]},
        margin = {'l':0, 'r':0, 'b':0, 't':0})
fig.show()

为澄清我的意图,我想回答两个问题:

  1. 为什么将某些多边形坐标绘制为一个形状,而另一些坐标仅绘制为单个点?

  2. 使用上述功能后,是否存在基于'z'值的填充形状的解决方法?

2 个答案:

答案 0 :(得分:0)

我发现了造成多边形消失的原因。由于Plotly使用geojson文件而不是与geopandas数据框进行交互(我相信这就是原因),因此它对数据格式有更严格的要求。其他库(例如Bokeh,上下文或地理熊猫)会在绘制它们之前聚合多行共享同一父级的多边形,而Plotly会单独查看它们。在我的情况下,由于每个“ id”都有多个子ID,每个子ID都有自己的多边形坐标,因此Plotly在绘制它们时只会选择一个。它将其余的存储为点,并且仅当我使用“填充”选项时才显示它们。这是我的数据框的大致示例:

DAUID DBUID Total geometry
001   00101 5     Polygon(x1, y1)
001   00102 5     Polygon(x2, y2)
001   00103 5     Polygon(x3, y3)

因此,虽然主要编号和总值保持不变,但几何形状却没有。我在尝试编写颜色映射器时偶然发现了这一点,并发现我有重复的DAUID条目。最后,我的错是没有使用正确的数据库。

Plotly似乎很快将引入对Geopandas的支持,因此我很想知道它是否可以解决这种极端情况。

答案 1 :(得分:0)

我遇到了类似的问题。这是我的 geopandas 数据框的一部分,看起来像 -

   province_id  geometry
0  1            POLYGON (x1, y1)
1  1            POLYGON (x2, y2)
2  1            POLYGON (x3, y3)

我使用 province_id_data.dissolve(by='province_id', aggfunc='first') 将它们组合成一个多边形,然后使用 plotly 绘制。