散景无法从GeoJson正确渲染多面(岛) [英] Bokeh is not rendering properly multipolygon (islands) from GeoJson

查看:70
本文介绍了散景无法从GeoJson正确渲染多面(岛)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在散景上绘制一个Choropleth贴图.我的地理数据是带有Polygons和MultiPolygons的GeoJSON.

I'm rendering a choropleth map on Bokeh. My geodata is an GeoJSON with Polygons and MultiPolygons.

我在渲染Multipolygons时遇到问题:

I have trouble rendering the Multipolygons:

如果我提取某个要素的所有几何图形(例如,在一个列表中有四个岛),则它们的图不会在图形之间切开",而它们似乎都是一个.它显示了一些蜘蛛网"的东西,所有点都无序地穿过了.

If I extract all geometries of an feature (four islands, for example, in one list) their plot doesn't 'cut' between figures, and they seems all one. It shows some 'spiderweb' stuff, crossing unorderly all the points.

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

If I create one list for island (I assume that it is the correct way to work this), Bokeh doesn't plot anything. Not even the grid (only the toolbar)....and doesn't show any error.

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

Probably it's some issue with the output of the function 'obtCoordMultipoligono'.

我已经搜索了一些关于岛屿的例子,但是没有什么可以帮助我的.

I've searched for examples on islands, but nothing coudn't help me.

提前谢谢.

更新:我添加了摘要.它们是原始但实用的片段.这个想法就像是在BokehGallery上的德克萨斯失业"之类的输出,但我国上有岛屿.

Update: I add my snippets. They are fragments of original, but functional. The idea is an output like the 'Texas unemployment' on the BokehGallery, but my country has islands on it.

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

My GeoJSON in argentina.json (extract 1 multipolygon only; i don't have issues with polygons):

    {
    "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)

推荐答案

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

Instead of following the original 'Texas example', you can significantly simplify your code if you use Bokeh's GeoJSONDataSource.

使用geojson精简的示例如下:

A trimmed down example using your geojson could look like:

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)

输出结果如下:

这是使用下面注释中提到的整个geojson时的输出结果.

This is what the output looks like when using the entire geojson as mentioned in the comments below.

并放大南部的岛屿:

我添加了此功能,以便根据传递的JSON数据以交互方式编辑geoJSON.

I added this function in order to edit the geoJSON in an interactive way, depending on a JSON data passed.

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

The geoJSON now has the 'data' property and the state international code (property: 'ISO_3166-2').

JSON数据如下:

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

该函数读取geoJSON并分配数据:

The function reads the geoJSON and asign the data:

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

这篇关于散景无法从GeoJson正确渲染多面(岛)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆