最近在搜索关于GIS的项目时,在知乎看到了一个构建电子地图网站的教程,里面运用到的QGIS、python语言是之前未接触到的,觉得比较新颖,接下来准备用几天的时间按照教程来实现网站功能,希望能有所收获,这也算是一次小小的实践经验!
1. 需要用到的软件
后端开发软件:IntelliJ IDEA,语言JAVA。
数据处理软件:pyCharm,语言python。(试试用vscode替代)
前端开发软件:sublime,语言JavaScript。(试试用vscode替代)
数据库:PostgreSQL+PostGIS,语言SQL。
数据查看软件:QGIS。
浏览器:谷歌chrome
新安装了QGIS、PostgreSQL、PostGIS、Navicat Premium
1.1 安装QGIS(易)
这个软件开源且安装简单,相比ArcGIS的各种破解,这个软件是真滴良心!直接从官网下载好电脑对应的版本,之后就是傻瓜的“下一步”式安装了!安装好了之后在“XYZ Tiles”下可以添加在线地图,百度搜索“瓦片地图”对应地图的url添加进去就ok 了!
1.2 安装PostgreSQL+PostGIS+Navicat Premium
特别注意:PostGIS的安装必须在PostgreSQL安装好之后再进行安装!!!两个的版本要对应,推荐安装稍微低一点的版本,高版本易出错,推荐PostgreSQL12+postgis3.0.x+Navicat Premium16
Navicat Premium的版本和
安装PostgreSQL(较易)
下载电脑对应版本的软件
注:PostGIS的版本要与PostgreSQL版本一致,所以,不推荐下载高版本的。最开始我下载的PostgreSQL15,安装了对应的PostgreSQL版本之后,PostgreSQL中是有根据PostGIS新建的数据库,但是PostgreGIS一直打不开,报错:找不到xxxxx.dll文件
推荐下载PostgreSQL12
安装过程要设置密码和端口号,端口号默认就行
安装PostgreGIS(较易)
下载与PostgreSQL对应的版本
可以去官网或者一些网站下载,也可以直接在PostgreSQL安装路径下的“Application Stack Builder”中下载(更推荐后者的下载方式,可以直接选择下载对应的版本,但是这根据网上的说法好像要网不卡)
安装路径要和PostgreSQL的安装路径一样
输入在PostgreSQL安装时设置的username和password,还有端口号
弹出来的弹窗都选择“是”,这是自动设置了环境变量
安装Navicat Premium(要破解)
Navicat的版本可以下载高版本的,当版本较低,而PostSQL版本较高时会连接报错!Navicat的版本应比PostSQL的版本高!
1.3 安装PyCharm
我是直接通过联想的电脑管家直接进行傻瓜式安装
2 数据处理——PostGIS
2.1 数据来源
China Historical GIS(CHGIS (harvard.edu))
里面的数据包含基于wgs84的utf和gbk两种不同的编码,包含:历史行政区划点,到县一级;历史行政区划点,到州一级;历史政区面
2.2 数据入库
navicat连接pg库
空间扩展
navicat打开数据库postgres,这就是初始化的数据库
新建查询,执行
CREATE EXTENSION postgis
,为数据库添加空间扩展,会发现数据库中多了一表spatial_ref_sys
2.3 PostGIS工具上传shp
把utf8编码格式、wgs84坐标系的文件上传数据库,因为数据库一般都是utf-8编码的
- 打开PostGIS Shapefile Import/Export Manager
- View connection details连接PostSQL
- Add File上传shp文件再Import一下
3 查看数据
3.1 QGIS查看pg库中的数据
QGIS添加一个地图瓦片
Browser——XYZ Tiles——右键——New Connection,打开 XYZ Connection——把url粘贴进去
QGIS连接PostSQL并把shp数据加载进去
打开Data Source Manger,选择Vector,选择Database,下拉选择PostgreSQL,选择new,输入Connection Information,输入User name和Password,勾选store,Test Connection,显示连接成功,ok,ok,add
3.2 用Sql语法查看
打开Navicat
新建查询
1
2
3SELECT st_astext(geom) FROM v6_time_cnty_pts_utf_wgs84 LIMIT 1;
SELECT st_astext(geom) FROM v6_time_pref_pgn_utf_wgs84 LIMIT 1;
SELECT st_astext(geom) FROM v6_time_pref_pts_utf_wgs84 LIMIT 1查询结果一:POINT(111.079483 39.012409)
查询结果二:MULTIPOLYGON(((113.549411712145 36.7545434898289,113.543285553768 36.7521524539279,113.560044728209 36.7134634435762,113.55651873219 36.7287158304727,113.552914744172 36.7456842597138,113.549411712145 36.7545434898289)))
查询结果三:POINT(111.076347 39.017826)
4 数据处理——Python
用PostGIS可以很简单的就上传shp文件,但是由于导入shp文件没有字段备注和表说明,且如果字段名过长,还会截短字段名。所以为了规范化,用py脚本把数据读入PostgreSQL数据库中。
4.1 环境搭建
Python需要3个库包:gdal、shapely、psycopg2
这3个库包可以进入cmd利用命令行进行安装
1 | pip install gdal |
4.2 Python读取shp文件
读shp文件,并返回一个list方法,再把list写入一个文本txt中
1 | # coding=gbk |
4.3 PostSQL数据库中建表
直接将之前shp生成的txt文件作为源,写入数据库!进行两个步骤的操作:① 建表;② 插入
建表
建表的时候最好加上字段说明,顺便可以再加上索引
- public. v6_time_cnty_pts_utf_wgs84表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57--建表
CREATE TABLE public. v6_time_cnty_pts_utf_wgs84(
gid SERIAL8 PRIMARY KEY NOT NULL,
name_py varchar(40),
name_ch varchar(45),
name_ft varchar(45),
x_coor float8,
y_coor float8,
pres_loc varchar(60),
type_py varchar(15),
type_ch varchar(15),
lev_rank varchar(1),
beg_yr int8,
beg_rule varchar(1),
end_yr int8,
end_rule varchar(1),
note_id int8,
obj_type varchar(7),
sys_id int8,
geo_src varchar(10),
compiler varchar(12),
gecomplr varchar(10),
checker varchar(10),
ent_date varchar(10),
beg_chg_ty varchar(21),
end_chg_ty varchar(30),
geom geometry
);
--建立索引
CREATE INDEX v6_time_cnty_pts_utf_wgs84_index ON v6_time_cnty_pts_utf_wgs84 USING btree(gid);
--表说明
COMMENT ON TABLE public.v6_time_cnty_pts_utf_wgs84 IS '第6版中国历史地理时间序列点数据';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.gid IS '主键ID';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.name_py IS '拼音名称';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.name_ch IS '简体中文名称';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.name_ft IS '繁体中文名称';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.x_coor IS '经度';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.y_coor IS '纬度';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.pres_loc IS '现所在地';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.type_py IS '建制类型拼音';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.type_ch IS '建制类型简体中文';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.lev_rank IS '建制等级';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.beg_yr IS '建制开始时间';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.beg_rule IS '开始时间精度';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.end_yr IS '建制结束时间';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.end_rule IS '结束时间精度';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.note_id IS '系统id';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.obj_type IS 'geometry对象类型';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.sys_id IS '系统id';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.geo_src IS 'geometry数据来源';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.compiler IS '编辑人员';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.gecomplr IS '绘制人员';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.checker IS '审核人员';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.ent_date IS '结束时间';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.beg_chg_ty IS '建制开始原因';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.end_chg_ty IS '建制结束原因';
COMMENT ON COLUMN public.v6_time_cnty_pts_utf_wgs84.geom IS 'geometry对象';插入
插入一条数据进去
1
INSERT INTO v6_time_cnty_pts_utf_wgs84(name_py,name_ch,name_ft,x_coor,y_coor,pres_loc,type_py,type_ch,lev_rank,beg_yr,beg_rule,end_yr,end_rule,note_id,obj_type,sys_id,geo_src,compiler,gecomplr,checker,ent_date,beg_chg_ty,end_chg_ty,geom) VALUES('Luowubu','罗婺部','羅婺部',102.40378,25.88668,'云南省禄劝彝族苗族自治县西北七十二里云龙','Bu','部','6',960,null,1253,null,80317,' POINT',80317,'FROM_FD',null,null,null,null,'新建','撤销',st_geomfromtext('POINT(102.4037799950270653 25.88667999033716072)',4326))
4.4 Python把生成的txt文件写入PostSQL数据库
测试一下能不能连接成功
1
2
3
4
5
6# coding=gbk
import psycopg2
conn = psycopg2.connect(database="mapdata", user="postgres", password="123456", host="127.0.0.1", port="5432")
print('连接成功')连接成功之后,就可以把在4.2生成的txt文件写入PostSQL数据库了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96# 建立游标
cur = conn.cursor()
f=open(r'E:\develop_gis\map website\data\V6 Time Series County Points\v6_time_cnty_pts_utf_wgs84\v6_time_cnty_pts_utf_wgs84.txt','r',encoding='utf-8')
# 按行读入txt
flines=f.readlines()
for line in flines:
# 去掉干扰,切词
abbrlist=line.replace("'"," ").split('\t')
# name_py,name_ch,name_ft,x_coor,y_coor,pres_loc,type_py,type_ch,lev_rank,beg_yr,beg_rule,end_yr,end_rule,note_id,obj_type,sys_id,geo_src,compiler,gecomplr,checker,ent_date,beg_chg_ty,end_chg_ty,geom
name_py='null'
if (abbrlist[0]!=''):
name_py="'"+abbrlist[0]+"'"
name_ch='null'
if (abbrlist[1]!=''):
name_ch="'"+abbrlist[1]+"'"
name_ft='null'
if (abbrlist[2]!=''):
name_ft="'"+abbrlist[2]+"'"
x_coor='null'
if (abbrlist[3]!=''):
x_coor=abbrlist[3]
y_coor='null'
if (abbrlist[4]!=''):
y_coor=abbrlist[4]
pres_loc='null'
if (abbrlist[5]!=''):
pres_loc="'"+abbrlist[5]+"'"
type_py='null'
if (abbrlist[6]!=''):
type_py="'"+abbrlist[6]+"'"
type_ch='null'
if (abbrlist[7]!=''):
type_ch="'"+abbrlist[7]+"'"
lev_rank='null'
if (abbrlist[8]!=''):
lev_rank="'"+abbrlist[8]+"'"
beg_yr='null'
if (abbrlist[9]!=''):
beg_yr=abbrlist[9]
beg_rule='null'
if (abbrlist[10]!=''):
beg_rule="'"+abbrlist[10]+"'"
end_yr='null'
if (abbrlist[11]!=''):
end_yr=abbrlist[11]
end_rule='null'
if (abbrlist[12]!=''):
end_rule="'"+abbrlist[12]+"'"
note_id='null'
if (abbrlist[13]!=''):
note_id=abbrlist[13]
obj_type='null'
if (abbrlist[14]!=''):
obj_type="'"+abbrlist[14]+"'"
sys_id='null'
if (abbrlist[15]!=''):
sys_id=abbrlist[15]
geo_src='null'
if (abbrlist[16]!=''):
geo_src="'"+abbrlist[16]+"'"
compiler='null'
if (abbrlist[17]!=''):
compiler="'"+abbrlist[17]+"'"
gecomplr='null'
if (abbrlist[18]!=''):
gecomplr="'"+abbrlist[18]+"'"
checker='null'
if (abbrlist[19]!=''):
checker="'"+abbrlist[19]+"'"
ent_date='null'
if (abbrlist[20]!=''):
ent_date="'"+abbrlist[20]+"'"
beg_chg_ty='null'
if (abbrlist[21]!=''):
beg_chg_ty="'"+abbrlist[21]+"'"
end_chg_ty='null'
if (abbrlist[22]!=''):
end_chg_ty="'"+abbrlist[22]+"'"
geom='null'
if (abbrlist[23]!=''):
geom="st_geomfromtext('"+abbrlist[23]+"',4326)"
# 拼接sql语句
sqltxt="INSERT INTO v6_time_cnty_pts_utf_wgs84(" \
"name_py,name_ch,name_ft,x_coor,y_coor,pres_loc,type_py,type_ch,lev_rank,beg_yr,beg_rule," \
"end_yr,end_rule,note_id,obj_type,sys_id,geo_src,compiler,gecomplr,checker,ent_date," \
"beg_chg_ty,end_chg_ty,geom) VALUES("+name_py+","+name_ch+","+name_ft+","+x_coor+","+y_coor+","\
+pres_loc+","+type_py+","+type_ch+","+lev_rank+","+beg_yr+","+beg_rule+","+end_yr+","+end_rule+","\
+note_id+","+obj_type+","+sys_id+","+geo_src+","+compiler+","+gecomplr+","+checker+","+ent_date+","\
+beg_chg_ty+","+end_chg_ty+","+geom+")"
print(sqltxt)
# 执行sql
cur.execute(sqltxt)
# 关闭连接
conn.commit()
conn.close()
print('插入完成')
4.5 总结流程
用python处理数据的流程:先把python的环境搭建好,然后读取shp文件,与此同时会返回一个txt的文件;接着,在PostSQL中建表,并插入一条数据测试;然后,用python连接数据库,把生成的txt文件写入数据库中!
Python读shp文件==》返回txt文件==》PostSQL数据库中建表==》插入一条数据==》Python连接数据库==》txt文件写入数据库
简单总结就两步:
- shp文件导出txt
- txt文件导入pg数据库
5 上传代码到GitHub
在GitHub上面新建一个仓库
选择本地需要上传的文件夹作为本地仓库,右键
git bash here
敲命令行上传代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37-----------------------------
-----------------------------
# 上传本地的文件到GitHub仓库
# 初始化
git init
# 把GitHub上面的仓库克隆下来
git clone https://github.com/xxxxx/historymap.git
# 把本地文件添加到暂存区
git add .
# 将暂存区的文件添加到仓库中
git commit -m "first commit"
# 将仓库中的文件提交提交到远程仓库
git push origin main
------------------------------
------------------------------
# 删除GitHub仓库中的文件
# 查看有哪些文件
dir
# 删除一个文件
git rm -r --cached xxx
git rm -r --cached xxxx
git rm -r --cached xxxxx
# 提交删除信息,添加操作说明
git commit -m "delete"
# push到GitHub仓库
git pushgit push origin main/git push -u origin main和git push -u origin master有什么区别
为什么后者代码数据传不上去,参考链接:git push -u origin master 与git push –set-upstream origin master_yzpyzp的博客-CSDN博客
新建的仓库的默认分支从master变成了main,至于origin,就是远程仓库的别名,github把远程仓库的名称默认称为origin,自己也可以改为其他名称,就像GitHub之前仓库的默认分支叫做master,而现在改为main
git push -u
是git push --set-upstream
的缩写版本;(upstream 是指本地分支与远程仓库中的分支之间的流通道,建立流通道就是建立本地分支与远程分支的关联,建立之后,后续就可以直接使用git push指令把本地分支的commit推到远程分支中)git push -u origin main
的作用:先把本地的当前分支推送到远程仓库origin的main分支
再把本地的当前分支关联到远程仓库origin的main分支
相当于
git push origin main
加上git branch --set-upstream-to=origin/main main
的作用,即先把本地分支push到远程仓库中,然后再建立本地分支与远程分支的关联。
不带任何参数的
git push
,默认只推送当前分支推送代码时,经常会报以下两个错误:
- ```
fatal: unable to access ‘https://github.com/xxxxx/historymap.git/': Failed to connect to github.com port 443 after 22072 ms: Timed out1
2
3
4
- ```
error: src refspec master does not match any
error: failed to push some refs to 'https://github.com/xxxxx/historymap.git'
这是网络的原因,GitHub网站经常会出现打不开的问题
- ```