Python和ArcGIS自动化制图完全指南(四):自动制图
作者:互联网
Python和ArcGIS自动化制图完全指南(四):自动制图
前言:在完成了《指南》第二章和第三章后,终于来到了制图。运用 python 和 arcpy 自动化完成 mxd 模板图层定义查询语句的自动更新、图框的自动居中、比例尺的校正、另存mxd等操作。 |
关键字:python、arcpy、mxd
PAGESIZE 字段是 定义查询 语句中使用的字段。作用是给每个 mxd 模板分配任务。
文章目录
1.限制 MXD 模板
《指南》第三章做的努力在这里得到了显现,在第三章中,我们根据大小、面积等规则给每个制图单位分配了合适的 mxd 模板,其信息就储存在 PAGESIZE 字段中,其值就是给该制图单位分配的模板的名字。
如下图所示,巴中市的 PAGESIZE 值是1180x900,表示给巴中市分配的制图模板是是1180x900.mxd.
但是细心的读者可能已经发现了,目前为止,仅仅只是更新了 mappingIndex 图层的 PAGESIZE 字段,而每一个 mxd 模板都是没有限制的,它可以生成我们所有17个地级市的地图,这显然是不对的。
在这里我们需要对每一个 mxd 模板文件作出限制。
所以每一个 mxd 模板文件都要在 MappingIndex 图层中设置定义查询语句。而查询语句就是模板名称。
如下所示:
如果还是不太明白,读者可以手动去给 MappingIndex 图层设置定义查询语句,看看会发生什么。
代码C1如下:
# -*- coding:utf-8 -*-
# Author: LiaoChenchen
from __future__ import absolute_import
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
import arcpy
import os
"""__________________________________________________________________________"""
"""____________________________global_values_________________________________"""
# 地址
mxd_template = r"E:\doc\Scratch\tempMXDS" # 模板文件位置
output_dir = r"E:\doc\Scratch\out" # 输出位置
gdb_path = r"E:\doc\Scratch\arcpy指南.gdb" # 数据库地址
# 重要常量
FIELD = "CITY" # 检索字段
MI = "MappingIndex" # 制图索引文件名称
SCALE = 200000 # 制图的比例尺
"""____________________________global_values_________________________________"""
"""__________________________________________________________________________"""
arcpy.env.overwriteOutput = True
arcpy.env.workspace = gdb_path
class MakeMXD(object):
def __init__(self,mapdocument, layers_names, mappindex_name, query_fielf, scale=None):
"""
:param mapdocument: {Object} MXD文件对象
:param layers_names: {List} 需要设置定义查询语句图层的名称列表
:param mappindex_name: {String} 索引图层名字;MappingIndex
:param query_fielf: {String} 定义查询使用的字段名;CITY
:param scale: {Int} 比例尺
"""
self.mxd = mapdocument
self.df = arcpy.mapping.ListDataFrames(self.mxd)[0]
self.layers = layers_names
self.index_name = mappindex_name
self.field = query_fielf
self.scale = scale
self.mapindex_lyr = arcpy.mapping.ListLayers(self.mxd,self.index_name)[0]
self.mapping_index_query()
self.make_mxd()
del self.mxd
def mapping_index_query(self): # ▶注释一◀
"""
给 MappingIndex 图层设置定义查询语句; PAGESIZE = '1080x700'
:return:
"""
map_path = self.mxd.filePath
name = os.path.splitext(os.path.basename(map_path))[0] # 1080x700 ▶注释二◀
definition_query = ["PAGESIZE"," = ","'",name,"'"]
self.size = name
self.mapindex_lyr.definitionQuery = "".join(definition_query) # ▶注释三◀
▶注释一◀:目前这里我们只需要关注方法 mapping_index_query,上面的初始化方法等拉通梳理一遍后再看。
▶注释二◀:name 就是模板文件的名字(不包括后缀名)。
▶注释三◀:"".join(LIst) 比一般的字符串拼接速度快。
2.遍历制图单位
对 mxd 模板文件进行限制处理后,就需要把与该模板匹配的制图单位导出来了。
一个 mxd 模板通常对应了几个制图单位。
比如 1080x1300.mxd 这个模板对应着达州市、绵阳市、雅安市三个制图单位。所以我们要遍历循环来处理,说白话就是一个一个处理。
2.1定义查询
代码C2如下:
class MakeMXD(object):
... # ▶注释一◀
def make_mxd(self):
with arcpy.da.SearchCursor(self.mapindex_lyr, self.field) as cursor:
for row in cursor:
name = row[0]
self.define_query(name) # 定义查询
self.center_scale(name) # 居中
self.change_txt(name) # 修改文本
self.label_query(name) # 标注查询语句
arcpy.SelectLayerByAttribute_management(self.mapindex_lyr, "CLEAR_SELECTION") # 取消该图层的所有选择选择项目
self.saveacopy(name) # 另存
def define_query(self, value):
"""
定义查询
:param value: {String/Int/Float} 用于定义查询的值
:return: None
"""
for layer in self.layers:
lyr = arcpy.mapping.ListLayers(self.mxd, layer)[0]
d_q = ['"',self.field,'"'," = ","'",value,"'"] # ▶注释二◀
lyr.definitionQuery = "".join(d_q)
▶注释一◀:上文的代码。
▶注释二◀:self.field 即字段 CITY;定义查询语句例如:CITY = '达州市’
2.2图层居中
使该制图单位居于布局的中央
代码C3如下:
class MakeMXD(object):
...
def center_scale(self, name):
"""
使图框居中并设置比例尺
:param name: {String/Int/Float} 用于查询语句的值
:return: None
"""
where_clause = "{} = '{}'".format(self.field, name)
arcpy_slba = arcpy.SelectLayerByAttribute_management # ▶注释一◀
arcpy_slba(self.mapindex_lyr, "NEW_SELECTION", where_clause)
self.df.extent = self.mapindex_lyr.getSelectedExtent()
if self.scale:
self.df.scale = self.scale
▶注释一◀:选中当前的制图单位,然后居中。self.df.extent 指图框的范围。
2.3修改文本
将原地图标题如:XX市铁路交通分布演示草图 修改成 成都市铁路交通分布演示草图。
class MakeMXD(object):
...
def change_txt(self, name):
# 修改文本
for elm in arcpy.mapping.ListLayoutElements(self.mxd, 'TEXT_ELEMENT'):
if elm.text == "XX市铁路交通分布演示草图":
elm.text = "XX市铁路交通分布演示草图".replace("XX市", name)
2.4标注查询语句
每一个地级市都设置了标注以显示名称,如果当前制图单位就是该地级市,可以不用再显示该地级市的标注。
如下图的中间的资阳市,就不显示标注:
使特定的区域标注不显示,代码C4如下:
class MakeMXD(object):
...
def label_query(self,name):
# 设置标注的查询语句
lyr_label = arcpy.mapping.ListLayers(self.mxd, "市级区域")[0]
if lyr_label.supports("LABELCLASSES"):
query = ["NOT","( ", self.field, "=", "'", name, "'", " )"] # NOT( CITY = '巴中市' ) # ▶注释一◀
for lblClass in lyr_label.labelClasses:
lblClass.SQLQuery = "".join(query)
▶注释一◀:查询语句如这样:NOT( CITY = ‘资阳市’)
表示不显示资阳市的标注。
2.5.另存 mxd
另存一个 mxd 文件,比如:达州市.mxd;绵阳市.mxd等。
class MakeMXD(object):
...
def saveacopy(self, name):
# 另存
self.mxd.saveACopy(output_dir+'/'+name+'.mxd')
print("Complete <name: {} size: {}> ".format(name, self.size))
3.完整代码
# -*- coding:utf-8 -*-
# ---------------------------------------------------------------------------
# Author: LiaoChenchen
# Created on: 2021/1/30 17:04
# Reference:
"""
Description: 自动制图
Usage:
"""
# ---------------------------------------------------------------------------
from __future__ import absolute_import
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
import arcpy
import os
"""__________________________________________________________________________"""
"""____________________________global_values_________________________________"""
# 地址
mxd_template = r"E:\doc\Scratch\tempMXDS" # 模板文件位置
output_dir = r"E:\doc\Scratch\out" # 输出位置
gdb_path = r"E:\doc\Scratch\arcpy指南.gdb" # 数据库地址
# 重要常量
FIELD = "CITY" # 检索字段
MI = "MappingIndex" # 制图索引文件名称
SCALE = 200000 # 制图的比例尺
"""____________________________global_values_________________________________"""
"""__________________________________________________________________________"""
arcpy.env.overwriteOutput = True
arcpy.env.workspace = gdb_path
class MakeMXD(object):
def __init__(self,mapdocument, layers_names, mappindex_name, query_fielf, scale=None):
"""
:param mapdocument: {Object} MXD文件对象
:param layers_names: {List} 需要设置定义查询语句图层的名称列表
:param mappindex_name: {String} 索引图层名字;MappingIndex
:param query_fielf: {String} 定义查询使用的字段名;CITY
:param scale: {Int} 比例尺
"""
self.mxd = mapdocument
self.df = arcpy.mapping.ListDataFrames(self.mxd)[0]
self.layers = layers_names
self.index_name = mappindex_name
self.field = query_fielf
self.scale = scale
self.mapindex_lyr = arcpy.mapping.ListLayers(self.mxd,self.index_name)[0]
self.mapping_index_query()
self.make_mxd() # ▶注释一◀
del self.mxd
def mapping_index_query(self):
"""
给 MappingIndex 图层设置定义查询语句; PAGESIZE = '1080x700'
:return:
"""
map_path = self.mxd.filePath
name = os.path.splitext(os.path.basename(map_path))[0] # 1080x700
definition_query = ["PAGESIZE"," = ","'",name,"'"]
self.size = name
self.mapindex_lyr.definitionQuery = "".join(definition_query)
# self.mxd.saveACopy(r"E:\doc\Scratch\out\er.mxd")
def make_mxd(self):
with arcpy.da.SearchCursor(self.mapindex_lyr, self.field) as cursor: # ▶注释二◀
for row in cursor:
name = row[0]
self.define_query(name) # 定义查询
self.center_scale(name) # 居中
self.change_txt(name) # 修改文本
self.label_query(name) # 标注查询语句
arcpy.SelectLayerByAttribute_management(self.mapindex_lyr, "CLEAR_SELECTION") # 取消该图层的所有选择选择项目 # ▶注释三◀
self.saveacopy(name) # 另存
def define_query(self, value):
"""
定义查询
:param value: {String/Int/Float} 用于定义查询的值
:return: None
"""
for layer in self.layers:
lyr = arcpy.mapping.ListLayers(self.mxd, layer)[0]
d_q = ['"',self.field,'"'," = ","'",value,"'"]
# lyr.definitionQuery = '"' + FIELD + '"' + " = " + "'" + value + "'"
lyr.definitionQuery = "".join(d_q)
def center_scale(self, name):
"""
使图框居中并设置比例尺
:param name: {String/Int/Float} 用于查询语句的值
:return: None
"""
where_clause = "{} = '{}'".format(self.field, name)
arcpy_slba = arcpy.SelectLayerByAttribute_management
arcpy_slba(self.mapindex_lyr, "NEW_SELECTION", where_clause)
self.df.extent = self.mapindex_lyr.getSelectedExtent()
if self.scale:
self.df.scale = self.scale
def change_txt(self, name):
# 修改文本
for elm in arcpy.mapping.ListLayoutElements(self.mxd, 'TEXT_ELEMENT'):
if elm.text == "XX市铁路交通分布演示草图":
elm.text = "XX市铁路交通分布演示草图".replace("XX市", name)
def label_query(self,name):
# 设置标注的查询语句
lyr_label = arcpy.mapping.ListLayers(self.mxd, "市级区域")[0]
if lyr_label.supports("LABELCLASSES"):
query = ["NOT","( ", self.field, "=", "'", name, "'", " )"] # NOT( CITY = '巴中市' )
for lblClass in lyr_label.labelClasses:
lblClass.SQLQuery = "".join(query)
def saveacopy(self, name):
# 另存
self.mxd.saveACopy(output_dir+'/'+name+'.mxd')
print("Complete <name: {} size: {}> ".format(name, self.size))
# 运行窗口
if __name__ == '__main__':
for a_mxd in [x for x in os.listdir(mxd_template) if ".mxd" or ".MXD" in x]:
mxd_fullpath = os.path.join(mxd_template, a_mxd)
mxd = arcpy.mapping.MapDocument(mxd_fullpath)
MakeMXD(mxd, ["roads","railways","landuse","natural","buildings"], MI, FIELD, SCALE) # ▶注释四◀
▶注释一◀:该方法必须放到 mapping_index_query 方法的后面,要先限制了 mxd 模板后再进行批量的导出 mxd 文件。
▶注释二◀:遍历一个 mxd 模板中所有可以制作的制图单位。
▶注释三◀:取消居中操作时选中的要素。
▶注释四◀:该类的第二的参数是一个列表,其中元素是需要进行定义查询语句的图层名称。比如:[“roads”,“railways”,“landuse”,“natural”,“buildings”]
《指南》第三章和第四章代码是可以合并到一起运行的,下载见最下面。
4.效果展示
运行视频:
部分导出的图片展示:
5.关于输出图片
关于如何批量导出地图,甚至是多进程批量导出地图的教程在公众号就能找到。欢迎关注微信公众号查看。
结尾
源文件下载(包括第三章和第四章合并后的源代码):
下载后解压即为 .py 后缀文件。
链接:https://pan.baidu.com/s/1dxAs9m8MotfeQXagjjJw8g
提取码:fm1z
一次性下载本指南全部资料请关注公众号并回复:自动化制图,以获取下载链接!
标签:__,name,Python,self,ArcGIS,query,mxd,arcpy,制图 来源: https://blog.csdn.net/rsLanZai/article/details/113717957