Hi all, I can't seem to figure out how to add my output layers to my current map display through my python toolbox code. Anyone have any idea how to do so?
import arcpy
import pandas as pd
from arcpy.sa import *
class Toolbox(object):
def __init__(self):
self.label = "Mapping Trees Model"
self.alias = "mapping trees"
# List of tool classes associated with this toolbox
self.tools = [MappingTrees]
class MappingTrees(object):
def __init__(self):
self.label = "Mapping Trees Model"
self.description = "This model analyzes information from a raster with tree data such as tree height, canopy cover percent, etc. for an area of interest defined by the user. "
def getParameterInfo(self):
#Define the parameters
Extent = arcpy.Parameter(
displayName = "Define Extent",
name = "Extent",
datatype = "GPExtent",
parameterType = "Required",
direction = "Input")
Identify_Workspace = arcpy.Parameter(
displayName = "Identify Workspace",
name = "Identify_Workspace",
datatype = "DEWorkspace",
parameterType = "Required",
direction = "Input")
Study_Area = arcpy.Parameter(
displayName="Study Area",
name="Study_Area",
datatype="GPFeatureLayer",
parameterType="Required",
direction="Input")
Study_Area.controlCLSID = "{60061247-BCA8-473E-A7AF-A2026DDE1C2D}"
Base_Raster = arcpy.Parameter(
displayName="Base Tree Raster (such as tree height, canopy cover percentage, etc.)",
name="Base_Raster",
datatype="GPRasterLayer",
parameterType="Required",
direction="Input")
#Base_Raster.filter.type = "ValueList"
dBASE_file = arcpy.Parameter(
displayName = "Class Ranges (dBASE file)",
name = "dBASE_file",
datatype = "GPTableView",
parameterType = "Required",
direction = "Input")
## Patches = arcpy.Parameter(
## displayName = "Raster to Polygon",
## name = "Patches",
## datatype = "GPLayer",
## parameter = "Derived",
## direction = "Output")
parameters = [Extent, Identify_Workspace, Study_Area, Base_Raster, dBASE_file]
return parameters
def isLicensed(self):
try:
if arcpy.CheckExtension("Spatial") != "Available":
raise Exception
else:
arcpy.CheckOutExtension("Spatial")
except Exception:
arcpy.AddMessage('Spatial Analyst Extension not available')
return False # tool cannot be executed
return True # tool can be executed
def updateParameters(self, parameters):
return
def updateMessages(self, parameters):
return
def execute(self, parameters, messages):
#allow tool to overwrite the layers in the file being used
arcpy.env.overwriteOutput == True
#Make it so I can use the parameters in the tool
Extent = parameters[0].valueAsText
Identify_Workspace = parameters[1].valueAsText
Study_Area = parameters[2].valueAsText
Base_Raster = parameters[3].valueAsText
dBASE_file = parameters[4].valueAsText
#Define workspace
arcpy.env.workspace = Identify_Workspace
# Extract by Mask: extract out the study area out of the base raster
Extract_Mask = "Extract_Raster.tif"
Extract_Mask1 = arcpy.sa.ExtractByMask(Base_Raster, Study_Area, "INSIDE")
Extract_Mask1.save(Extract_Mask)
# Reclassify: classify a raster with the range of what you would like it to be
array = arcpy.da.TableToNumPyArray(dBASE_file, "*")
df = pd.DataFrame(array)
class_list = df.values.tolist()
for i in range(len(class_list)):
class_list[i] = class_list[i][1:-1]
myRemapRange = arcpy.sa.RemapRange(class_list)
User_Reclassified_Raster = "User_Reclassified_Raster.tif"
reclassified_raster = arcpy.sa.Reclassify(Extract_Mask1, "Value", myRemapRange, "NODATA")
reclassified_raster.save(User_Reclassified_Raster)
# Add Field: add the field Range to the reclassified raster
# to help user know what ranges go with what classified value
arcpy.management.AddField(User_Reclassified_Raster, "Range", "TEXT", field_alias = "Height Range")
# Join Field: join the from and to fields from the dBASE file
arcpy.management.JoinField(User_Reclassified_Raster, "Value", dBASE_file, "OUT",["FROM_", "TO"])
# Calculate Field
arcpy.management.CalculateField(User_Reclassified_Raster,"Range", "\"!FROM_! - !TO!\"")
# Delete Field
arcpy.management.DeleteField(User_Reclassified_Raster, ["FROM_", "TO"])
#List the fields in the Study Area polygon and if it does not have the fild ID, add it
fields = arcpy.ListFields(Study_Area)
if "Id" not in fields:
arcpy.management.AddField(Study_Area, "Id", "LONG")
arcpy.management.CalculateField(Study_Area, "Id", 0)
# Tabulate Area: calculate the area of each range of heights, etc.
Tabulate_Area = "Tabulate_Area.dbf"
arcpy.sa.TabulateArea(User_Reclassified_Raster, "Range", Study_Area, "Id", Tabulate_Area, User_Reclassified_Raster, "CLASSES_AS_FIELDS")
# Join, Add Field, Calculate Field, Delete Field: the tabulate area table to the reclassified raster, then add and calculate
# the field Area so one knows what field they are looking at, Delete the field "ID_0"
arcpy.management.JoinField(User_Reclassified_Raster, "Range", Tabulate_Area, "RANGE", ["ID_0"])
arcpy.management.AddField(User_Reclassified_Raster, "Area", "DOUBLE")
arcpy.management.CalculateField(User_Reclassified_Raster, "Area", "!ID_0!")
arcpy.management.DeleteField(User_Reclassified_Raster, "ID_0")
# Raster to Polygon: convert the reclassified raster to polygons
R2P = "R2P"
arcpy.conversion.RasterToPolygon(User_Reclassified_Raster, R2P,"NO_SIMPLIFY", "Range")
# Dissolve: combine all the polygons together that touch
Dissolve_Polys = "Dissolve_Polys"
arcpy.management.Dissolve(R2P, Dissolve_Polys, "", "", "SINGLE_PART")
#Eliminate: smooth out the polygons
Patches = "Patches"
arcpy.management.EliminatePolygonPart(Dissolve_Polys, Patches, "AREA", 1000)
# Zonal Statistics: calculate the statistics (min, max, and mean) of the tree values
ZonalStats = "ZonalStats.dbf"
arcpy.sa.ZonalStatisticsAsTable(Patches, "ORIG_FID", Base_Raster, ZonalStats, "DATA", "MIN_MAX_MEAN")
# Join Field: join the zonal stats fields to the smoothed out polygons
arcpy.management.JoinField(Patches, "ORIG_FID", ZonalStats, "ORIG_FID", ["AREA", "MIN", "MAX", "MEAN"])
arcpy.management.DeleteField(Patches, ["Id", "ORIG_FID"])
arcpy.management.AddField(Patches, "Acres", "DOUBLE")
arcpy.management.CalculateGeometryAttributes(Patches, [["Acres","AREA"]], area_unit="ACRES_US")
# Delete: delete the following layers:
arcpy.management.Delete(Extract_Mask1)
arcpy.management.Delete(R2P)
arcpy.management.Delete(Dissolve_Polys)
arcpy.management.Delete(ZonalStats)
arcpy.management.Delete(Tabulate_Area)
c_project=arcpy.mp.ArcGISProject("CURRENT")
return
def postExecute(self, parameters):
return
have you set the parameter in the toolbox to 'output'
If that doesn't work then try adding a derived parameter as output as per:
https://community.esri.com/t5/arcgis-pro-questions/how-to-display-feature-layer-from-python-toolbox/...
That does not seem to work. I believe that is because I'm writing a python toolbox and not a script tool in a normal toolbox.
It is an environment setting and can only be changed within the python window or a notebook in ArcGIS Pro
List tools, toolboxes, and environment settings—ArcGIS Pro | Documentation
env—ArcGIS Pro | Documentation
import arcpy
environments = arcpy.ListEnvironments()
# Sort the environment list, disregarding capitalization
environments.sort(key=str.lower)
for environment in environments:
# As the environment is passed as a variable, use Python's getattr to
# evaluate the environment's value
env_value = getattr(arcpy.env, environment)
# Format and print each environment and its current setting
print(f"{environment:<30}: {env_value}")
addOutputsToMap : True
.... snip ....
If your derived output is being created by the tool, you can set the value by doing this at the end of your execute method:
parameters[5].value = Patches
Note that you might need to adjust the parameter's data type, you picked "GPLayer" but you probably want "GPFeatureLayer" or "DEFeatureClass".
Why are you assigning c_project then doing nothing with it?
To interact with an active project, you usually assign that at the beginning of the tool (I usually throw it in the tool __init__ function so I can use it with a "self.project" call. Then you can do map operations while the tool is executing (like addLayerFromDatasource, or moveLayer)
You can then pass layers generated using arcpy tools to the appropriate .mp calls on that project and it's associated objects.