简介:本文以Python地理空间分析指南(第2版)第一章为基本,对于书中出现的概念只是简要的说明,大家如果不懂可以自行补充,此文主要以程序分析为基本,用到的python版本为3.9。此节对于程序SimpleGIS为重点,进行了全面的刨析,以及所需要的turtle库进行的简单讲解。

基本概念

        本书第一章介绍了GIS与遥感方面基本概念,如地信与遥感的概念、矢量数据栅格数据的介绍,对于地信人员来说是基础。如果你还不是对地信与遥感这方面特别熟练,推荐着重学习一些相关软件如Arcgis与ENVI,实践学习相结合更好的帮助自己理解并学习掌握这方面内容,为接下来学习做准备。

SimpleGIS所涉及的库

        对于简单的Python没有太多概述,建议大家可以自学,能够使用列表、字典、类、函数即可;本章设计的库为turtle库,用到的代码如下:

turtle.up()——抬起画笔(在移动过程中不会画线)

turtle.down()——画笔落下(将抬起的画笔放下,使能在屏幕绘制线条)

turtle.goto(x,y)——移动画笔至(x,y)点

turtle.write()——写入文本

turtle.dot()——画点(在屏幕上标记出点)

turtle.done()——持续打开图画

turtle.pen(shown=False)——隐藏光标

其他turtle库以及各种参数请参考turtle --- 海龟绘图 — Python 3.10.8 文档

SimpleGIS解析 

导入turtle,并赋值变量。

import turtle as t
NAME=0
POINTS=1
POP=2

建立一个包含科罗拉多州城市、坐标、人口的列表。

state=["科多里达",[[-109,37],[-109,41],[-102,41],[-102,37]],5187582]

创建一个城市空列表,将3个城市信息(包含名字、坐标、人口)分别建立三个列表并添加到城市列表中。

cities=[]
cities.append(['DENVER',[-104.98,39.71],634265])
cities.append(['BOULDER',[-105.27,40.02],98889])
cities.append(['DURANGO',[-107.88,37.28],17069])

采用赋值变量的形式定义地图尺寸。

map_width=400
map_height=300

确保州尺寸在地图中,如果不在将自动调整。

  1. 这里最大/小x,y代表的为经纬度(以°为单位),东西经各180°则分为±180°,南北纬同理。我们定义到xy的最大最小值范围。
  2. 使用for循环,前面我们定义过POINTS=1,这里索引state[POINTS]表示索引state列表第二个值第二个值为四个点组成的列表,即[[-109,37],[-109,41],[-102,41],[-102,37]]。从这里x,y将继续索引四个点组成的列表,首先索引[-109,37]其次[-109,41]直至索引到最后,第一次索引时会给x赋值为-109,y赋值为37,之后的索引的类似。
  3. 我们要确保的周边界并不是地球的边界,所以采用if条件语句改变minx/miny/maxx/maxy的边界为州边界。
minx=180
maxx=-180
miny=90
maxy=-90
for x,y in state[POINTS]:
    if x<minx:
        minx=x
    elif x>maxx:
        maxx=x
    if y <miny:
        miny=y
    elif y>maxy:
        maxy=y

计算州和绘图版的缩放比例

  1. 要将地图显示到州的范围,此外我们输入的数据是经纬度坐标,而屏幕显示的是400*300的画布,需要进行经纬度与画布的宽高(400*300)的转化。
  2. 求x,y(经纬度坐标)在的总长得到dist_x与dist_y。例:maxx=-102°,minx=-107°因此总长应为dist_x=-102°-(-107°)=5°
  3. 分别计算经纬度1°等于画布的长度为多少。例:上例中的总长为5°我们用画布的宽400做计算x_ratio=map_width/dist_x=400/5=80。
dist_x=maxx-minx
dist_y=maxy-miny
x_ratio=map_width/dist_x
y_ratio=map_height/dist_y

定义convert函数,使用缩放比例将经纬度转换为平面坐标,类似于转换投影坐标系。

  1. 这里的定义函数前三行代表意思的为定义一个函数,这个函数形参为一个列表,前两个值应该为lon和lat即经纬度。
  2. 3、4行则表示转化过来的点x、y应该在画布的什么位置(从经纬度转化到画布上位置)。maxx-lon表示经度为在州的范围内所处的位置(锁定州的范围后,坐标系不是从0开始的而且从minx开始的)。例:假设州的范围为-107~-102°E,27°~39°N,输入点坐标为(-105,30),以经度为例maxx-lon=-102-(-105)=3°,所得结果为点值州最大边界的距离。即-105至-102的距离。
  3. 得到输入点至边界的最大距离后将其*x_ratio表示将经纬度距离转到画布距离。以上文为例:3°*80=240,即输入点到画布最大值边界距离为240
  4. 用map_width-点到画布最大值边界距离即可获得输入点在画布的x坐标。例:400-240=160此时该点在画布的x坐标为160。同理获得y坐标。
  5. 5、6行表示移动到中心位置,画布开始位置(0,0)点位于边界的左下角,要调整(0,0)点为画布中心。
def convert(point):
    lon=point[0]
    lat=point[1]
    x=map_width-((maxx-lon)*x_ratio)
    y=map_height-((maxy-lat)*y_ratio)
    x=x-(map_width/2)
    y=y-(map_height/2)
    return [x,y]

Python中空间点怎么表示 python空间分析_python

 
打印州的区域

  1. state[POINTS]代表州的四个点坐标组成的列表,用for循环遍历这个列表。每次循环获得一个点坐标point。
  2. 在一次循环中调用convert函数让pixel为转换后的坐标,并用if条件语句判断第一个点,以便闭合(下面的t.goto()在闭合时需要第一个点的位置),转换后使用t.goto()定位到该点,并用t.down()使画笔落下,移动时进行画线。将循环执行完。
  3. 这里的if语句,开始定义了一个first_pixel=None,让first_pixel为空,if not first_pixel表示如果first_pixel没有值时将执行...。在这里第一次循环获得第一个点后,第二次循环first_pixel将有值if语句将不再执行。
  4. 循环结束后,继续定位到第一个点first_pixel并用t.up()抬起画笔不再画线。
  5. 定位到(0,0)画布中心,使用t.write()书写州的各种信息。
t.up()
first_pixel=None
for point in state[POINTS]:
    pixel=convert(point)
    if not first_pixel:
        first_pixel=pixel
    t.goto(pixel)
    t.down()
t.goto(first_pixel)
t.up()
t.goto([0,0])
t.write(state[NAME],align='center',font=('Arial',16,'bold'))

绘制城市各个城市

for city in cities:
    pixel=convert(city[POINTS])
    t.up()
    t.goto(pixel)

  绘制城市位置

t.dot(10,'red')

标记城市

t.write(f'城市:{city[NAME]}人口:{city[POP]}',align='left')
    t.up()

查询人口最多的城市

biggest_city=max(cities,key=lambda city:city[POP])
t.goto(0,-200)
t.write(f'人口最多的城市是{biggest_city[NAME]}')

查询离西部最远的城市

western_city=min(cities,key=lambda city:city[POINTS])
t.goto(0,-220)
t.write(f'最靠近西的为{western_city[NAME]}')

隐藏光标并持续打开
 

t.pen(shown=False)
t.done()

原码

'''导入turtle'''
 import turtle as t
 NAME=0
 POINTS=1
 POP=2
 '''一个包含科罗拉多州城市、坐标、人口的列表'''
 state=["科多里达",[[-109,37],[-109,41],[-102,41],[-102,37]],5187582]
 '''城市信息'''
 cities=[]
 cities.append(['DENVER',[-104.98,39.71],634265])
 cities.append(['BOULDER',[-105.27,40.02],98889])
 cities.append(['DURANGO',[-107.88,37.28],17069])
 '''定义地图尺寸'''
 map_width=400
 map_height=300
 '''确保州尺寸在地图中,如果不在自动调整'''
 minx=180
 maxx=-180
 miny=90
 maxy=-90
 for x,y in state[POINTS]:
     if x<minx:
         minx=x
     elif x>maxx:
         maxx=x
     if y <miny:
         miny=y
     elif y>maxy:
         maxy=y
 '''计算州和绘图版的缩放比例'''
 dist_x=maxx-minx
 dist_y=maxy-miny
 x_ratio=map_width/dist_x
 y_ratio=map_height/dist_y
 '''convert函数,使用缩放比例将经纬度转换为XY坐标'''
 def convert(point):
     lon=point[0]
     lat=point[1]
     x=map_width-((maxx-lon)*x_ratio)
     y=map_height-((maxy-lat)*y_ratio)
     x=x-(map_width/2)
     y=y-(map_height/2)
     return [x,y]
 '''打印区域'''
 t.up()
 first_pixel=None
 for point in state[POINTS]:
     pixel=convert(point)
     if not first_pixel:
         first_pixel=pixel
     t.goto(pixel)
     t.down()
 t.goto(first_pixel)
 t.up()
 t.goto([0,0])
 t.write(state[NAME],align='center',font=('Arial',16,'bold'))
 '''绘制城市'''
 for city in cities:
     pixel=convert(city[POINTS])
     t.up()
     t.goto(pixel)
     # 绘制城市位置
     t.dot(10,'red')
     # 标记城市
     t.write(f'城市:{city[NAME]}人口:{city[POP]}',align='left')
     t.up()
 # 查询人口最多
 biggest_city=max(cities,key=lambda city:city[POP])
 t.goto(0,-200)
 t.write(f'人口最多的城市是{biggest_city[NAME]}')
 # 哪个离西部最远
 western_city=min(cities,key=lambda city:city[POINTS])
 t.goto(0,-220)
 t.write(f'最靠近西的为{western_city[NAME]}')
 # 隐藏光标并持续打开
 t.pen(shown=False)
 t.done()