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

时间:2016-10-24 19:37:36

标签: 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
      }
    }
    ]
    }

我在 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)

1 个答案:

答案 0 :(得分:6)

如果您使用Bokeh&#39; GeoJSONDataSource,您可以大大简化代码,而不是遵循原始的&#39;德克萨斯示例。

使用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)

然后输出如下: enter image description here

编辑:

这是使用整个geojson时输出的样子,如下面的评论所述。

enter image description here

放大了南部的岛屿:

enter image description here

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

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

geoJSON现在拥有&#39;数据&#39;财产和州国际代码(财产:&#39; ISO_3166-2&#39;)。

JSON数据是这样的:

{
"AR-A": "7",
"AR-B": "53",
"AR-C": "46"
}

该函数读取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