ApplySymbologyFromLayer_management creates copy of a layer rather than updating it

2211
8
Jump to solution
06-12-2013 01:05 PM
BenjaminBauman
Occasional Contributor
Hey all,

I'm very new to ArcPy, and have encountered a roadblock when trying to update a layer's symbology using ApplySymbologyFromLayer_management. It works, but it creates a copy of the target layer rather than updating it in place. In order to clean out the duplicates, I attempted to apply the RemoveLayer function to the original layer (as seen on the second to last line), but this did not seem to remove it from the TOC.

import arcpy from arcpy import analysis, env  workspace = arcpy.env.workspace = r"C:/temp"  arcpy.env.overwriteOutput = True  mxDoc = arcpy.mapping.MapDocument(r"X:/GisResources/Mxd Map Templates/HighUnemploymentCensusTracts_Template.mxd")  df = arcpy.mapping.ListDataFrames(mxDoc, "Detail Map") [0]  co_layer = arcpy.mapping.ListLayers(mxDoc,"",df) [0]  co_name = "NAME"  rows = arcpy.SearchCursor(co_layer)  for row in rows:     co = row.getValue(co_name)     whereClause = "NAME <> '%s'" % co     analysis.Select(co_layer, "Co_%s" % co, whereClause)     arcpy.ApplySymbologyFromLayer_management("Co_%s" % co, "Export_Output_21")     inputLayer = arcpy.mapping.Layer("Co_%s" % co)     arcpy.mapping.RemoveLayer(df, inputLayer)      arcpy.RefreshActiveView()
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
RhettZufelt
MVP Frequent Contributor
Well, without the time to dive into this, this is the way I would approach it as I am doing something very similar and this method works for me.

Also, I'm not back until monday either. gotta love 4-10s.

Thank you both. Unfortunately, I won't be back in the office until Monday, so I will not be able to try out your suggestions until then. In the meantime, I can explain the purposes of this script. Text in bold indicates instructions that exist within the current script, as seen on the OP. 

Iterate through features within IlCounties layer, and do the following for each feature:

the da.walk will do this for you.

for dirpath, dirnames, filenames in arcpy.da.Walk(datatype="FeatureClass",type="All"):  ## would restrict this "All" to the feature/table type you are after      for filename in filenames:               Rest of the code would go here since you want it for each feature in the FC....


Zoom to feature

cntyLayer = r'path\to\IlCounties" feature class    ###    would hard code this one since it is fixed, and we iterate through the others. df = arcpy.mapping.ListDataFrames(mxd, "Detail Map")[0] df2 = arcpy.mapping.ListDataFrames(mxd, "Locator Map")[0]   #  Just as well set both df's while here lyr = arcpy.mapping.ListLayers(mxd, "IlCounties", df)[0] df.extent = lyr.getSelectedExtent(True)




Select all features not equal to feature within IlCounties

Use SelectLayerByLocation with ARE_IDENTICAL_TO for overlap type and NEW_SELECTION for selection type.
Use SelectLayerByLocation with SWITCH_SELECTION as selection type ### These two will select features that are not equal to the other features 

Export selection as new layer, add to Detail Map dataframe

Use CopyFeatures to export to new FGDB FC # this will only copy/export the selected features 
then AddLayer to add the new FC to the df.

AddLayer(df,new_FC)


Update new layer to incorporate symbology of Export_Output_21

use UpdateLayer for this

Add new layer to a second existing dataframe (named Locator Map)

add layer again AddLayer(df2,new_FC) ## of course, you will have to update symobology again if needed. 

Replace MXD title element to IlCounties feature name


legend = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "title")[0]
legend.text = filename


Export as PDF

ExportToPDF (mxd, out_pdf,resolution=266)

I'm mostly just seeking help for the instructions in bold at the moment. I'll answer your questions and suggestions directly come Monday. Thank you!


Now that I spelled it all out, easy to put together. should be something like this (you will need to fill in the blanks)

 cntyLayer = r'path\to\IlCounties' arcpy.MakeFeatureLayer_management(cntyLayer, "IlCounties_lyr")     for dirpath, dirnames, filenames in arcpy.da.Walk(datatype="FeatureClass",type="All"):       for filename in filenames:         df = arcpy.mapping.ListDataFrames(mxd, "Detail Map")[0]         df2 = arcpy.mapping.ListDataFrames(mxd, "Locator Map")[0]   #  Just as well set both df's while here         lyr = arcpy.mapping.ListLayers(mxd, "IlCounties", df)[0]         df.extent = lyr.getSelectedExtent(True)         arcpy.MakeFeatureLayer_management(filename, str(filename) + "_lyr")                 SelectLayerByLocation(str(filename) + "_lyr", "ARE_IDENTICAL_TO", "IlCounties_lyr", #, NEW_SELECTION)         SelectLayerByLocation(str(filename) + "_lyr", "ARE_IDENTICAL_TO", "IlCounties_lyr", #, SWITCH_SELECTION)         CopyFeatures         AddLayer(df,new_FC)         UpdateLayer         AddLayer(df2,new_FC)         UpdateLayer         legend = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "title")[0]         legend.text = filename         ExportToPDF (mxd, out_pdf,resolution=266)  


R_

View solution in original post

0 Kudos
8 Replies
RhettZufelt
MVP Frequent Contributor
Where is it finding the value of Export_Output_21 since this is the layer you are trying to apply the symbology from?

ApplySymbologyFromLayer_management (in_layer, in_symbology_layer)

I have not used ApplySymbologyFromLayer before, but arcpy.mapping.UpdateLayer(df, updateLayer, sourceLayer, True) is working for me to update my symbology from a .lyr file.

R_
0 Kudos
BenjaminBauman
Occasional Contributor
Where is it finding the value of Export_Output_21 since this is the layer you are trying to apply the symbology from?

ApplySymbologyFromLayer_management (in_layer, in_symbology_layer)

I have not used ApplySymbologyFromLayer before, but arcpy.mapping.UpdateLayer(df, updateLayer, sourceLayer, True) is working for me to update my symbology from a .lyr file.

R_


Export_Output_21 is a layer located within the Detail Map data frame. It seems to me that this function would be repeating this anomaly regardless of the details of the source layer.

It would be ok if it was happening if I could subsequently remove it from the TOC, but I can't even manage that! It doesn't help that the two layers (original and copy) both share the same name. If there is no explanation as to how to avoid the ApplySymbologyFromLayer from creating copies, does anyone know how to simply remove a layer from the TOC, because the following doesn't work.

arcpy.mapping.RemoveLayer(df, inputLayer)
    
arcpy.RefreshActiveView()
0 Kudos
RhettZufelt
MVP Frequent Contributor
OK, so you must be running in the python window from within ArcMap if it is finding current layers in the TOC.

I have never had a reason to do this, so all my scripting is done stand alone, so not sure if this will make a difference, but you might try:


mxDoc = arcpy.mapping.MapDocument("CURRENT")



and see if that makes a differnce.

R_

also, this is Arcpy, so you never know for sure if it is working correctly.  If you can't get it to work, you might try arcpy.mapping.UpdateLayer.
0 Kudos
markdenil
Occasional Contributor III
I agree with rzufelt
I usually use ApplySymbologyFromLayer to permanently set the symbols in a layer file on disc.
So it is used when the lyr is brought into ArcMap.
UpdateLayer() is the best way to set the symbolization on an existing ArcMap layer.
You still reference an existing layer on disc or the TOC

Why, by the way, are you setting the symbolization and removing layers
from inside a search cursor? That makes no sense I can see.

If you want to cycle through the various values in the NAME field as variables in a where clause
you should use the cursor to build a list of the names.
close the cursor, then cycle through the list.
rows = arcpy.SearchCursor(co_layer)
nameList = []
for row in rows:
    co = row.getValue(co_name)
    nameList.append(co)
del rows
for name in nameList:
    whereClause = ' "NAME" = \'%s\' ' % (name) 
    # ... and so on


Also
reference the TOC layer object in ApplySymbologyFromLayer, not the name string
export_layer = arcpy.mapping.ListLayers(mxDoc,"Export_Output_21",df) [0]
arcpy.ApplySymbologyFromLayer_management("Co_%s" % co, export_layer)
0 Kudos
BenjaminBauman
Occasional Contributor
Thank you both. Unfortunately, I won't be back in the office until Monday, so I will not be able to try out your suggestions until then. In the meantime, I can explain the purposes of this script. Text in bold indicates instructions that exist within the current script, as seen on the OP.

Iterate through features within IlCounties layer, and do the following for each feature:

Zoom to feature
Select all features not equal to feature within IlCounties
Export selection as new layer, add to Detail Map dataframe
Update new layer to incorporate symbology of Export_Output_21

Add new layer to a second existing dataframe (named Locator Map)
Replace MXD title element to IlCounties feature name
Export as PDF

I'm mostly just seeking help for the instructions in bold at the moment. I'll answer your questions and suggestions directly come Monday. Thank you!
0 Kudos
RhettZufelt
MVP Frequent Contributor
Well, without the time to dive into this, this is the way I would approach it as I am doing something very similar and this method works for me.

Also, I'm not back until monday either. gotta love 4-10s.

Thank you both. Unfortunately, I won't be back in the office until Monday, so I will not be able to try out your suggestions until then. In the meantime, I can explain the purposes of this script. Text in bold indicates instructions that exist within the current script, as seen on the OP. 

Iterate through features within IlCounties layer, and do the following for each feature:

the da.walk will do this for you.

for dirpath, dirnames, filenames in arcpy.da.Walk(datatype="FeatureClass",type="All"):  ## would restrict this "All" to the feature/table type you are after      for filename in filenames:               Rest of the code would go here since you want it for each feature in the FC....


Zoom to feature

cntyLayer = r'path\to\IlCounties" feature class    ###    would hard code this one since it is fixed, and we iterate through the others. df = arcpy.mapping.ListDataFrames(mxd, "Detail Map")[0] df2 = arcpy.mapping.ListDataFrames(mxd, "Locator Map")[0]   #  Just as well set both df's while here lyr = arcpy.mapping.ListLayers(mxd, "IlCounties", df)[0] df.extent = lyr.getSelectedExtent(True)




Select all features not equal to feature within IlCounties

Use SelectLayerByLocation with ARE_IDENTICAL_TO for overlap type and NEW_SELECTION for selection type.
Use SelectLayerByLocation with SWITCH_SELECTION as selection type ### These two will select features that are not equal to the other features 

Export selection as new layer, add to Detail Map dataframe

Use CopyFeatures to export to new FGDB FC # this will only copy/export the selected features 
then AddLayer to add the new FC to the df.

AddLayer(df,new_FC)


Update new layer to incorporate symbology of Export_Output_21

use UpdateLayer for this

Add new layer to a second existing dataframe (named Locator Map)

add layer again AddLayer(df2,new_FC) ## of course, you will have to update symobology again if needed. 

Replace MXD title element to IlCounties feature name


legend = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "title")[0]
legend.text = filename


Export as PDF

ExportToPDF (mxd, out_pdf,resolution=266)

I'm mostly just seeking help for the instructions in bold at the moment. I'll answer your questions and suggestions directly come Monday. Thank you!


Now that I spelled it all out, easy to put together. should be something like this (you will need to fill in the blanks)

 cntyLayer = r'path\to\IlCounties' arcpy.MakeFeatureLayer_management(cntyLayer, "IlCounties_lyr")     for dirpath, dirnames, filenames in arcpy.da.Walk(datatype="FeatureClass",type="All"):       for filename in filenames:         df = arcpy.mapping.ListDataFrames(mxd, "Detail Map")[0]         df2 = arcpy.mapping.ListDataFrames(mxd, "Locator Map")[0]   #  Just as well set both df's while here         lyr = arcpy.mapping.ListLayers(mxd, "IlCounties", df)[0]         df.extent = lyr.getSelectedExtent(True)         arcpy.MakeFeatureLayer_management(filename, str(filename) + "_lyr")                 SelectLayerByLocation(str(filename) + "_lyr", "ARE_IDENTICAL_TO", "IlCounties_lyr", #, NEW_SELECTION)         SelectLayerByLocation(str(filename) + "_lyr", "ARE_IDENTICAL_TO", "IlCounties_lyr", #, SWITCH_SELECTION)         CopyFeatures         AddLayer(df,new_FC)         UpdateLayer         AddLayer(df2,new_FC)         UpdateLayer         legend = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "title")[0]         legend.text = filename         ExportToPDF (mxd, out_pdf,resolution=266)  


R_
0 Kudos
RhettZufelt
MVP Frequent Contributor
Thank you both. Unfortunately, I won't be back in the office until Monday, so I will not be able to try out your suggestions until then. In the meantime, I can explain the purposes of this script. Text in bold indicates instructions that exist within the current script, as seen on the OP.

Iterate through features within IlCounties layer, and do the following for each feature:

Zoom to feature
Select all features not equal to feature within IlCounties
Export selection as new layer, add to Detail Map dataframe
Update new layer to incorporate symbology of Export_Output_21

Add new layer to a second existing dataframe (named Locator Map)
Replace MXD title element to IlCounties feature name
Export as PDF

I'm mostly just seeking help for the instructions in bold at the moment. I'll answer your questions and suggestions directly come Monday. Thank you!


Now that I read your post more carefully, I can make what you are "asking" for much simpler.

How about this:

import arcpy

mxDoc = arcpy.mapping.MapDocument(r"X:/GisResources/Mxd Map Templates/HighUnemploymentCensusTracts_Template.mxd")
out_pdf = r"X:/GisResources/NewPDF.pdf")

ExportToPDF (mxDoc, out_pdf,resolution=266)



Since "Iterate through features within IlCounties layer, and do the following for each feature"
and then "Select all features not equal to feature within IlCounties" if you are selecting for all features that are not equal to the same features you are comparing it to, you will always get zero results, so the rest of the code is not needed.  :cool:

Still a little confused about what you are after I guess.  Also, what is the end result/purpose of this?

My "similar" scripts, I just put a definition query on my layer(s) (same layer in both dataframes), then export to pdf.

Most the time, there would be no need to actually make a new layer, then add to the mxd unless your end result is actually to get the "new" FC created.

It almost sounds like you are just after a pdf with a map of all features minus one (without the current one).

In this case, I would just iterate through the OID's, set a definition query to OID <> iterOID (on a copy of the IlCounties layer in both df, with symbology applied)

update thet text,
then dump to PDF

This way, no need to create, add, update layers/and or symbology.  Symbology would be set, definition query would determine features displayed.

OID <> iterOID as a definition query would display ALL features in IlCounties that do not match the currently "selected" feature.

I realize this post was initially about applying symbology, but, if you were to define your final objectives, there may be a much easier/faster way to accomplish it.

R_

R_
0 Kudos
BenjaminBauman
Occasional Contributor
Thank you both rzufelt and mdenil for your suggestions, and apologies for not responding to your input yesterday (had to resolve something else). I was overwhelmed by the amount of advice I got! This is obviously a very supportive forum. The issue was resolved by rzufelt's suggestion to set the MXD to "current".

I incorporated additional suggestions into my script on a piecemeal basis. The completed script can be seen below. By the way, rzufelt - you were wondering what my intentions were. I was intending to create a batch set of maps, one per county, describing areas of high unemployment. An example of the end result can be seen on the attachment. Luckily, the majority of the layout elements were not dynamic, with the exception of the subtitle, so customized changes did not have to be incorporated into the script.

import arcpy
from arcpy import analysis, env

workspace = arcpy.env.workspace = r"C:/temp"

env.overwriteOutput = True

mxDoc = arcpy.mapping.MapDocument("CURRENT")

df = arcpy.mapping.ListDataFrames(mxDoc, "Detail Map") [0]
df2 = arcpy.mapping.ListDataFrames(mxDoc, "Locator Map") [0]

co_layer = arcpy.mapping.ListLayers(mxDoc,"",df) [-1]

co_name = "NAME"

rows = arcpy.SearchCursor(co_layer)

for row in rows:
    co = row.getValue(co_name)
    whereClause = "NAME <> '%s'" % co
    analysis.Select(co_layer, "Co_%s" % co, whereClause)
    arcpy.ApplySymbologyFromLayer_management("Co_%s" % co, "Export_Output_21")
    lyr = arcpy.mapping.ListLayers(mxDoc, "", df)[0]
    arcpy.mapping.AddLayer(df2, lyr)
    whereClause2 = "NAME = '%s'" % co
    analysis.Select(co_layer, "Co_%s1" % co, whereClause2)
    lyr = arcpy.mapping.ListLayers(mxDoc, "", df)[0]
    lyr1 = arcpy.mapping.ListLayers(mxDoc, "", df)[1]
    lyr2 = arcpy.mapping.ListLayers(mxDoc, "", df2)[0]
    df.extent = lyr.getSelectedExtent(True)
    arcpy.mapping.RemoveLayer(df, lyr)
    title = arcpy.mapping.ListLayoutElements(mxDoc, "TEXT_ELEMENT", "*")[0]
    title.text = "%s County" % co
    arcpy.mapping.ExportToPDF(mxDoc, r"C:/temp/ProjectDataFrame%s.pdf" % co)
    arcpy.mapping.RemoveLayer(df, lyr1)
    arcpy.mapping.RemoveLayer(df2, lyr2)
    arcpy.RefreshActiveView() 
0 Kudos