基于ArcGis利用Python制作分幅索引表

        在日常工作中,经常需要制作分幅接图表,以方便使用者查阅。对于图斑数量少、分布相对均匀的地图,使用分幅接图表能够清晰明了的展示图斑分幅情况,而对于图斑面积较小、数量较多、相对集中的地图,使用分幅接图表就显得较为密集臃肿,难以区分哪个图幅包含哪些图斑。针对以上弊端,基于ArcGis软件提供的ArcPy接口,结合Python的os、xlwt模块,向大家介绍如何以表格的形式“自动批量”制作分幅索引表,清晰明了展现地图分幅情况。

凯里市退化乔木林分幅索引表
图幅号小班号
凯里市湾水镇翁凼村11
凯里市凯棠乡凯哨村22
凯里市湾水镇翁凼村33
凯里市湾水镇翁凼村、鱼良村44
凯里市旁海镇旁海村55
凯里市湾水镇翁凼村66、7

        ArcGis使用的是Python2.X版本,2.X版本已不再更新,2.X与3.X采用的编码格式完全不同。2.X使用ascii编码,3.X使用unicode,编码格式的不同会导致什么结果?就是能否有效的识别中文。如果你使用的是ArcGis,你就需要在代码开头以# -*-coding:utf-8 -*-或者# coding:utf-8的方式,指定编码方式,如果你使用的是ArcGis Pro,那么恭喜你,你完全不用为编码格式发愁,你只管哐哐哐敲代码。

1 制作标题行       

        Python提供的os模块主要用于处理目录和文件,xlwt模块主要用于将数据写入工作表。当然ArcGis Pro可以有更多的选择,如openpyxl、pandas等。xlwt只能处理“.xls”格式的工作簿,openpyxl只能处理“.xlsx”格式的工作簿,在写文件名的时候如果没有分清楚,软件将会报错。

        通常,工作表的标题为“XXX工程图幅索引表”,直接是用write_merge()方法写入即可。标题行相对灵活,以列表[u"县", u"乡", u"村", u"图幅号", u"小班号"]的形式,使用for循环逐个写入即可,由于ArcGis使用的是ascii编码格式,需在中文字符串前加上u,以声明编码格式为“utf-8”。xlwt模块行列起始值为0,openpyxl模块行列起始值为1。 

# 创建工作簿
wb = xlwt.Workbook(encoding='utf-8')
# 添加工作表
ws = wb.add_sheet(sheet_name, cell_overwrite_ok=True)
# 添加标题并按标题行的长度合并单元格
ws.write_merge(0, 0, 0, len(hearder_line)-1, sheet_title)
# 写入标题行
for col in range(len(hearder_line)):
    ws.write(1, col, hearder_line[col])

2 获取数据

        如何获取数据,才能保证数据不会重复,使用arcpy.da.SearchCursor()查询游标结合字典get()方法,获取每一行数据。get(key, default)方法有两个参数,key为键,当键key不存在时,将键key的值设置为default。这里将默认值设置为列表,列表相加就是将一个列表的元素加入到另一个列表。小班号数据类型为长整型,这里将小班号转换成字符串型,主要是方便后面字符串的拼接。

xians = {}; xiangs = {}; cuns = {}; page_numbers = {}; xiao_bans = {}
with arcpy.da.SearchCursor(in_feature, fields) as cursor:
    for row in cursor:
        key = row[3]
        xians[key] = xians.get(key, []) + [row[0]]
        xiangs[key] = xiangs.get(key, []) + [row[1]]
        cuns[key] = cuns.get(key, []) + [row[2]]
        xiao_bans[key] = xiao_bans.get(key, []) + [str(row[4])]

3 写入索引表

        以图幅号为键,分别将县、乡、村、图幅号、小班号写入对应的单元格,这里需要说明一点,在使用set()函数去重时,会打乱列表原有顺序,为保证去重后仍然保持列表原有顺序,需使用sorted()函数,指定排序关键字为原有列表索引。

for key in xians.keys():
    # 写入县字段
    xian = sorted(list(set(xians[key])), key=xians[key].index)
    ws.write(key + 1, 0, "、".join(xian))
    # 写入乡字段
    xiang = sorted(list(set(xiangs[key])), key=xiangs[key].index)
    ws.write(key + 1, 1, "、".join(xiang))
    # 写入村字段
    cun = sorted(list(set(cuns[key])), key=cuns[key].index)
    ws.write(key + 1, 2, "、".join(cun))
    # 写入图幅编号字段
    ws.write(key + 1, 3, key)
    # 写入小班号字段
    ws.write(key + 1, 4, "、".join(xiao_bans[key]))

wb.save(save_path)

4 结论 

        dict.get(key, default)的使用:如果键存在,返回键所对应的值,如果键不存在,返回设置的默认值。get()可以用在统计数量上,如d[k] = d.get(k, 0)+1,或者嵌套列表、字典等可迭代对象一起使用,如d[k]=d.get(k, [])+[]、d[k]=d.get(k, {}).get(k)等。

        sorted(iterable, key)的使用:iterable为可迭代对象,key为排序的关键字,传入原对象的索引,保证新对象的序列与原对象一致,也常与匿名函数lambda x:x[0]一起使用。sort()是对实例进行操作,改变实例的顺序,无返回值;sorted()返回排序后的新序列,没有修改原对象。        

# -*- coding:utf-8 -*-
import arcpy
import os
import xlwt
import sys

reload(sys)
sys.setdefaultencoding('utf-8')
def make_map_set(in_feature, save_path, sheet_name, sheet_title, hearder_line, fields):
    """
        in_feature: 输入要素类
        save_path:输出表存储位置
        sheet_name:表名
        sheet_title:表标题
        hearder_line:表标题行
        fields:标题对应要素类字段
    """
    wb = xlwt.Workbook(encoding='utf-8')
    ws = wb.add_sheet(sheet_name, cell_overwrite_ok=True)
    ws.write_merge(0, 0, 0, len(hearder_line)-1, sheet_title)
    for col in range(len(hearder_line)):
        ws.write(1, col, hearder_line[col])

    xians = {}; xiangs = {}; cuns = {}; page_numbers = {}; xiao_bans = {}
    with arcpy.da.SearchCursor(in_feature, fields) as cursor:
        for row in cursor:
            key = row[3]
            xians[key] = xians.get(key, []) + [row[0]]
            xiangs[key] = xiangs.get(key, []) + [row[1]]
            cuns[key] = cuns.get(key, []) + [row[2]]
            xiao_bans[key] = xiao_bans.get(key, []) + [str(int(row[4]))]

    for key in xians.keys():
        # 填写县字段
        xian = sorted(list(set(xians[key])), key=xians[key].index)
        ws.write(key + 1, 0, "、".join(xian))
        # 填写乡字段
        xiang = sorted(list(set(xiangs[key])), key=xiangs[key].index)
        ws.write(key + 1, 1, "、".join(xiang))
        # 填写村字段
        cun = sorted(list(set(cuns[key])), key=cuns[key].index)
        ws.write(key + 1, 2, "、".join(cun))
        # 填写图幅编号字段
        ws.write(key + 1, 3, key)
        # 填写小班号字段
        ws.write(key + 1, 4, "、".join(xiao_bans[key]))

    wb.save(save_path)

if __name__ == "__main__":
    try:
        in_feature = u"F:\XXX.gdb\XXX"
        save_path = u"F:\XXX.xls"
        sheet_name = os.path.basename(save_path).split(".")[0]
        sheet_title = os.path.basename(save_path).split(".")[0]
        # 标题行与要素类中字段一一对应
        hearder_line = [u"县", u"乡", u"村", u"图幅号", u"小班号"]
        fields = [u"县", u"乡", u"村", u"PageNumber", u"小班号"]
        make_map_set(in_feature, save_path, sheet_name, sheet_title, hearder_line, fields)
    except Exception as e:
        print(e.message)

         在这里顺便讨论下,什么是方法,什么又是函数?个人理解为,要分清函数和方法可以从调用方式入手,采用"实例.方法名(形参1,形参2,..)"方式调用即为方法,采用"函数名(形参1,形参2,...)"方式调用即为函数。 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值