利用python解析基于GraphML的的社会网络并用GIS展示

好长一个标题… …但是确实是用python来连接SNA(Social Network Analysis)和GIS(Geographic Information System)。脑子里反复想着自己特长是啥,画地图?那大概是5岁以前的事情,后来几个伙计打趣说我谈恋爱很在行,Seriously,这方面我还确实拿不出手。一直不离不弃的,也许就是自己编程的能耐,当学了“君子不器”后,越来越发觉似乎连编程都不能当会事了,但是话说回来,至少这算是个爱好吧。

需求大抵是这样的,客户用igraph进行社会网络分析,然后生成了xml格式的数据文件,但并没有很好的网络展示平台,manager就来找我,希望通过我们研发的WebGIS系统展示。在我们的WebGIS系统中,矢量数据都是保存在PostgreSQL数据库里,一般来说,都是通过shapefile 生成sql files,然后导入数据库。由于没有shapefile,但是分析graphicML文件发现结构还是很简单的,而且对于社会网络的两个node之间的关系(relationship),从几何的角度讲,两个nodes构成的关系就是一条两点直线(edge)。基于此,我希望通过python对graphML进行分析,然后直接生成sql file,导入到postgreSQL里面,此后就能用uDig就能直接转换成为shapefile,我不清楚新版的ArcGIS 9.3有没有相似的功能,好久不用Arctoolbox了。

sna

原始数据片段:

< ?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<!-- Created by igraph -->
  <key id="filestub" for="graph" attr.name="filestub" attr.type="string"/>
  <key id="id" for="node" attr.name="id" attr.type="string"/>
  <key id="xcoord" for="node" attr.name="xcoord" attr.type="double"/>
  <key id="ycoord" for="node" attr.name="ycoord" attr.type="double"/>
  <key id="h_loc" for="edge" attr.name="h_loc" attr.type="string"/>
  <key id="h_zip" for="edge" attr.name="h_zip" attr.type="string"/>
  <key id="h_city" for="edge" attr.name="h_city" attr.type="string"/>
  <key id="t_loc" for="edge" attr.name="t_loc" attr.type="string"/>
  <key id="t_zip" for="edge" attr.name="t_zip" attr.type="string"/>
  <key id="t_city" for="edge" attr.name="t_city" attr.type="string"/>
  <key id="appyear" for="edge" attr.name="appyear" attr.type="string"/>
  <key id="patent" for="edge" attr.name="patent" attr.type="string"/>
  <key id="pat_type" for="edge" attr.name="pat_type" attr.type="string"/>
  <graph id="G" edgedefault="undirected" parse.nodes="1022" parse.edges="9399">
    <data key="filestub">/tmp/VDC/DSB/iGraph.322801</data>
    <node id="n0">
      <data key="id">20190035</data>
      <data key="xcoord">394.439</data>
      <data key="ycoord">245.759</data>
    </node>
    <node id="n1">
      <data key="id">21810055</data>
      <data key="xcoord">452.308</data>
      <data key="ycoord">-49.6771</data>
    </node>
    <edge source="n1020" target="n1021">
      <data key="h_loc">MA</data>
      <data key="h_zip">01532</data>
      <data key="h_city">NORTHBORO</data>
      <data key="t_loc">MA</data>
      <data key="t_zip">01601</data>
      <data key="t_city">WORCESTER</data>
      <data key="appyear">2004</data>
      <data key="patent">7459547</data>
      <data key="pat_type">U</data>
    </edge>
  </graph>
</graphml>

通过python对XML进行解析,我还是向大家推荐pyQuery,大概是喜欢Jquery的缘故吧,我觉得pyQuery用起来很方便,很顺手。大家可以到pyquery.org查找帮助和教程。需要注意的是,pyQuery对于命名空间的解析似乎不是很好,我记得以前我写过一篇帖子叫做两个GIS编程技巧,里面提及了用@nodeName=namespace:elementName的方式来对异域命名空间的元素进行解析。但是pyQuery似乎不能进行该操作,所以我在进行解释之前,将根节点的所有命名空间都删除了。
解析本省是一件很简单的事情,随后写入到另一个文件中,其次对每一个node和edge进行分析,按照SQL语法,生成INSERT INTO的语句。

python 代码片段

from pyquery import PyQuery as pq
from lxml import etree
d = pq(filename="data/rna.xml")
file = open('data/output.sql', 'w+')
content = ''
nodes =  d('node')
for item in nodes:
  content += "INSERT INTO sn_node ( the_geom, nid) VALUES ( GeomFromText('POINT(" + item[1].text.__str__() + " " + item[2].text.__str__() +")', 900913), '" + item.attrib['id'] + "');\n"
file.write(content)
file.close()

从而生成output.sql,如下片段,

INSERT INTO sn_node ( the_geom, nid) VALUES ( GeomFromText('POINT(394.439 245.759)', 900913), 'n0');
INSERT INTO sn_node ( the_geom, nid) VALUES ( GeomFromText('POINT(452.308 -49.6771)', 900913), 'n1');
INSERT INTO sn_node ( the_geom, nid) VALUES ( GeomFromText('POINT(172.295 72.8809)', 900913), 'n2');
INSERT INTO sn_node ( the_geom, nid) VALUES ( GeomFromText('POINT(-217.813 -581.18)', 900913), 'n3');
INSERT INTO sn_edge ( the_geom, snid, tnid, s_zip, t_zip, appyear, patent, pat_type) VALUES ( GeomFromText('LINESTRING(-206.829 790.104,-200.639 791.055)', 900913), 'n121', 'n365', '05403', '05452', '1997', '5902044', 'U');
INSERT INTO sn_edge ( the_geom, snid, tnid, s_zip, t_zip, appyear, patent, pat_type) VALUES ( GeomFromText('LINESTRING(-206.829 790.104,-231.181 757.468)', 900913), 'n121', 'n214', '05403', '05403', '1998', '6134704', 'U');

生成了SQL的INSERT INTO 语句后,然后加上创建数据库和构建索引的语句

CREATE TABLE sn_node (
id serial,
nid varchar(6)
);
SELECT AddGeometryColumn('', 'sn_node','the_geom',900913,'POINT',2);
CREATE INDEX sn_node_index ON sn_node USING GIST ( the_geom );

所有的SQL语句组成了一个SQL文件,如果你有PgAdminIII,导入不是繁琐的事情。不再熬述了。uDig可以直接读取PostgreSQL里面的数据,然后我在uDig里面可以绘制出社会网络的模型,也可uDig输出shapefile,再用ArcGIS读取并展示。如图所示:

ArcGIS 显示 SNA

Share with:

  • email
  • LinkedIn
  • Twitter
  • Facebook
  • del.icio.us
  • StumbleUpon
  • Reddit
  • Digg
  • 豆瓣

Related posts: