Bokeh无法从GeoJson中正确渲染多边形(岛屿)

Nat*_*cha 2 python geojson bokeh

我在Bokeh上渲染了一个等值线图.我的地理数据是一个带有多边形和多边形的GeoJSON.

我在渲染Multipolygons时遇到问题:

如果我提取一个特征的所有几何形状(例如,在一个列表中的四个岛),它们的图形不会在图形之间"切割",它们似乎都是一个.它显示了一些"蜘蛛网"的东西,所有的点都是不规则的.

如果我为岛创建一个列表(我认为这是正确的工作方式),Bokeh不会绘制任何内容.甚至不是网格(只有工具栏)....并且不显示任何错误.

可能是函数'obtCoordMultipoligono'的输出存在问题.

我在岛上搜寻了一些例子,但没有什么可以帮助我.

提前致谢.

更新: 我添加了我的代码段.它们是原始的,但功能性的碎片.这个想法是像BokehGallery上的"德州失业"这样的输出,但是我的国家有它的岛屿.

我在argentina.json中的 GeoJSON (仅提取1个多字形;我没有多边形问题):

    {
    "type": "FeatureCollection",
    "features": [

    {
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [
            [
              [
                -59.68266601562502,
                -52.231640624999976
              ],
              [
                -59.74658203124997,
                -52.25087890624999
              ],
              [
                -59.76445312499996,
                -52.2421875
              ],
              [
                -59.784863281249955,
                -52.2046875
              ],
              [
                -59.78593749999999,
                -52.156152343749966
              ],
              [
                -59.79331054687498,
                -52.134179687500016
              ],
              [
                -59.75322265624999,
                -52.14140624999998
              ],
              [
                -59.681005859375034,
                -52.18007812499995
              ],
              [
                -59.68266601562502,
                -52.231640624999976
              ]
            ]
          ],
          [
            [
              [
                -58.438818359375006,
                -52.011035156249974
              ],
              [
                -58.432714843750006,
                -52.09902343749996
              ],
              [
                -58.512841796874966,
                -52.071093750000045
              ],
              [
                -58.54140625000002,
                -52.02841796874996
              ],
              [
                -58.49707031249997,
                -51.99941406250001
              ],
              [
                -58.46054687499998,
                -52.0015625
              ],
              [
                -58.438818359375006,
                -52.011035156249974
              ]
            ]
          ],
          [
            [
              [
                -61.01875,
                -51.7857421875
              ],
              [
                -60.94726562499997,
                -51.79951171875005
              ],
              [
                -60.87597656250003,
                -51.79423828125004
              ],
              [
                -60.91616210937494,
                -51.89697265625001
              ],
              [
                -60.94755859374996,
                -51.94628906250002
              ],
              [
                -61.031982421875,
                -51.94248046875004
              ],
              [
                -61.11577148437493,
                -51.87529296875003
              ],
              [
                -61.14501953125003,
                -51.83945312500001
              ],
              [
                -61.05166015625002,
                -51.81396484374997
              ],
              [
                -61.01875,
                -51.7857421875
              ]
            ]
          ],
          [
            [
              [
                -60.11171875000002,
                -51.39589843749998
              ],
              [
                -60.24882812499996,
                -51.39599609375
              ],
              [
                -60.27587890624997,
                -51.36318359374997
              ],
              [
                -60.275341796874955,
                -51.28056640625002
              ],
              [
                -60.17138671875,
                -51.273437499999986
              ],
              [
                -60.06982421875,
                -51.307910156249996
              ],
              [
                -60.07646484374993,
                -51.34257812500004
              ],
              [
                -60.11171875000002,
                -51.39589843749998
              ]
            ]
          ]

        ]
      },
      "type": "Feature",
      "properties": {
        "perimeter": 0,
        "vista": "mim",
        "provincia": "Islas Malvinas",
        "objectid": 24,
        "prov": 0,
        "bounds": [
          0,
          0
        ],
        "provif3_": 27.0,
        "ogc_fid": 26,
        "provif3_id": 26.0
      }
    }
    ]
    }
Run Code Online (Sandbox Code Playgroud)

我在PBIArg.csv中的数据:

24,AR-V,Islas,13245

我的代码:

<!-- language: lang-py -->

import json,pprint,csv
pp = pprint.PrettyPrinter(indent=4)
from bokeh.io import output_file, show
from bokeh.models import HoverTool
from bokeh.plotting import figure, show, output_file, ColumnDataSource
import pandas as pd
from osgeo import ogr

fname = r'islas.json' # constante hasta conseguir algo mejor
dname = r'PBIArg.csv' # variable estadística a graficar.



paleta = ["#FFF5F0", "#FEE0D2", "#FCBBA1", "#FC9272", "#FB6A4A", "#EF3B2C", "#CB181D", "#99000D"]


def colorante(rate,max_value,min_value,paleta):
    try:
        intensidad = int(float(len(paleta)-1) * float(rate - min_value) / float(max_value - min_value))
        return paleta[intensidad]
    except:
        intensidad = int(float(len(paleta)-1) * float(rate - min_value) / float(max_value - min_value))
        return paleta[intensidad]


def obtCoordMultipoligono(pcia):
    mpoly = ogr.CreateGeometryFromJson(pcia)

    print('pcia-MPOLY tiene esta cantidad de islas: ', mpoly.GetGeometryCount()) 
    coordX,coordY = [],[]

    # idx poly mpoly
    for idx, poly in enumerate(mpoly): #itero mpoly
        print('POLY tiene esta cantidad de islas: ', poly.GetGeometryCount()) 
        innerX,innerY = [],[]
        # ind 
        for ind in range(0, poly.GetGeometryCount()): #itero poly
            innerPoly = poly.GetGeometryRef(ind)
            print('INNERPOLY tiene esta cantidad de PUNTOS: ', innerPoly.GetPointCount()) 
            lastX,lastY = [],[]
            for i in range(0, innerPoly.GetPointCount()): #itero innerpoly
                # GetPoint returns a tuple not a Geometry
                punto = innerPoly.GetPoint(i)
                print('pto obtenido en X',punto[0])
                # Asigno a lista local
                lastX.append(punto[0])
                lastY.append(punto[1])
            print('LastX:')
            pp.pprint(lastX)
            innerX.append(lastX)
            innerY.append(lastY)
        print('InnerX:')
        pp.pprint(innerX)
        coordX.append(innerX)
        coordY.append(innerY)
        print('CoordX:')
        pp.pprint(coordX)
    dictCoord = dict(coordX=coordX,coordY=coordY)
    print('DictCoord:')
    pp.pprint(dictCoord)
    return dictCoord

############  MAIN  ##################
######## Leo csv estadísticas ########

with open(dname, 'r') as f:
    '''Leo el CSV, creo diccio de pciaID: estadísticaPcial.
    Abajo busco la estadísticaPcial max y min para luego calcular los colores'''
    max_value, min_value = 0,0
    datos = {}
    for row in csv.reader(f):
        estadistica = int(row[3])
        datos[row[0]] = estadistica
        if estadistica > max_value:
            max_value = estadistica
        if estadistica < min_value:
            min_value = estadistica

######## Leo geojson ########            
with open(fname, 'r') as f:
    geojson = f.read()
    geoDict = json.loads(geojson)

######## Parseo geojson ########

dictArg = {}
for pcia in geoDict['features']:
    pciaID = str(pcia['properties']['objectid'])
    nombrePcia = pcia['properties']['provincia']
    coordX = []
    coordY = []

    if pcia['geometry']['type'] == 'Polygon':
        for punto in pcia['geometry']['coordinates'][0]:
            if len(punto) == 2:
                coordX.append(punto[0])
                coordY.append(punto[1])
    elif pcia['geometry']['type'] == 'MultiPolygon': 
        multiJSON = json.dumps(pcia['geometry'])
        dictCoord = obtCoordMultipoligono(multiJSON)
        # print(dictCoord)
        coordX = dictCoord['coordX']
        coordY = dictCoord['coordY']

    # Handling states without data
    try:
        info=int(datos[pciaID])
    except KeyError:
        info = 0    
    color = colorante(info,max_value,min_value,paleta)
    dictPcia = dict(nombre=nombrePcia,coordX=coordX,coordY=coordY, info=info,color=color)
    dictArg[pciaID] = dictPcia
    print('dict',dictArg['19'])

######## saco coord de las pcias ########
provincias = {
    codPcia: nombrePcia for codPcia, nombrePcia in dictArg.items()
}

# print(provincias)
pcia_xs = [provincia['coordX'] for provincia in provincias.values()]
pcia_ys = [provincia['coordY'] for provincia in provincias.values()]

nombres_provincias = [provincia['nombre'] for provincia in provincias.values()]

######## Saco estadísticas de las pcias ########
provincias_datos = [provincia['info'] for provincia in provincias.values()]

######## Coloreo el mapa a nivel datos ########

provincias_colores = [provincia['color'] for provincia in provincias.values()]

source = ColumnDataSource(data=dict(
    x=pcia_xs,
    y=pcia_ys,
    color=provincias_colores,
    nombre=nombres_provincias,
    dato=provincias_datos,
))

TOOLS="pan,wheel_zoom,box_zoom,reset,hover,save"

p = figure(title="PBI de Argentina por provincia", tools=TOOLS)

p.patches('x', 'y', source=source,
          fill_color='color', fill_alpha=0.9,
          line_color='#767676', line_width=1.5)

hover = p.select_one(HoverTool)
hover.point_policy = "follow_mouse"
hover.tooltips = [
    ("State:", "@nombre"),
    ("Nº:", "@dato"),

]

output_file("PBIar.html", title="Testing islands in bokeh")

show(p)
Run Code Online (Sandbox Code Playgroud)

Rut*_*ies 6

如果您使用Bokeh,您可以显着简化代码,而不是遵循原始的"德克萨斯州示例" GeoJSONDataSource.

使用geojson的精简示例可能如下所示:

from bokeh.io import show, output_notebook, output_file
from bokeh.models import (
    GeoJSONDataSource,
    HoverTool,
    LinearColorMapper
)
from bokeh.plotting import figure
from bokeh.palettes import Viridis6

with open(r'argentina.geojson', 'r') as f:
    geo_source = GeoJSONDataSource(geojson=f.read())


color_mapper = LinearColorMapper(palette=Viridis6)

TOOLS = "pan,wheel_zoom,box_zoom,reset,hover,save"

p = figure(title="Argentina", tools=TOOLS, x_axis_location=None, y_axis_location=None, width=500, height=300)
p.grid.grid_line_color = None

p.patches('xs', 'ys', fill_alpha=0.7, fill_color={'field': 'objectid', 'transform': color_mapper}, 
          line_color='white', line_width=0.5, source=geo_source)


hover = p.select_one(HoverTool)
hover.point_policy = "follow_mouse"
hover.tooltips = [("Provincia:", "@provincia")]

output_file("PBIar.html", title="Testing islands in bokeh")

show(p)
Run Code Online (Sandbox Code Playgroud)

然后输出如下: 在此输入图像描述

编辑:

这是使用整个geojson时输出的样子,如下面的注释中所述.

在此输入图像描述

并放大了南部的岛屿:

在此输入图像描述

更新:具有可变数据的功能

我添加了这个函数,以便以交互方式编辑geoJSON,具体取决于传递的JSON数据.

geoJSON现在具有'data'属性和state国际代码(property:'ISO_3166-2').

JSON数据是这样的:

{
"AR-A": "7",
"AR-B": "53",
"AR-C": "46"
}
Run Code Online (Sandbox Code Playgroud)

该函数读取geoJSON并将数据设为:

def asignDataToStates(geo,data):
    for pcia in geo['features']:
        codPcia = str(pcia['properties']['ISO_3166-2'])

        if codPcia in data.keys():
            if data.values() != 0:
                pcia['properties']['data'] = data[codPcia]
    dataJson = json.dumps(geo,ensure_ascii=True)
    return dataJson
Run Code Online (Sandbox Code Playgroud)