gpt4 book ai didi

python - 获取 GeoJSONDataSource 中所选项目的属性

转载 作者:太空狗 更新时间:2023-10-30 00:05:02 25 4
gpt4 key购买 nike

我想将包含补丁(来自 GeoJSONDataSource)的图表与折线图链接起来,但我无法获取所选补丁的属性。

Its basically a plot showing polygons, and when a polygon is selected, i want to update the line chart with a timeseries of data for that polygon.折线图由普通的 ColumnDataSource 驱动。

我可以通过添加与 geo_source.selected['1d']['indices'] 相结合的回调来获取所选补丁的索引。但是我如何获得与该索引对应的数据/属性?我需要在属性中获取一个“键”,然后我可以使用它来更新折线图。

GeoJSONDataSource 没有我可以在其中查找数据本身的 data 属性。 Bokeh 可以使用着色/工具提示等属性,所以我认为必须有一种方法可以从 GeoJSONDataSource 中获取这些属性,不幸的是我找不到它。

编辑:

这是工作玩具示例,展示了我到目前为止所获得的内容。

import pandas as pd
import numpy as np

from bokeh import events
from bokeh.models import (Select, Column, Row, ColumnDataSource, HoverTool,
Range1d, LinearAxis, GeoJSONDataSource)
from bokeh.plotting import figure
from bokeh.io import curdoc

import os
import datetime
from collections import OrderedDict

def make_plot(src):
# function to create the line chart

p = figure(width=500, height=200, x_axis_type='datetime', title='Some parameter',
tools=['xwheel_zoom', 'xpan'], logo=None, toolbar_location='below', toolbar_sticky=False)

p.circle('index', 'var1', color='black', fill_alpha=0.2, size=10, source=src)

return p

def make_geo_plot(src):
# function to create the spatial plot with polygons

p = figure(width=300, height=300, title="Select area", tools=['tap', 'pan', 'box_zoom', 'wheel_zoom','reset'], logo=None)

p.patches('xs', 'ys', fill_alpha=0.2, fill_color='black',
line_color='black', line_width=0.5, source=src)

p.on_event(events.SelectionGeometry, update_plot_from_geo)

return p

def update_plot_from_geo(event):
# update the line chart based on the selected polygon

selected = geo_source.selected['1d']['indices']

if (len(selected) > 0):
first = selected[0]
print(geo_source.selected['1d']['indices'])


def update_plot(attrname, old, new):
# Callback for the dropdown menu which updates the line chart
new_src = get_source(df, area_select.value)
src.data.update(new_src.data)

def get_source(df, fieldid):
# function to get a subset of the multi-hierarchical DataFrame

# slice 'out' the selected area
dfsub = df.xs(fieldid, axis=1, level=0)
src = ColumnDataSource(dfsub)

return src

# example timeseries
n_points = 100
df = pd.DataFrame({('area_a','var1'): np.sin(np.linspace(0,5,n_points)) + np.random.rand(100)*0.1,
('area_b','var1'): np.sin(np.linspace(0,2,n_points)) + np.random.rand(100)*0.1,
('area_c','var1'): np.sin(np.linspace(0,3,n_points)) + np.random.rand(100)*0.1,
('area_d','var1'): np.sin(np.linspace(0,4,n_points)) + np.random.rand(100)*0.1},
index=pd.DatetimeIndex(start='2017-01-01', freq='D', periods=100))

# example polygons
geojson = """{
"type":"FeatureCollection",
"crs":{"type":"name","properties":{"name":"urn:ogc:def:crs:OGC:1.3:CRS84"}},
"features":[
{"type":"Feature","properties":{"key":"area_a"},"geometry":{"type":"MultiPolygon","coordinates":[[[[-108.8,42.7],[-104.5,42.0],[-108.3,39.3],[-108.8,42.7]]]]}},
{"type":"Feature","properties":{"key":"area_b"},"geometry":{"type":"MultiPolygon","coordinates":[[[[-106.3,44.0],[-106.2,42.6],[-103.3,42.6],[-103.4,44.0],[-106.3,44.0]]]]}},
{"type":"Feature","properties":{"key":"area_d"},"geometry":{"type":"MultiPolygon","coordinates":[[[[-104.3,41.0],[-101.5,41.0],[-102.9,37.8],[-104.3,41.0]]]]}},
{"type":"Feature","properties":{"key":"area_c"},"geometry":{"type":"MultiPolygon","coordinates":[[[[-105.8,40.3],[-108.3,37.7],[-104.0,37.4],[-105.8,40.3]]]]}}
]
}"""

geo_source = GeoJSONDataSource(geojson=geojson)

# populate a drop down menu with the area's
area_ids = sorted(df.columns.get_level_values(0).unique().values.tolist())
area_ids = [str(x) for x in area_ids]
area_select = Select(value=area_ids[0], title='Select area', options=area_ids)
area_select.on_change('value', update_plot)

src = get_source(df, area_select.value)

p = make_plot(src)
pgeo = make_geo_plot(geo_source)

# add to document
curdoc().add_root(Row(Column(area_select, p), pgeo))

将代码保存在 .py 文件中并使用 bokeh serve example.py --show 加载

enter image description here

最佳答案

您应该为 GeoJSONDataSource 编写自定义扩展

这是 GeoJSONDataSource 的 CoffeeScript https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/models/sources/geojson_data_source.coffee

我不太擅长自定义扩展。所以我完全复制了 GeoJSONDataSource 并将其命名为 CustomGeo。我只是将“数据”从@internal 移到了@define。然后宾果游戏,你得到了一个带有“数据”属性的 GeoJSONDataSource。

在下面的示例中,我使用“键”列表进行了回调,但是由于您现在拥有这样的数据,如果您担心混洗,您可以编写一些东西来双重检查它是否对应于适当的多边形

import pandas as pd
import numpy as np

from bokeh.core.properties import Instance, Dict, JSON, Any

from bokeh import events
from bokeh.models import (Select, Column, Row, ColumnDataSource, HoverTool,
Range1d, LinearAxis, GeoJSONDataSource, ColumnarDataSource)
from bokeh.plotting import figure
from bokeh.io import curdoc

import os
import datetime
from collections import OrderedDict

def make_plot(src):
# function to create the line chart

p = figure(width=500, height=200, x_axis_type='datetime', title='Some parameter',
tools=['xwheel_zoom', 'xpan'], logo=None, toolbar_location='below', toolbar_sticky=False)

p.circle('index', 'var1', color='black', fill_alpha=0.2, size=10, source=src)

return p

def make_geo_plot(src):
# function to create the spatial plot with polygons

p = figure(width=300, height=300, title="Select area", tools=['tap', 'pan', 'box_zoom', 'wheel_zoom','reset'], logo=None)

a=p.patches('xs', 'ys', fill_alpha=0.2, fill_color='black',
line_color='black', line_width=0.5, source=src,name='poly')

p.on_event(events.SelectionGeometry, update_plot_from_geo)

return p

def update_plot_from_geo(event):
# update the line chart based on the selected polygon

try:
selected = geo_source.selected['1d']['indices'][0]
except IndexError:
return

print geo_source.data
print geo_source.data['key'][selected]

new_src = get_source(df,geo_source.data['key'][selected])
src.data.update(new_src.data)

def update_plot(attrname, old, new):
# Callback for the dropdown menu which updates the line chart
print area_select.value
new_src = get_source(df, area_select.value)
src.data.update(new_src.data)

def get_source(df, fieldid):
# function to get a subset of the multi-hierarchical DataFrame

# slice 'out' the selected area
dfsub = df.xs(fieldid, axis=1, level=0)
src = ColumnDataSource(dfsub)

return src

# example timeseries
n_points = 100
df = pd.DataFrame({('area_a','var1'): np.sin(np.linspace(0,5,n_points)) + np.random.rand(100)*0.1,
('area_b','var1'): np.sin(np.linspace(0,2,n_points)) + np.random.rand(100)*0.1,
('area_c','var1'): np.sin(np.linspace(0,3,n_points)) + np.random.rand(100)*0.1,
('area_d','var1'): np.sin(np.linspace(0,4,n_points)) + np.random.rand(100)*0.1},
index=pd.DatetimeIndex(start='2017-01-01', freq='D', periods=100))

# example polygons
geojson = """{
"type":"FeatureCollection",
"crs":{"type":"name","properties":{"name":"urn:ogc:def:crs:OGC:1.3:CRS84"}},
"features":[
{"type":"Feature","properties":{"key":"area_a"},"geometry":{"type":"MultiPolygon","coordinates":[[[[-108.8,42.7],[-104.5,42.0],[-108.3,39.3],[-108.8,42.7]]]]}},
{"type":"Feature","properties":{"key":"area_b"},"geometry":{"type":"MultiPolygon","coordinates":[[[[-106.3,44.0],[-106.2,42.6],[-103.3,42.6],[-103.4,44.0],[-106.3,44.0]]]]}},
{"type":"Feature","properties":{"key":"area_d"},"geometry":{"type":"MultiPolygon","coordinates":[[[[-104.3,41.0],[-101.5,41.0],[-102.9,37.8],[-104.3,41.0]]]]}},
{"type":"Feature","properties":{"key":"area_c"},"geometry":{"type":"MultiPolygon","coordinates":[[[[-105.8,40.3],[-108.3,37.7],[-104.0,37.4],[-105.8,40.3]]]]}}
]
}"""

implementation = """
import {ColumnarDataSource} from "models/sources/columnar_data_source"
import {logger} from "core/logging"
import * as p from "core/properties"

export class CustomGeo extends ColumnarDataSource
type: 'CustomGeo'

@define {
geojson: [ p.Any ] # TODO (bev)
data: [ p.Any, {} ]
}

initialize: (options) ->
super(options)
@_update_data()
@connect(@properties.geojson.change, () => @_update_data())

_update_data: () -> @data = @geojson_to_column_data()

_get_new_list_array: (length) -> ([] for i in [0...length])

_get_new_nan_array: (length) -> (NaN for i in [0...length])

_flatten_function: (accumulator, currentItem) ->
return accumulator.concat([[NaN, NaN, NaN]]).concat(currentItem)

_add_properties: (item, data, i, item_count) ->
for property of item.properties
if !data.hasOwnProperty(property)
data[property] = @_get_new_nan_array(item_count)
data[property][i] = item.properties[property]

_add_geometry: (geometry, data, i) ->

switch geometry.type

when "Point"
coords = geometry.coordinates
data.x[i] = coords[0]
data.y[i] = coords[1]
data.z[i] = coords[2] ? NaN

when "LineString"
coord_list = geometry.coordinates
for coords, j in coord_list
data.xs[i][j] = coords[0]
data.ys[i][j] = coords[1]
data.zs[i][j] = coords[2] ? NaN

when "Polygon"
if geometry.coordinates.length > 1
logger.warn('Bokeh does not support Polygons with holes in, only exterior ring used.')
exterior_ring = geometry.coordinates[0]
for coords, j in exterior_ring
data.xs[i][j] = coords[0]
data.ys[i][j] = coords[1]
data.zs[i][j] = coords[2] ? NaN

when "MultiPoint"
logger.warn('MultiPoint not supported in Bokeh')

when "MultiLineString"
flattened_coord_list = geometry.coordinates.reduce(@_flatten_function)
for coords, j in flattened_coord_list
data.xs[i][j] = coords[0]
data.ys[i][j] = coords[1]
data.zs[i][j] = coords[2] ? NaN

when "MultiPolygon"
exterior_rings = []
for polygon in geometry.coordinates
if polygon.length > 1
logger.warn('Bokeh does not support Polygons with holes in, only exterior ring used.')
exterior_rings.push(polygon[0])

flattened_coord_list = exterior_rings.reduce(@_flatten_function)
for coords, j in flattened_coord_list
data.xs[i][j] = coords[0]
data.ys[i][j] = coords[1]
data.zs[i][j] = coords[2] ? NaN

else
throw new Error('Invalid type ' + geometry.type)

_get_items_length: (items) ->
count = 0
for item, i in items
geometry = if item.type == 'Feature' then item.geometry else item
if geometry.type == 'GeometryCollection'
for g, j in geometry.geometries
count += 1
else
count += 1
return count

geojson_to_column_data: () ->
geojson = JSON.parse(@geojson)

if geojson.type not in ['GeometryCollection', 'FeatureCollection']
throw new Error('Bokeh only supports type GeometryCollection and FeatureCollection at top level')

if geojson.type == 'GeometryCollection'
if not geojson.geometries?
throw new Error('No geometries found in GeometryCollection')
if geojson.geometries.length == 0
throw new Error('geojson.geometries must have one or more items')
items = geojson.geometries

if geojson.type == 'FeatureCollection'
if not geojson.features?
throw new Error('No features found in FeaturesCollection')
if geojson.features.length == 0
throw new Error('geojson.features must have one or more items')
items = geojson.features

item_count = @_get_items_length(items)

data = {
'x': @_get_new_nan_array(item_count),
'y': @_get_new_nan_array(item_count),
'z': @_get_new_nan_array(item_count),
'xs': @_get_new_list_array(item_count),
'ys': @_get_new_list_array(item_count),
'zs': @_get_new_list_array(item_count)
}

arr_index = 0
for item, i in items
geometry = if item.type == 'Feature' then item.geometry else item

if geometry.type == 'GeometryCollection'
for g, j in geometry.geometries
@_add_geometry(g, data, arr_index)
if item.type == 'Feature'
@_add_properties(item, data, arr_index, item_count)
arr_index += 1
else
# Now populate based on Geometry type
@_add_geometry(geometry, data, arr_index)
if item.type == 'Feature'
@_add_properties(item, data, arr_index, item_count)

arr_index += 1

return data

"""

class CustomGeo(ColumnarDataSource):
__implementation__ = implementation

geojson = JSON(help="""
GeoJSON that contains features for plotting. Currently GeoJSONDataSource can
only process a FeatureCollection or GeometryCollection.
""")

data = Dict(Any,Any,default={},help="wooo")

geo_source = CustomGeo(geojson=geojson)

# populate a drop down menu with the area's
area_ids = sorted(df.columns.get_level_values(0).unique().values.tolist())
area_ids = [str(x) for x in area_ids]
area_select = Select(value=area_ids[0], title='Select area', options=area_ids)
area_select.on_change('value', update_plot)

src = get_source(df, area_select.value)

p = make_plot(src)
pgeo = make_geo_plot(geo_source)

# add to document
curdoc().add_root(Row(Column(area_select, p), pgeo))

关于python - 获取 GeoJSONDataSource 中所选项目的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47225484/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com