2

我试图通过修改描绘美国所有县的SVG 地图来生成等值线地图。基本方法由Flowing Data捕获。由于 SVG 基本上只是 XML,因此该方法利用了BeautifulSoup解析器。

问题是,解析器不会捕获pathSVG 文件中的所有元素。以下仅捕获了 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对象修改的图像会进行所有的课外活动?任何建议将不胜感激。

4

2 回答 2

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
于 2015-01-19T02:24:24.510 回答
2

alexce 的回答对您的第一个问题是正确的。至于你的第二个问题:

为什么用 ElementTree 对象修改的图像会进行所有的课外活动?"

答案很简单——不是每个<path>元素都画出一个县。具体来说,应该消除两个元素,一个带有id="State_Lines",一个带有。id="separator"你没有提供你的颜色数据集,所以我只是为每个县使用了一个随机的十六进制颜色生成器(从这里lxml改编),然后用来解析.svg's 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')

产生了这个漂亮的图像:

于 2015-01-19T03:07:30.793 回答