SVG格式
SVG(Scalable Vector Graphics)乃可缩放矢量图形。以前学Flash的时候看教程书了解过矢量图和位图的差异。位图(Bitmap)是比较普遍的图片表示形式,通过像素(每个位置的色彩点)的集合来表示一幅图像,因此位图的清晰度受其分辨率(Resolution)的限制。矢量图则通过存储图像的图形学特征来表示一幅图,比如矩形,折线,曲线的各个关键点的特征,因此矢量图的质量不会因放缩受影响,其相较下的缺点便是存储的复杂性。
位图与矢量图的放缩效果对比,这幅示例图是SVG格式的(源自维基百科)
SVG格式通过XML(eXtensible Markup Language,可扩展标记语言)定义,XML和HTML同属SGML(Standard Generalized Markup Language,标准通用标记语言)这一大类的标记语言。有趣的是这种格式的标准是有W3C制定的Web标准。因此,当我们用浏览器打开一幅SVG图像时,我们可以用其开发者工具查看它的每个元素。用文本编辑工具打开一个SVG文件同样能查看它的文件结构,实际上它很像一个HTML页面,只不过标签不同。正因为SVG的文件结构特点,往往对其操作最方便的就是利用Javascript这一门前端语言。
SVG基本标签
SVG 代码以<svg>元素开始,用开启标签<svg>和关闭标签</svg>包括。<svg>是SVG XML的根元素,如同HTML的<html></html>。<svg>标签的width 和 height 属性设置SVG文件的宽度和高度。
SVG的形状通过<rect>(矩形)、<circle>(圆形)、<ellipse>(椭圆)、<line>(线)、<polyline>(折线)、<polygon>(多边形)和<path>(路径)这些标签定义。打开维基开放媒体提供的世界地图素材后,可以发现上面的国家都是通过<path>标签定义的。
文字通过<text>标签插入。上面那幅示例图即通过这种方式插入文字。
<g>标签指定元素的组,在同个<g>标签内的元素位于同一组(这一点可以在用编辑器打开时体会)。比如地图素材中的美国由于有多个不相连的块组成,就体现了建组的作用。
SVG标签的样式同样是由CSS定义的,这为绘图提供大大的方便,标签的style属性就是用来指定CSS属性的。比如通过指定fill属性即可指定图形的填充颜色。
示例:
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg"> <line x1="0" y1="0" x2="300" y2="300" style="stroke:rgb(99,99,99);stroke-width:2"/> </svg>这段SVG XML代码定义了一幅从图片左上角画到左下角的直线。
世界地图的XML代码非常复杂,因为都是一堆<path>标签对国界线的定义,这种图形是通过编辑器画出来的。
关于SVG的更多标准可以查看W3C的官方文档。
代码
import re def getPaintedMap(classification, colorScheme, filename="untitled.svg"): f = open('test.svg', 'r') content = f.read() stylePattern = re.compile(r'<style id="style_css_sheet" type="text/css">([\s\S]+?)</style>') styleText = stylePattern.search(content).group(1) newStyle = styleText for country in classification: selectorStr = "." + country + " \n{\n\tfill: " + colorScheme[classification[country]] + "\n}\n" newStyle += selectorStr content = content.replace(styleText, newStyle) f.close() f = open(filename, "w") f.write(content) f.close()实际上代码的函数只是很简单的在原SVG文件的style标签中加上对应的css fill属性。素材中的每个国家都通过其对应的ISO 3166-2标准的国家代号(中国是cn,加拿大是ca等等)进行了标记。只需要用CSS选择器选择即可。
函数接受三个参数,classification是一个从ISO 3166-2国家代号字符串映射到分组号的字典,colorScheme定义着色方案,是分组号映射到颜色号的字典,filename定义输出的文件名。
简单应用
根据Opennet组织对73国的网络自由度评估,从组织整理的四项参数(的五级评分中,先做K-均值聚类而后绘制出这些国家的网络自由度程度评级,地图效果如下:
颜色越深的代表审查程度越严苛,灰色是原素材默认颜色,表示没有包括在数据内的国家。聚类结果比较符合预期,而画图的代码很直观地表示出分析信息。Python有一个第三方的pycountry模块,其源码中有很充足的ISO标准数据库,以xml格式存储。可以直接使用模块的函数或是自己抓出国家代号的信息。而Opennet官方也提供.csv格式的自由度评分数据。
题外话,Opennet的评估局限性在哪?除了其国家数量不足以外,更重要的一点是其评估的公允性。根据维基百科综合Opennet,无国界记者等的评估,结果如下:
无国界记者组织2014年列出的“互联网公敌”名单(图中粉色)新增了数个国家,包括美国和英国,很大程度即因为棱镜门丑闻的爆发。
没有评论 :
发表评论