So I have a python script that sets a dataframe extent to the extent of a particular layer and currently the user would then set the scale to something neater (i.e. 1:4,387 would become 1:5,000). I have seen ways to round up to a set increment (i.e. every 1000) but I am more interested in getting it to round up to the next interval in a list of intervals (i.e. 5000, 7500, 10000, 12500, 20000, 25000, 30000, 40000...). Can anyone recommend a way to do this?
Demo code;
# input parameters;
Plantation = arcpy.GetParameter(0)
# variables;
mxd = mapping.MapDocument("CURRENT")
layers = mapping.ListLayers(mxd)
dflist = arcpy.mapping.ListDataFrames(mxd, "")
new_exp = "PLANTATION = '" + Plantation + "'"
for lyr in layers:
if lyr.name == "Mapping Patch":
lyr.definitionQuery = new_exp
arcpy.AddMessage(lyr.name + " definition query updated")
ext = lyr.getExtent() #gets the new extent of the Fertilser Plan
dflist[0].extent = ext #applies the Fertiliser Plan extent to the dataframe
Solved! Go to Solution.
provide the list as a variable and select it wherever you are getting the input value. But I can't tell where you are looping to get the extent.
Perhaps if you throw some print statements in to see what is working now.
There is no 'rounding' but I think you want to select the next highest in a list. unfortunately lists don't really have a 'position' option, so you have to use the bisect module in your script...
Have a read, and see if this is what you are after
from bisect import bisect
a = [5000, 7500, 10000, 12500, 20000, 25000, 30000, 40000]
scale = 13000
a[bisect(a, scale)]
Out[21]: 20000 # 'rounded up' to the next scale
provide the list as a variable and select it wherever you are getting the input value. But I can't tell where you are looping to get the extent.
Perhaps if you throw some print statements in to see what is working now.
There is no 'rounding' but I think you want to select the next highest in a list. unfortunately lists don't really have a 'position' option, so you have to use the bisect module in your script...
Have a read, and see if this is what you are after
from bisect import bisect
a = [5000, 7500, 10000, 12500, 20000, 25000, 30000, 40000]
scale = 13000
a[bisect(a, scale)]
Out[21]: 20000 # 'rounded up' to the next scale
Thank you for providing this information as it can be useful in a replacement app for a .NET app that will be getting retired with the migration to Pro.
Michael... there are lots of hidden gems in python
Hi Dan. Thanks for the tip - trying to integrate it now. Is there a typo in the last line though?
Is - Out[21]: 20000 # 'rounded up' to the next scale
Should be? - Out[1]: 20000 # 'rounded up' to the next scale
Lindsay
Out[21]: is simply from Spyder's IPython built in console. It just keeps track of line numbers and I didn't remove it as I usually do to avoid confusion (failed miserably though )
The answer is simply … 20000 ...
Here's my full original code.
I'm thinking that I need to add your code in after Line 52 of my code (original in full at bottom). After setting the extent of the dataframe, I'm trying to get the current scale, run it though your code snippet to select the next value above the existing scale and apply the output to the dataframe. This same logic would then be applied to other parts of the code that do the same thing. I think I'm getting hung up on how I get both the existing scale and the output of your code snippet as a variable to use as the final input.
import arcpy
from arcpy import env, mapping
from bisect import bisect
#input parameters;
Plantation = arcpy.GetParameter(0)
ForestID = arcpy.GetParameter(1)
CommonName = arcpy.GetParameter(2)
PYear = arcpy.GetParameter(3)
#variables;
title1 = Plantation + " PLANTATION"
title2 = Plantation + "\r\nPLANTATION"
title3 = Plantation + " (" + CommonName + ")"
title4 = Plantation + " P" + PYear + " AREA STATEMENT"
mxd = mapping.MapDocument("CURRENT")
elements = mapping.ListLayoutElements(mxd)
layers = mapping.ListLayers(mxd)
dflist = arcpy.mapping.ListDataFrames(mxd, "")
new_exp = "PLANTATION = '" + Plantation + "'"
new_sur_exp = "PLANTATION <> '" + Plantation + "'"
as_new_exp = "EnteredInGeoMaster IS NOT NULL AND Plantation = '" + Plantation + "'"
scalelist = [5000, 7500, 10000, 12500, 20000, 25000, 30000, 40000, 50000, 60000, 70000, 75000, 80000, 90000, 100000]
...
elif lyr.name == "PlantationsHarvestPlan_OperationsPlanner_WA":
lyr.definitionQuery = new_exp
arcpy.AddMessage(lyr.name + " definition query updated")
ext = lyr.getExtent() #gets the new extent of the Harvest Plan
dflist[0].extent = ext #applies the Harvest Plan extent to the dataframe
oldscale = dflist[0].getScale # Get Scale here
scalelist[bisect(scalelist, oldscale)]# Run bisect here
dflist[0].scale = ????? # Use output of bisect to set new scale
...
Original code in full (works in this format but doesn't round/increment scales);
import arcpy
from arcpy import env, mapping
#input parameters;
Plantation = arcpy.GetParameter(0)
ForestID = arcpy.GetParameter(1)
CommonName = arcpy.GetParameter(2)
PYear = arcpy.GetParameter(3)
#variables;
title1 = Plantation + " PLANTATION"
title2 = Plantation + "\r\nPLANTATION"
title3 = Plantation + " (" + CommonName + ")"
title4 = Plantation + " P" + PYear + " AREA STATEMENT"
mxd = mapping.MapDocument("CURRENT")
elements = mapping.ListLayoutElements(mxd)
layers = mapping.ListLayers(mxd)
dflist = arcpy.mapping.ListDataFrames(mxd, "")
new_exp = "PLANTATION = '" + Plantation + "'"
new_sur_exp = "PLANTATION <> '" + Plantation + "'"
as_new_exp = "EnteredInGeoMaster IS NOT NULL AND Plantation = '" + Plantation + "'"
def ChangeTextElement(mxd,textElementName,newText):
textToChange = mapping.ListLayoutElements(mxd,"TEXT_ELEMENT",textElementName)[0]
textToChange.text = newText
for elm in elements:
if elm.name == "PTNID":
ChangeTextElement(mxd,"PTNID",ForestID.upper())
elif elm.name == "Plantation Name 1 line":
ChangeTextElement(mxd,"Plantation Name 1 line",title1.upper())
elif elm.name == "Plantation Name 2 lines":
ChangeTextElement(mxd,"Plantation Name 2 lines",title2.upper())
elif elm.name == "SF Plantation Name":
ChangeTextElement(mxd,"SF Plantation Name",title3.upper())
elif elm.name == "Area Statement Title":
ChangeTextElement(mxd,"Area Statement Title",title4.upper())
for lyr in layers:
if lyr.name == "OpCode Boundaries":
lyr.definitionQuery = new_exp
arcpy.AddMessage(lyr.name + " definition query updated")
elif lyr.name == "PlantationsHarvestPlan_OperationsPlanner_WA":
lyr.definitionQuery = new_exp
arcpy.AddMessage(lyr.name + " definition query updated")
ext = lyr.getExtent() #gets the new extent of the Harvest Plan
dflist[0].extent = ext #applies the Harvest Plan extent to the dataframe
elif lyr.name == "Mapping Patch":
lyr.definitionQuery = new_exp
arcpy.AddMessage(lyr.name + " definition query updated")
ext = lyr.getExtent() #gets the new extent of the Fertilser Plan
dflist[0].extent = ext #applies the Fertiliser Plan extent to the dataframe
elif lyr.name == "Mapping Patch Surround":
lyr.definitionQuery = new_sur_exp
arcpy.AddMessage(lyr.name + " definition query updated")
elif lyr.name == "Planned Establishment Areas":
lyr.definitionQuery = new_exp
arcpy.AddMessage(lyr.name + " definition query updated")
ext = lyr.getExtent() #gets the new extent of the Fertilser Plan
dflist[0].extent = ext #applies the Fertiliser Plan extent to the dataframe
elif lyr.name == "Target Fertiliser Areas":
lyr.definitionQuery = new_exp
arcpy.AddMessage(lyr.name + " definition query updated")
ext = lyr.getExtent() #gets the new extent of the Fertilser Plan
dflist[0].extent = ext #applies the Fertiliser Plan extent to the dataframe
elif lyr.name == "Captured Establishment Areas":
lyr.definitionQuery = as_new_exp
arcpy.AddMessage(lyr.name + " definition query updated")
ext = lyr.getExtent() #gets the new extent of the Captured Establishment Areas layer
dflist[0].extent = ext #applies the Captured Establishment Areas layer extent to the dataframe
elif lyr.name == "Mapping Focus Locality":
lyr.definitionQuery = new_exp
arcpy.AddMessage(lyr.name + " definition query updated")
ext = lyr.getExtent() #gets the new extent of the Mapping Focus Locality
dflist[1].extent = ext #applies the Mapping Focus Locality extent to the dataframe
dflist[2].extent = ext #applies the Mapping Focus Locality extent to the dataframe
dflist[1].scale = 500000 # sets the scale to 1:500,000
dflist[2].scale = 1500000 # sets the scale to 1:1,500,000
elif lyr.name == "Mapping Surround Locality":
lyr.definitionQuery = new_sur_exp
arcpy.AddMessage(lyr.name + " definition query updated")
woooo, that is a
a[bisect(a, scale)] # the simple expression
scalelist = [5000, 7500, 10000, 12500, 20000, 25000, 30000, 40000, 50000, 60000, 70000, 75000, 80000, 90000, 100000]
scale = ??? # you can't get scale from the extent, not sure where you are getting it, but it needs to be an integer
will become
new_scale = scalelist[bisect(scalelist, scale)] # bisect returns a 'slice' of the list... that is a position, then it returns the right-most value at that position
where are you getting scale then?
Awesome! Figured it out. Snippet of final code below. Thank you for your help Dan Patterson. Been thinking of this for a while. Good to be able to do it. (Slowly improving my python skills!).
elif lyr.name == "PlantationsHarvestPlan_OperationsPlanner_WA":
lyr.definitionQuery = new_exp
arcpy.AddMessage(lyr.name + " definition query updated")
ext = lyr.getExtent() #gets the new extent of the Harvest Plan
dflist[0].extent = ext #applies the Harvest Plan extent to the dataframe
oldscale = dflist[0].scale # Get scale of dataframe
newscale = scalelist[bisect(scalelist, oldscale)] # bisect old scale to get new scale
dflist[0].scale = newscale # Apply new scale to dataframe
Glad it worked out Lindsay!