Dan*_*ty2 1 shapefile python-3.x pandas bokeh
我试图用密歇根州的县数据修改这个例子.简而言之,它是有效的,但它似乎在绘制县的过程中在这里和那里增加了一些额外的形状.我猜测在某些情况下(有岛屿的县),岛屿部分需要列为一个单独的"县",但我不确定另一个案例,例如在较低的韦恩县正确的部分国家.
这是我到目前为止所做的:
注意:要pip install shapefile(真的是pyshp),我想我必须从这里下载.whl文件,然后执行pip install [path to .whl file].
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)
Run Code Online (Sandbox Code Playgroud)
我正在寻找一种避免额外线条和形状的方法.
提前致谢!
我有一个解决这个问题的方法,我想我甚至可能知道它为什么是正确的.首先,让我在Google小组Bokeh讨论中向Bryan Van de ven引用:
没有内置的支持来处理shapefile.您必须将数据转换为Bokeh理解的简单格式.(顺便说一句:如果能够更轻松地处理各种GIS格式,那将会很棒.)
Bokeh期望补丁的格式是点的"列表".所以类似于:
Run Code Online (Sandbox Code Playgroud)xs = [ [patch0 x-coords], [patch1 x-coords], ... ] ys = [ [patch1 y-coords], [patch1 y-coords], ... ]请注意,如果修补程序由多个多边形组成,则目前通过将NaN值放在子列表中来表示.因此,任务基本上是将您拥有的任何形式的多边形数据转换为此格式,然后Bokeh可以显示它.
因此,似乎你忽略了NaN或者不能正确处理多个多边形.下面是一些代码,它们将下载美国人口普查数据,解压缩,正确读取Bokeh,并制作纬度,长度,州和县的数据框.
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
Run Code Online (Sandbox Code Playgroud)
此命令的输入是您要将地图数据下载到的本地目录,另一个输入是形状文件的名称.我知道上面函数中的url至少有两个可用的地图你可以调用:
map_low_res = "cb_2015_us_county_20m"
map_high_res = "cb_2015_us_county_500k"
Run Code Online (Sandbox Code Playgroud)
如果美国人口普查改变了他们的网址,他们肯定会有一天,那么你需要更改输入文件名和网址变量.所以,你可以调用上面的函数
map_output = get_map_data(map_low_res, ".")
Run Code Online (Sandbox Code Playgroud)
然后你可以像原始问题中的代码那样绘制它.首先添加一个颜色数据列(原始问题中的"county_colors"),然后将其设置为源,如下所示:
source = ColumnDataSource(map_output)
Run Code Online (Sandbox Code Playgroud)
要完成所有工作,您需要导入诸如requests,os,itertools,shapefile,bokeh.models.ColumnDataSource等库...
| 归档时间: |
|
| 查看次数: |
1850 次 |
| 最近记录: |