Ploly Choroplethmapbox не показывает все полигоны - PullRequest
0 голосов
/ 21 октября 2019

У меня странная проблема с Plotly, изображение ниже даст некоторый контекст:

Это карта, сделанная с Bokeh

Этоэто карта, созданная с помощью 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())

PLOTLY

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()

USKE BOKEH

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) не распознает несколько групп соседних точек в качестве координат для многоугольника, и, следовательно, исключает их, пока вы не укажете, что хотите, чтобы они присутствовали. Это делается путем установки значений словаря mapbox для «type» в «fill», «line» или «circle». Это, конечно, приводит к другой проблеме, когда новые фигуры не окрашиваются и не маркируются так же, как исходные полигоны, поскольку их там не было по умолчанию.

Вот пример кода, который помогает показать проблему сточки многоугольника не образуют законченную форму:

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. Почему Plotly преобразует некоторыекоординаты многоугольника для фигуры, а другие только для отдельных точек?

  2. Существует ли обходной путь для заполнения фигур после использования вышеуказанной функции на основе значения 'z'?

1 Ответ

0 голосов
/ 22 октября 2019

Я выяснил, что заставляет полигоны исчезать. Поскольку Plotly использует файлы geojson, а не взаимодействует с фреймами данных геопанд (я полагаю, в этом причина), у него более строгие требования к форматированию данных. Другие библиотеки, такие как Bokeh, контекстно или геопанда, объединяют несколько строк полигонов, которые имеют общего родителя, перед тем как строить их, а Plotly смотрит на них по отдельности. В моем случае, так как у каждого '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 вскоре представит поддержку геопанд, поэтому мне было бы интересно посмотреть, разрешит ли она такие крайние случаи, как этот.

...