Bokeh映射县[英] Bokeh Mapping Counties

本文是小编为大家收集整理的关于Bokeh映射县的处理方法,想解了Bokeh映射县的问题怎么解决?Bokeh映射县问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

我正在尝试修改这个例子与密歇根州的县数据.简而言之,它正在工作,但在绘制县的过程中,它似乎在这里和那里增加了一些额外的形状.我猜测,在某些情况下(有群岛的县),岛屿部分需要被列为一个单独的"县",但我不确定其他案例,比如与韦恩县的较低右边的一部分.

这是我目前的图片: 输入图像描述

这是我到目前为止所做的:

  1. 从Bokeh的样本县数据获取县数据只是为了获得每个状态编号的状态缩写(我的第二个,主要数据源只有状态号).对于此示例,我将仅通过过滤状态26)来简化它.
  2. get state coordinates ('500k'文件)来自美国.人口普查站点
  3. 使用以下代码生成密歇根州的"互动"地图.

注意:到pip安装shapefile(真的pyshp),我想我不得不从这里然后do pip安装[路径到.whl文件].

import pandas as pd
import numpy as np
import shapefile
from bokeh.models import HoverTool, ColumnDataSource
from bokeh.palettes import Viridis6
from bokeh.plotting import figure, show, output_notebook
shpfile=r'Path\500K_US_Counties\cb_2015_us_county_500k.shp'
sf = shapefile.Reader(shpfile)
shapes = sf.shapes()

#Here are the rows from the shape file (plus lat/long coordinates)
rows=[]
lenrow=[]
for i,j in zip(sf.shapeRecords(),sf.shapes()):
    rows.append(i.record+[j.points])
    if len(i.record+[j.points])!=10:
           print("Found record with irrular number of columns")
fields1=sf.fields[1:] #Ignore first field as it is not used (maybe it's a meta field?)
fields=[seq[0] for seq in fields1]+['Long_Lat']#Take the first element in each tuple of the list
c=pd.DataFrame(rows,columns=fields)
try:
    c['STATEFP']=c['STATEFP'].astype(int)
except:
    pass
#cns=pd.read_csv(r'Path\US_Counties.csv')
#cns=cns[['State Abbr.','STATE num']]
#cns=cns.drop_duplicates('State Abbr.',keep='first')
#c=pd.merge(c,cns,how='left',left_on='STATEFP',right_on='STATE num')
c['Lat']=c['Long_Lat'].apply(lambda x: [e[0] for e in x]) 
c['Long']=c['Long_Lat'].apply(lambda x: [e[1] for e in x])
#c=c.loc[c['State Abbr.']=='MI']
c=c.loc[c['STATEFP']==26]
#latitudex, longitude=y
county_xs = c['Lat']
county_ys = c['Long']
county_names = c['NAME']
county_colors = [Viridis6[np.random.randint(1,6, size=1).tolist()[0]] for l in aland]
randns=np.random.randint(1,6, size=1).tolist()[0]
#county_colors = [Viridis6[e] for e in randns]
#county_colors = 'b'
source = ColumnDataSource(data=dict(
    x=county_xs,
    y=county_ys,
    color=county_colors,
    name=county_names,
    #rate=county_rates,
))

output_notebook()

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

p = figure(title="Title", tools=TOOLS,
           x_axis_location=None, y_axis_location=None)
p.grid.grid_line_color = None

p.patches('x', 'y', source=source,
          fill_color='color', fill_alpha=0.7,
          line_color="white", line_width=0.5)

hover = p.select_one(HoverTool)
hover.point_policy = "follow_mouse"
hover.tooltips = [
    ("Name", "@name"),
    #("Unemployment rate)", "@rate%"),
    ("(Long, Lat)", "($x, $y)"),
]

show(p)

我正在寻找一种方法来避免额外的线条和形状.

提前感谢!

推荐答案

我对此问题有一个解决方案,我认为我甚至可能知道为什么它是正确的.首先,让我在谷歌集团Bokeh讨论中从Bryan Van de Ven展示报价:

没有用于处理shapefile的内置支持.您必须将数据转换为散景理解的简单格式. (除了一边:在更容易地处理各种GIS格式的贡献是很好的贡献).

Bokeh期望修补程序的格式是点的"列表列表".所以类似的东西:

  xs = [ [patch0 x-coords], [patch1 x-coords], ... ]
  ys = [ [patch1 y-coords], [patch1 y-coords], ... ]

请注意,如果修补程序由多边形组成,则当前通过将纳米符号放入子夹中的值表示.因此,任务基本上是为了转换您必须使用这种格式的任何形式的多边形数据,然后可以显示Bokeh.

所以它似乎是不知何故,你忽略了NANS或者以其他方式正确处理多个多边形.以下是一些代码,将下载我们的人口普查数据,解压缩它,正确阅读散景,并制作拉特,长,州和县的数据框架.

def get_map_data(shape_data_file, local_file_path):
    url = "http://www2.census.gov/geo/tiger/GENZ2015/shp/" + \
      shape_data_file + ".zip"
    zfile = local_file_path + shape_data_file + ".zip"
    sfile = local_file_path + shape_data_file + ".shp"
    dfile = local_file_path + shape_data_file + ".dbf"
    if not os.path.exists(zfile):
        print("Getting file: ", url)
        response = requests.get(url)
        with open(zfile, "wb") as code:
            code.write(response.content)

    if not os.path.exists(sfile):
        uz_cmd = 'unzip ' + zfile + " -d " + local_file_path
        print("Executing command: " + uz_cmd)
        os.system(uz_cmd)

    shp = open(sfile, "rb")
    dbf = open(dfile, "rb")
    sf = shapefile.Reader(shp=shp, dbf=dbf)

    lats = []
    lons = []
    ct_name = []
    st_id = []
    for shprec in sf.shapeRecords():
        st_id.append(int(shprec.record[0]))
        ct_name.append(shprec.record[5])
        lat, lon = map(list, zip(*shprec.shape.points))
        indices = shprec.shape.parts.tolist()
        lat = [lat[i:j] + [float('NaN')] for i, j in zip(indices, indices[1:]+[None])]
        lon = [lon[i:j] + [float('NaN')] for i, j in zip(indices, indices[1:]+[None])]
        lat = list(itertools.chain.from_iterable(lat))
        lon = list(itertools.chain.from_iterable(lon))
        lats.append(lat)
        lons.append(lon)

    map_data = pd.DataFrame({'x': lats, 'y': lons, 'state': st_id, 'county_name': ct_name})
    return map_data

此命令的输入是您要将地图数据下载到的本地目录,而另一个输入是形状文件的名称.我知道您可以拨打的函数中的URL中至少有两个可用的地图:

map_low_res = "cb_2015_us_county_20m"
map_high_res = "cb_2015_us_county_500k"

如果美国人口普查会更改其URL,它们当然会有一天,那么您需要更改输入文件名和URL变量.所以,您可以称之为高于

map_output = get_map_data(map_low_res, ".")
然后,您可以像原始问题中的代码一样绘制它.首先添加颜色数据列(原始问题中的"county_colors"),然后将其设置为如下所示:

source = ColumnDataSource(map_output)
要使这一切工作,您需要导入库,如请求,操作系统,itertools,shapefile,bokeh.models.columndataSource等...

其他推荐答案

一个解决方案: 使用1:20,000,000形状文件而不是1:500,000文件. 它围绕每个县的形状丢失了一些细节,但没有任何额外的形状(只有几条额外的线条).

在此处输入图像描述

本文地址:https://www.itbaoku.cn/post/1727747.html