《Python地理空间分析指南 第2版》学习笔记-5.7空间信息可视化

13 篇文章 4 订阅
6 篇文章 0 订阅

5.7.1点密度计算

点密度地图表达了给定区域内点状符号的密度。
本次案例使用PNGCanvas模块输出地图。

数据
在这里插入图片描述

"""Create a dot-density thematic map"""
import random
import pngcanvas
import shapefile

# 判断一个点是否在多边形内部
def point_in_poly(x, y, poly):
    # 判断该点是否是顶点
    if (x, y) in poly:
        return True
    # 判断该点是否在多边形边界
    for i in range(len(poly)):
        p1 = None
        p2 = None
        if i == 0:
            p1 = poly[0]
            p2 = poly[1]
        else:
            p1 = poly[i - 1]
            p2 = poly[i]
        if p1[1] == p2[1] and p1[1] == y and \
                x > min(p1[0], p2[0]) and x < max(p1[0], p2[0]):
            return True
    n = len(poly)
    inside = False

    p1x, p1y = poly[0]
    for i in range(n + 1):
        p2x, p2y = poly[i % n]
        if y > min(p1y, p2y):
            if y <= max(p1y, p2y):
                if x <= max(p1x, p2x):
                    if p1y != p2y:
                        xints = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
                    if p1x == p2x or x <= xints:
                        inside = not inside
        p1x, p1y = p2x, p2y

    if inside:
        return True
    else:
        return False


def world2screen(bbox, w, h, x, y):
    # 地理左边转换为屏幕坐标
    minx, miny, maxx, maxy = bbox
    xdist = maxx - minx
    ydist = maxy - miny
    xratio = w / xdist
    yratio = h / ydist
    px = int(w - ((maxx - x) * xratio))
    py = int((maxy - y) * yratio)
    return (px, py)

if __name__ == '__main__':
    # 打开人口普查矢量文件
    inShp = shapefile.Reader(r"GIS_CensusTract/GIS_CensusTract_poly")

    # 设置输出图片尺寸
    iwidth = 600
    iheight = 400
	#============1、读取属性====================
    # 获取人口记录索引
    pop_index = None
    dots = []

    for i, f in enumerate(inShp.fields):
    	#找到人口字段的索引
        if f[0] == "POPULAT11":
            # 声明删除标记
            pop_index = i - 1

    # 计算点密度并绘制相关点,生成的所有点都存储在dots中,利用point_in_poly函数来判断是否在要素内
    for sr in inShp.shapeRecords():
        population = sr.record[pop_index]
        # Density ratio - 1 dot per 100 people
        # 点密度比例,一个点代表100人
        density = population / 100
        found = 0
        # 绘制随机点,直到密度达到指定比率
        while found < int(density):
            minx, miny, maxx, maxy = sr.shape.bbox
            #生成随机点
            x = random.uniform(minx, maxx)
            y = random.uniform(miny, maxy)
            #判断随机点是否在要素内,在就添加到dots中
            if point_in_poly(x, y, sr.shape.points):
                dots.append((x, y))
                found += 1

    # 为输出png图片做准备,设置长和宽
    c = pngcanvas.PNGCanvas(iwidth, iheight)

    # 绘制红色的点
    c.color = (255, 0, 0, 0xff)
    for d in dots:
        x, y = world2screen(inShp.bbox, iwidth, iheight, *d)
        c.filled_rectangle(x - 1, y - 1, x + 1, y + 1)
	#============2、读取图形====================
    # 绘制人口普查区域
    c.color = (0, 0, 0, 0xff)
    for s in inShp.iterShapes():
        pixels = []
        for p in s.points:
            pixel = world2screen(inShp.bbox, iwidth, iheight, *p)
            pixels.append(pixel)
        c.polyline(pixels)

    # 保存图片
    with open(r"GIS_CensusTract/DotDensity1.png", "wb") as img:
        img.write(c.dump())

最终结果:
在这里插入图片描述

5.7.2 等值区域图

等值区域图也是一种用于显示密度的地图,但它们是使用阴影和颜色来表达密度的。

本示例将根据上一个点密度示例重新创建一张等值区域图。将根据人口普查区域每平方公里的人口得出密度比率,然后根据该比率配置相应的颜色。颜色越深的区域人口密度越大,反之亦然。

import math
import shapefile

try:
    import Image
    import ImageDraw
except:
    from PIL import Image,ImageDraw

def world2screen(bbox, w, h, x, y):
    # 地理坐标转换为屏幕坐标
    # bbox 外接矩形范围
    # w 宽度 h 高度
    # x,y 坐标
    minx, miny, maxx, maxy = bbox
    xdist = maxx - minx
    ydist = maxy - miny

    xratio = w / xdist
    yratio = h / ydist
    px = int(w - ((maxx - x) * xratio))
    py = int((maxy - y) * yratio)
    return (px, py)

if __name__ == '__main__':
    # 打开shapefile文件
    inputShp = shapefile.Reader(r"GIS_CensusTract/GIS_CensusTract_poly")

    #定义输出图片的大小
    iwidth = 600
    iheight = 400

    # 初始化PIL库的Image对象
    img = Image.new("RGB",(iwidth,iheight),(255,255,255))
    # PIL库的Draw模块用于填充多边形
    draw = ImageDraw.Draw(img)

    #设置人口和面积索引
    pop_index = None
    area_index = None
    #获取人口普查区阴影
    # print(inputShp.fields)
    for i,f in enumerate(inputShp.fields):
        # print(i,f)
        if f[0] == "POPULAT11":
            pop_index = i - 1
        elif f[0] == "AREASQKM":
            area_index = i - 1

    #绘制多边形
    for sr in inputShp.shapeRecords():
        #计算密度
        density = sr.record[pop_index]/sr.record[area_index]
        # print(density)
        # 计算权重
        weight = min(math.sqrt(density / 80.0), 1.0) * 50
        R = int(205 - weight)
        G = int(215 - weight)
        B = int(245 - weight)
        # print(R,G,B)
        pixels = []
        for x,y in sr.shape.points:
            # 地理坐标转换为屏幕坐标
            (px, py) = world2screen(inputShp.bbox, iwidth, iheight, x, y)
            pixels.append((px, py))
        # 绘制
        draw.polygon(pixels, outline=(255, 55, 255), fill=(R, G, B))

    img.save(r"GIS_CensusTract/choropleth1.png")


绘制结果:
在这里插入图片描述


本节介绍了点密度计算和等值区域图。

《Python地理空间分析指南 第2版》学习笔记,仅供学习,如有侵权请联系删除。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值