我试图通过修改描绘美国所有县的SVG map来生成一个等值区域地图。 Flowing Data捕获了基本方法。由于SVG基本上只是XML,因此该方法利用了BeautifulSoup解析器。
问题是,解析器不捕获SVG文件中的所有path
元素。以下仅捕获了149条路径(超过3000条路径):
#Open SVG file
svg=open(shp_dir+'USA_Counties_with_FIPS_and_names.svg','r').read()
#Parse SVG
soup = BeautifulSoup(svg, selfClosingTags=['defs','sodipodi:namedview'])
#Identify counties
paths = soup.findAll('path')
len(paths)
然而,我知道,物理检查和ElementTree方法通过以下例程捕获3,143条路径的事实还存在更多:
#Parse SVG
tree = ET.parse(shp_dir+'USA_Counties_with_FIPS_and_names.svg')
#Capture element
root = tree.getroot()
#Compile list of IDs from file
ids=[]
for child in root:
if 'path' in child.tag:
ids.append(child.attrib['id'])
len(ids)
我还没有弄清楚如何以一种并非完全混乱的方式从ElementTree
对象写入。
#Define style template string
style='font-size:12px;fill-rule:nonzero;stroke:#FFFFFF;stroke-opacity:1;'+\
'stroke-width:0.1;stroke-miterlimit:4;stroke-dasharray:none;'+\
'stroke-linecap:butt;marker-start:none;stroke-linejoin:bevel;fill:'
#For each path...
for child in root:
#...if it is a path....
if 'path' in child.tag:
try:
#...update the style to the new string with a county-specific color...
child.attrib['style']=style+col_map[child.attrib['id']]
except:
#...if it's not a county we have in the ACS, leave it alone
child.attrib['style']=style+'#d0d0d0'+'\n'
#Write modified SVG to disk
tree.write(shp_dir+'mhv_by_cty.svg')
上面的修改/写入程序会产生这种怪异:
我的主要问题是:为什么BeautifulSoup无法捕获所有path
标签?第二,为什么用ElementTree
对象修改的图像会进行所有的课外活动?任何建议都将不胜感激。
答案 0 :(得分:3)
您需要执行以下操作:
升级到beautifulsoup4
:
pip install beautifulsoup4 -U
将其导入为:
from bs4 import BeautifulSoup
安装最新的lxml
模块:
pip install lxml -U
明确指定lxml
作为解析器:
soup = BeautifulSoup(svg, 'lxml')
演示:
>>> from bs4 import BeautifulSoup
>>>
>>> svg = open('USA_Counties_with_FIPS_and_names.svg','r').read()
>>> soup = BeautifulSoup(svg, 'lxml')
>>> paths = soup.findAll('path')
>>> len(paths)
3143
答案 1 :(得分:2)
alexce的回答对你的第一个问题是正确的。就你的第二个问题而言:
为什么使用ElementTree对象修改的图像会进行所有的课外活动?“
答案很简单 - 不是每个<path>
元素都会绘制一个县。具体来说,有两个元素,一个包含id="State_Lines"
,另一个包含id="separator"
,应该被删除。你没有提供你的颜色数据集,所以我只为每个县使用了一个随机的十六进制颜色生成器(改编自here),然后使用lxml
来解析.svg
的XML并遍历每个<path>
元素,跳过我上面提到的那些:
from lxml import etree as ET
import random
def random_color():
r = lambda: random.randint(0,255)
return '#%02X%02X%02X' % (r(),r(),r())
new_style = 'font-size:12px;fill-rule:nonzero;stroke:#FFFFFF;stroke-opacity:1;stroke-width:0.1;stroke-miterlimit:4;stroke-dasharray:none;stroke-linecap:butt;marker-start:none;stroke-linejoin:bevel;fill:'
tree = ET.parse('USA_Counties_with_FIPS_and_names.svg')
root = tree.getroot()
for child in root:
if 'path' in child.tag and child.attrib['id'] not in ["separator", "State_Lines"]:
child.attrib['style'] = new_style + random_color()
tree.write('counties_new.svg')
产生了这个漂亮的图像: