如何使用Python将ArcMap中的Extent、Scale和RefreshView转换为ArcPro

huangapple go评论74阅读模式
英文:

How to convert Extent, Scale and RefreshView from ArcMap to ArcPro using Python

问题

我使用了一个Python(2.7)的ArcMap脚本多年,现在我正试图将其转换为适用于ArcPro(Python 3)。我已经将我的ArcMap脚本的一半转换为ArcPro(使用Visual Studio),但在修改代码以缩放到图层范围后修改其定义查询方面遇到了问题。

地图名称为“Mailing List Map”。

我想要从中导出PDF地图的布局称为:“Irrigation_Services_Maps”。

我正在更改地图标题的表格名称是一个名为irrStats的变量。它有两列,客户名称和频率(客户名称的数量-每条记录表示一个灌溉点。一个客户可以有多个灌溉点)

我想创建一个以客户名称为标题的地图,包括与该客户相关的所有灌溉点,并将其导出为PDF。

有人可以指导我如何重写这个吗?我已经花了整天时间回顾这个问题,但没有找到明显的解决方案。你会觉得这应该比现在容易。

代码中的问题从以下行开始:#####。我无法弄清楚如何添加行号。

谢谢

import arcpy, os
from datetime import datetime
startTime = datetime.now()

print ((datetime.now() - startTime))

irrFile = arcpy.GetParameterAsText(0)  # 获取包含数据的灌溉文件
pdfFolder = arcpy.GetParameterAsText(1)  # 请求用于放置PDF输出文件的文件夹位置
arcpy.AddMessage(pdfFolder)
pdflist = [f for f in os.listdir(pdfFolder) if f.endswith(".pdf")]
for f in pdflist:
    os.remove(os.path.join(pdfFolder, f))
arcpy.env.overwriteOutput = True  # 允许我们多次运行脚本而不删除中间文件
aprx = arcpy.mp.ArcGISProject("CURRENT")
aprxMap = aprx.listMaps("Mailing List Map")[0]
lyt = aprx.listLayouts("Irrigation_Services_Maps")[0]
scratchDir = pdfFolder + "\\scratch"  # 用于存储临时数据的临时文件夹
arcpy.AddMessage(scratchDir)

if not os.path.exists(scratchDir):
    os.makedirs(scratchDir)
arcpy.env.workspace = scratchDir

arcpy.env.overwriteOutput = True
tempFGDB = arcpy.CreateFileGDB_management(scratchDir, "scratchGDB").getOutput(0)

arcpy.AddMessage(tempFGDB)
arcpy.env.workspace = tempFGDB
irrStats = "irr_stats"
if arcpy.Exists(irrStats):
    arcpy.Delete_management(irrStats)

arcpy.Frequency_analysis(irrFile, irrStats, "cus_name")
with arcpy.da.SearchCursor(irrStats, ("FREQUENCY", "cus_name")) as rows: # 遍历irrStats表
    for row in rows:
        cusName = row[1]
        cusFreq = row[0]
        if len(cusName) > 1:
            arcpy.AddMessage(cusName)
            lyr = aprxMap.listLayers(irrFile)[0]
            lyr.definitionQuery = ""       
            lyr.definitionQuery = "\"cus_name\" = '" + cusName + "'"
            for xyz in aprx.listLayouts():   
                for elm in xyz.listElements("TEXT_ELEMENT"):
                    if elm.name == "customer":
                        elm.text = (cusName) # 并将标题(文本元素"Customer")更改为表中选择的名称
                        
###### 不知道如何为ArcPro编写Extent、Scale和Refresh View
###### 下面是需要重写的旧ArcMap代码

        pdfMap = pdfFolder + "\\" + cusName + ".pdf"
        if cusFreq == 1:  # 如果只有一个客户记录
            arcpy.AddMessage("Name : " + cusName)
            ext = lyr.getExtent()
            df.extent = ext
            arcpy.RefreshActiveView()  # 重新绘制地图
            df.scale = 1000   # 设置比例为1000
            arcpy.RefreshActiveView()  # 重新绘制地图
            arcpy.mapping.ExportToPDF(mxd, pdfMap)
        elif cusFreq > 1:  # 如果有多个记录
            arcpy.AddMessage("Name2 : " + cusName)
            ext = lyr.getExtent() # 查找范围
            df.extent = ext # 缩放到它
            arcpy.RefreshActiveView()  # 重新绘制地图

            if df.scale < 1000: #如果范围小于1000,则设置比例为1000
                df.scale = 1000
            else:
                df.scale = df.scale * 1.2  # 否则将比例设置为图层范围的1.2倍

            arcpy.RefreshActiveView()  # 刷新地图
            arcpy.mapping.ExportToPDF(mxd, pdfMap) # 导出地图 
            arcpy.AddMessage("more than one")
        else:
            arcpy.AddMessage("Name3 : " + cusName)
        lyr.definitionQuery = ""    
英文:

I used an Python (2.7) ArcMap script for years and now I am trying to convert it to use with ArcPro (Python 3). I have converted half of my ArcMap script to ArcPro (with Visual Studio) but am stuck on modifying my code to zoom to the extent of the layer after modifying its definition query.

The map name is "Mailing List Map".

The layout I want to use to export my pdf maps from is called:"Irrigation_Services_Maps"

The table name I am changing the map title of is a variable called irrStats. It has two columns, Customer Name and Frequency (number of customer names-each record represents an irrigation point. A single customer can have many irrigation points)

I want to create a map with the customer name as the title and all the irrigation points associated with that customer and export it as a pdf.

Can someone please guide me as to rewrite this. I have spent all day reviewing this with no discernable solution. You would think it was easier than this.

Issues with code start at line that begins #####. I could not figure out how to add line numbers.

Thanks

import arcpy, os
from datetime import datetime
startTime = datetime.now()
print ((datetime.now() - startTime))
irrFile = arcpy.GetParameterAsText(0)  # Gets the irrigation file with the data in it
pdfFolder = arcpy.GetParameterAsText(1)  # Asks for folder location to put the pdf output files
arcpy.AddMessage(pdfFolder)
pdflist = [f for f in os.listdir(pdfFolder) if f.endswith(&quot;.pdf&quot;)]
for f in pdflist:
os.remove(os.path.join(pdfFolder, f))
arcpy.env.overwriteOutput = True  # Allows us to run the script repeatedly without deleting the intermediate files
aprx = arcpy.mp.ArcGISProject(&quot;CURRENT&quot;)
aprxMap = aprx.listMaps(&quot;Mailing List Map&quot;)[0]
lyt=aprx.listLayouts(&quot;Irrigation_Services_Maps&quot;)[0]
scratchDir = pdfFolder + &quot;\\scratch&quot;  # Temporary folder to store temp data
arcpy.AddMessage(scratchDir)
if not os.path.exists(scratchDir):
os.makedirs(scratchDir)
arcpy.env.workspace = scratchDir
arcpy.env.overwriteOutput = True
tempFGDB = arcpy.CreateFileGDB_management(scratchDir, &quot;scratchGDB&quot;).getOutput(0)
arcpy.AddMessage(tempFGDB)
arcpy.env.workspace = tempFGDB
irrStats = &quot;irr_stats&quot;
if arcpy.Exists(irrStats):
arcpy.Delete_management(irrStats)
arcpy.Frequency_analysis(irrFile, irrStats, &quot;cus_name&quot;)
with arcpy.da.SearchCursor(irrStats, (&quot;FREQUENCY&quot;, &quot;cus_name&quot;)) as rows: # Goes through the irrStats table
for row in rows:
cusName = row[1]
cusFreq = row[0]
if len(cusName) &gt; 1:
arcpy.AddMessage(cusName)
lyr = aprxMap.listLayers(irrFile)[0]
lyr.definitionQuery = &quot;&quot;       
lyr.definitionQuery = &quot;\&quot;cus_name\&quot; = &quot; + &quot;&#39;&quot; + cusName + &quot;&#39;&quot;
for xyz in aprx.listLayouts():   
for elm in xyz.listElements(&quot;TEXT_ELEMENT&quot;):
if elm.name == &quot;customer&quot;:
elm.text = (cusName) # and changes the title (text element &quot;Customer&quot;) to selected name in table 
###### Don&#39;t know how to code Extent, Scale and Refresh View for ArcPro
###### Old ArcMap code needing rewrite below this point
pdfMap = pdfFolder + &quot;\\&quot; + cusName + &quot;.pdf&quot;
if cusFreq == 1:  # if there is only one customer record
arcpy.AddMessage(&quot;Name : &quot; + cusName)
ext = lyr.getExtent()
df.extent = ext
arcpy.RefreshActiveView()  # redraw the map
df.scale = 1000   # set the scale to 1000
arcpy.RefreshActiveView()  # redraw the map
arcpy.mapping.ExportToPDF(mxd, pdfMap)
elif cusFreq &gt; 1:  # if there is more than 1 record
arcpy.AddMessage(&quot;Name2 : &quot; + cusName)
ext = lyr.getExtent() # Find out the extent
df.extent = ext # zoom to it
arcpy.RefreshActiveView()  # redraw the map
if df.scale &lt; 1000: #set the scale to 1000 is extent is &lt; 1000
df.scale = 1000
else:
df.scale = df.scale * 1.2  # otherwise make the scale 1.2 times the layers extent
arcpy.RefreshActiveView()  # refresh the map
arcpy.mapping.ExportToPDF(mxd, pdfMap) # export the map 
arcpy.AddMessage(&quot;more than one&quot;)
else:
arcpy.AddMessage(&quot;Name3 : &quot; + cusName)
lyr.definitionQuery = &quot;&quot;    

答案1

得分: 1

以下是翻译好的部分:

  1. RefreshActiveView

在ArcGIS Pro和“CURRENT”项目中,对arcpy.mp-API的所有更改都会直接更新到ArcGIS Pro中,因此无需调用refreshActiveView函数。

  1. 图层范围

可以使用arcpy.Describe来检索数据元素(如图层)的属性:

    desc = arcpy.Describe(lyr)
    etxent = desc.extent
  1. MapFrame/MapView

在ArcGIS Pro中,不再使用数据框架,而是使用类MapFrame(页面布局元素)和MapView(活动地图)。在这两个类上都有一个名为camera的属性,它可以让您访问比例:

    map_view = aprxMap.activeView
    camera = map_view.camera
    
    #获取当前范围:
    current_extent = camera.getExtent()
    
    #设置范围
    camera.setExtent(extent)
  1. 比例尺

比例尺也是相机类的属性(可读可写):

    camera = map_view.camera
    
    #读取
    scl = camera.scale
    
    #写入
    camera.scale *= 1.5

也许您可以使用这些信息来更好地转换为ArcGIS Pro时解决问题。

英文:

There are a few things you have to look out for.

  1. RefreshActiveView

With ArcGIS Pro and the "CURRENT" project, all changes to the arcpy.mp-API result in a direct update in ArcGIS Pro, so there is no need to call a refreshActiveView-function.

  1. Layer Extent

Properties of data elements, such as layers, can be retreived using arcpy.Describe:

    desc = arcpy.Describe(lyr)
    etxent = desc.extent
  1. MapFrame/MapView

In ArcGIS Pro you don't work with DataFrames anymore, instead use the classes MapFrame (Page Layout element) and MapView (active Map).
On both of these classes you have a property camera which gives you access to the scale:

    map_view = aprxMap.activeView
    camera = map_view.camera
    
    #get current extent:
    current_extent = camera.getExtent()
    
    #set extent
    camera.setExtent(extent)
  1. Scale

The scale is also a property of the camera-class (read and write) :

    camera = map_view.camera
    
    #read
    scl = camera.scale
    
    #write
    camera.scale *= 1.5

Mayber you can narrow down the problems you have converting to ArcGIS Pro using this.

答案2

得分: 0

以下是代码的中文翻译:

我发布我的最终代码因为我在网上找不到很多示例我希望这有所帮助因为我发现在线文档很难理解

import arcpy, os
from datetime import datetime
startTime = datetime.now()

print ((datetime.now() - startTime))

irrFile = arcpy.GetParameterAsText(0)  # 获取包含数据的灌溉文件
pdfFolder = arcpy.GetParameterAsText(1)  # 请求文件夹位置以放置PDF输出文件
arcpy.AddMessage(irrFile)
pdflist = [f for f in os.listdir(pdfFolder) if f.endswith(".pdf")]
for f in pdflist:
    os.remove(os.path.join(pdfFolder, f))
arcpy.env.overwriteOutput = True  # 允许我们重复运行脚本而不删除中间文件
aprx = arcpy.mp.ArcGISProject("CURRENT")
aprxMap = aprx.listMaps("Mailing List Map")[0]
scratchDir = pdfFolder + "\\scratch"  # 用于存储临时数据的临时文件夹
arcpy.AddMessage(scratchDir)

if not os.path.exists(scratchDir):
   os.makedirs(scratchDir)
arcpy.env.workspace = scratchDir

arcpy.env.overwriteOutput = True
tempFGDB = arcpy.CreateFileGDB_management(scratchDir, "scratchGDB").getOutput(0)

arcpy.AddMessage(tempFGDB)
arcpy.env.workspace = tempFGDB
irrStats = "irr_stats"
if arcpy.Exists(irrStats):
   arcpy.Delete_management(irrStats)

arcpy.Frequency_analysis(irrFile, irrStats, "cust_name")
lyt=aprx.listLayouts("Irrigation_Services_Maps")[0]

with arcpy.da.SearchCursor(irrStats, ("FREQUENCY", "cust_name")) as rows:
   for row in rows:
      cusName = row[1]
      cusFreq = row[0]
      if len(cusName) > 1:
         arcpy.AddMessage(cusName)
         lyr = aprxMap.listLayers(irrFile)[0]
         lyr.definitionQuery = ""       
         lyr.definitionQuery = "\"cust_name\" = " + "'" + cusName + "'"
         if cusName == 'DEPT OF TRANSPORTATION':
             cusName = "DOT"
             arcpy.AddMessage(cusName)
         for xyz in aprx.listLayouts():   
             for elm in xyz.listElements("TEXT_ELEMENT"):
                if elm.name == "customer":
                    elm.text = (cusName)

         pdfMap = pdfFolder + "\\" + cusName + ".pdf"
         mf = lyt.listElements('mapframe_element')[0]

         if cusFreq == 1:  # 如果只有一个客户记录
            arcpy.AddMessage("Name : " + cusName)
            mf.camera.setExtent(mf.getLayerExtent(lyr, False, True))
            mf.camera.scale = 1000
            lyt.exportToPDF(pdfMap)
         elif cusFreq > 1:  # 如果有多于1个记录
            arcpy.AddMessage("Name2 : " + cusName)
            mf.camera.setExtent(mf.getLayerExtent(lyr, False, True))
            if mf.camera.scale < 1000: # 如果范围小于1000,则将比例设置为1000
               mf.camera.scale = 1000
            else:
               mf.camera.scale = mf.camera.scale * 1.2  # 否则将比例设置为图层范围的1.2倍

            lyt.exportToPDF(pdfMap) # 导出地图 
            arcpy.AddMessage("more than one")
         else:
            arcpy.AddMessage("Name3 : " + cusName)
         lyr.definitionQuery = ""

希望这对您有所帮助!如果您需要进一步的翻译或有其他问题,请告诉我。

英文:

I am posting my final code because I could not find many examples of this online. I hope it helps as I found the online documentation to be very hard to make sense of.

import arcpy, os
from datetime import datetime
startTime = datetime.now()
print ((datetime.now() - startTime))
irrFile = arcpy.GetParameterAsText(0)  # Gets the irrigation file with the data in it
pdfFolder = arcpy.GetParameterAsText(1)  # Asks for folder location to put the pdf output files
arcpy.AddMessage(irrFile)
pdflist = [f for f in os.listdir(pdfFolder) if f.endswith(&quot;.pdf&quot;)]
for f in pdflist:
os.remove(os.path.join(pdfFolder, f))
arcpy.env.overwriteOutput = True  # Allows us to run the script repeatedly without deleting the intermediate files
aprx = arcpy.mp.ArcGISProject(&quot;CURRENT&quot;)
aprxMap = aprx.listMaps(&quot;Mailing List Map&quot;)[0]
scratchDir = pdfFolder + &quot;\\scratch&quot;  # Temporary folder to store temp data
arcpy.AddMessage(scratchDir)
if not os.path.exists(scratchDir):
os.makedirs(scratchDir)
arcpy.env.workspace = scratchDir
arcpy.env.overwriteOutput = True
tempFGDB = arcpy.CreateFileGDB_management(scratchDir, &quot;scratchGDB&quot;).getOutput(0)
arcpy.AddMessage(tempFGDB)
arcpy.env.workspace = tempFGDB
irrStats = &quot;irr_stats&quot;
if arcpy.Exists(irrStats):
arcpy.Delete_management(irrStats)
arcpy.Frequency_analysis(irrFile, irrStats, &quot;cust_name&quot;)
lyt=aprx.listLayouts(&quot;Irrigation_Services_Maps&quot;)[0]
with arcpy.da.SearchCursor(irrStats, (&quot;FREQUENCY&quot;, &quot;cust_name&quot;)) as rows:
for row in rows:
cusName = row[1]
cusFreq = row[0]
if len(cusName) &gt; 1:
arcpy.AddMessage(cusName)
lyr = aprxMap.listLayers(irrFile)[0]
lyr.definitionQuery = &quot;&quot;       
lyr.definitionQuery = &quot;\&quot;cust_name\&quot; = &quot; + &quot;&#39;&quot; + cusName + &quot;&#39;&quot;
if cusName == &#39;DEPT OF TRANSPORTATION&#39;:
cusName = &quot;DOT&quot;
arcpy.AddMessage(cusName)
for xyz in aprx.listLayouts():   
for elm in xyz.listElements(&quot;TEXT_ELEMENT&quot;):
if elm.name == &quot;customer&quot;:
elm.text = (cusName)
pdfMap = pdfFolder + &quot;\\&quot; + cusName + &quot;.pdf&quot;
mf = lyt.listElements(&#39;mapframe_element&#39;)[0]
if cusFreq == 1:  # if there is only one customer record
arcpy.AddMessage(&quot;Name : &quot; + cusName)
mf.camera.setExtent(mf.getLayerExtent(lyr, False, True))
mf.camera.scale = 1000
lyt.exportToPDF(pdfMap)
elif cusFreq &gt; 1:  # if there is more than 1 record
arcpy.AddMessage(&quot;Name2 : &quot; + cusName)
mf.camera.setExtent(mf.getLayerExtent(lyr, False, True))
if mf.camera.scale &lt; 1000: #set the scale to 1000 is extent is &lt; 1000
mf.camera.scale = 1000
else:
mf.camera.scale = mf.camera.scale * 1.2  # otherwise make the scale 1.2 times the layers extent
lyt.exportToPDF(pdfMap) # export the map 
arcpy.AddMessage(&quot;more than one&quot;)
else:
arcpy.AddMessage(&quot;Name3 : &quot; + cusName)
lyr.definitionQuery = &quot;&quot;

答案3

得分: 0

mf.panToExtent(mf.getLayerExtent(lyr, False, True)):

避免每次重新检查和设置比例为1000。似乎它保持在那个比例上,您可以设置地图框架在那个比例上而不进行更改。

英文:
mf.panToExtent(mf.getLayerExtent(lyr, False, True))

Would avoid rechecking and setting scale to 1000 ever time. As it seems it stays there and you can set map frame at that scale and not alter.

huangapple
  • 本文由 发表于 2023年6月29日 08:26:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76577426.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定