ApplySymbologyFromLayer_management Not Updating Layer

3208
7
Jump to solution
01-02-2014 11:40 AM
JonathanMulder
New Contributor III
import arcpy
import arcpy.mapping
import datetime
import os
arcpy.env.overwriteOutput = True
I've been struggling with this for a few hours in a rather large script, so I trimmed it down to just a few lines of code.  It seems the "ApplySymbologyFromLayer_management" process doesn't come across.  I've looked at my lyr file in ArcCatalog and the color ramp is there.  Any ideas?  The lyr file is also "Time-enabled", if that makes any difference.

Jon Mulder
California Depertment of Water Resources

 ##Add GSE_AllContours3D Featureclass to map. mxd = arcpy.mapping.MapDocument("Current") df = arcpy.mapping.ListDataFrames(mxd)[0] FeatureClassToAdd = "G:\Documents\GIS\HydstraData\HydstraMeasurementsDeep\Contours_Daily_20130625_20130731.gdb\WSE_AllContours3D" InSymbologyLayer = "G:\Documents\GIS\HydstraData\Template_Contours.lyr" TempLayer = "WSE_Contours" # Make a layer from the feature class arcpy.MakeFeatureLayer_management(FeatureClassToAdd,TempLayer) addLayer = arcpy.mapping.Layer(TempLayer) arcpy.mapping.AddLayer(df, addLayer, "AUTO_ARRANGE") arcpy.ApplySymbologyFromLayer_management(addLayer, InSymbologyLayer) arcpy.RefreshTOC()
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
TonyAlmeida
Occasional Contributor II
I beleive you are missing arcpy.mapping.ListLayers.

http://resources.arcgis.com/en/help/main/10.1/index.html#//00s300000008000000

Instead of using arcpy.ApplySymbologyFromLayer_management i use
arcpy.mapping.UpdateLayer, so you might what to try that.

View solution in original post

0 Kudos
7 Replies
TonyAlmeida
Occasional Contributor II
I beleive you are missing arcpy.mapping.ListLayers.

http://resources.arcgis.com/en/help/main/10.1/index.html#//00s300000008000000

Instead of using arcpy.ApplySymbologyFromLayer_management i use
arcpy.mapping.UpdateLayer, so you might what to try that.
0 Kudos
JonathanMulder
New Contributor III
Ah!  That did the trick.  I never have understood what the "arcpy.mapping.ListLayers" function was for, although I have seen it a lot in the examples.  I always thought it was to iterate through several layers.  But, if I understand correctly from the link you sent me, I have to make a Python list (consisting of one variable -- i.e. one layer) and then apply the symbology.

Thanks very much!  I'm on the road again!

import arcpy
import arcpy.mapping
import datetime
import os
arcpy.env.overwriteOutput = True


##Add GSE_AllContours3D Featureclass to map.
mxd = arcpy.mapping.MapDocument("Current")
df = arcpy.mapping.ListDataFrames(mxd)[0]
FeatureClassToAdd = "G:\Documents\GIS\HydstraData\HydstraMeasurementsDeep\Contours_Daily_20130625_20130731.gdb\WSE_AllContours3D"
InSymbologyLayer = "G:\Documents\GIS\HydstraData\Template_Contours.lyr"
TempLayer = "WSE_Contours"
# Make a layer from the feature class
arcpy.MakeFeatureLayer_management(FeatureClassToAdd,TempLayer)
addLayer = arcpy.mapping.Layer(TempLayer)
arcpy.mapping.AddLayer(df, addLayer, "AUTO_ARRANGE")
for lyr in arcpy.mapping.ListLayers(mxd, "WSE_Contours", df):
    arcpy.ApplySymbologyFromLayer_management(lyr, InSymbologyLayer)
arcpy.RefreshTOC()
0 Kudos
TonyAlmeida
Occasional Contributor II
You should have to loop since it's not repeating. For better practice i would place the arcpy.mapping.ListLayers like this.

mxd = arcpy.mapping.MapDocument("Current")
df = arcpy.mapping.ListDataFrames(mxd)[0]
lyr = arcpy.mapping.ListLayers(mxd, "WSE_Contours", df)
0 Kudos
T__WayneWhitley
Frequent Contributor
Not bad Tony - just remember, all the listing functions return a list.  That means if you're expecting a single item returned, you need to 'get it' from the list with [0].   Just as you did listing data frames...[0] means you're getting the 1st item in the list (which with a single item returned, then return that item).


@Jon, just curious, is there any reason you cannot do something like the following (I didn't test), applying the symbology before adding it to the map?:
addLayer = arcpy.mapping.Layer(TempLayer)
arcpy.ApplySymbologyFromLayer_management(addLayer, InSymbologyLayer)
arcpy.mapping.AddLayer(df, addLayer, "AUTO_ARRANGE")
0 Kudos
JonathanMulder
New Contributor III
Wayne and Tony,

Thanks very much for your inputs!

Ultimately, I went back to the process of adding a layer file, then replacing the DataSource for the layer with another one in a geodatabase that the user selects.  The "ApplySymbologyFromLayer" only applies the Symbology properties from the layer.  My saved template layers also have Label and Time properties.  So, adding a Layer file then replacing the datasource made the best sense.

Wayne, I also wanted to let you know that I've solved the issue with "Time-Enabled Layers.  The template layers have to be time-enabled before adding to map.  After that, it's somewhat simple to modify dataframe time properties.  I have another script that actually generates the daily contours and places them (and the surface rasters) into a newly created geodatabase.  The geodatabase naming convention follows the format of "Contours_" + TimeInterval + DateStart + DateEnd (i.e., "Contours_Daily_20130625_20130731" or "Contours_Monthly_20110101_20131231").  By splitting out the GeoDatabase name, I am able to assign the time.timeWindowUnits, time.startTime, and time.endTime.  It's pretty slick; get back to me if you want more information.

Another issue that I had was graduated color-ramping the contours from red (lowest) to green (highest).  The issue is that the template layer symbology is for another set of contours that are not always the sample elevation range.  So some analysis of the Contours Featureclass "Contour" field was needed.  This was done by using a little Python code snippet ("SortedContours = unique_values(Contours_lyr, "Contour") that provided a sorted python list of unique contour values.  From the list, I derived the following:


  •     LowestContour = SortedContours[0]

  •     HighestContour = SortedContours[-1]

  •     ContourInterval = SortedContours[1] - SortedContours[0]

  •     TotalContours = len(SortedContours)

An additional contour was inserted into theSortedContours below the lowest contour value.  This is because you need one more classBreakValue then your actual contour values.  Then, I spun out a string list of the SortedContour list (and deleted the first value) to use as the classBreakLabels.  Reading the GraduatedColorsSymbology help was invaluable.

On a final note, if you glance at my code, you'll notice that I actually have two Contours Featureclasses.  This is because groundwater contours can be portrayed in two different ways: Water Surface Elevation (WSE) or Depth To Water (DTW).  The DTW contours are very useful for identifying how deep a well needs to be to reach groundwater.

Next step is to run a few time-step simulations and spin them out to movie files.  Let me know if you'd like to take a look at them.

Thanks for all your help!

Jon Mulder
Engineering Geologist
California Department of Water Resources

import arcpy
import arcpy.mapping
import datetime
import os

def AddContours(DataType,LayerFileNameAndLocation):
    Contours_lyr = arcpy.mapping.Layer(LayerFileNameAndLocation)
    Contours_lyr.replaceDataSource(GeoDatabaseNameAndLocation,"NONE",DataType + "_AllContours3D")
    if Contours_lyr.supports("LABELCLASSES"):
        arcpy.AddMessage("LABELCLASSES are supported.")
        Contours_lyr.labelClasses[0].expression =  "[Contour]"
        Contours_lyr.showLabels = True
    if Contours_lyr.symbologyType == "GRADUATED_COLORS":
        arcpy.AddMessage("GRADUATED_COLORS are supported.")
    ##Create a List of unique Contour values.    
    SortedContours = unique_values(Contours_lyr, "Contour")
    arcpy.AddMessage(SortedContours)
    LowestContour = SortedContours[0]
    HighestContour = SortedContours[-1]
    ContourInterval = SortedContours[1] - SortedContours[0]
    TotalContours = len(SortedContours)
    arcpy.AddMessage("Lowest contour: " + str(LowestContour))
    arcpy.AddMessage("Highest contour: " + str(HighestContour))
    arcpy.AddMessage("Contour Interval: " + str(ContourInterval))
    arcpy.AddMessage("Number of Contours: " + str(TotalContours))
    ##Insert an  additional contour before Lowest Contour.
    SortedContours.insert(0,LowestContour - ContourInterval)
    ##arcpy.AddMessage(SortedContours)
    ##Increment Total Contours by 1.
    TotalContours = TotalContours + 1
    ##Assign classBreakValues to SortedContours.
    Contours_lyr.symbology.classBreakValues = SortedContours
    ##Reclassify Color Ramp.
    Contours_lyr.symbology.reclassify()
    ##Create a string List of Sorted Contours for layer labels.
    LabelList = [str(int(i)) for i in SortedContours]
    ##arcpy.AddMessage(LabelList)
    ##Delete first variable in LabelList.
    ##NOTE: This is important because the classBreakLabels MUST be one less than the classBreakValues.
    del LabelList[0]
    ##arcpy.AddMessage(LabelList)
    Contours_lyr.symbology.classBreakLabels = LabelList
    arcpy.mapping.AddLayer(df,Contours_lyr,"BOTTOM")    
    return;

def unique_values(table, field):
     with arcpy.da.SearchCursor(table, [field]) as cursor:
         return sorted({row[0] for row in cursor}) 


GeoDatabaseNameAndLocation = arcpy.GetParameterAsText(0)
LayerFileNameAndLocation_Wells = arcpy.GetParameterAsText(1)
LayerFileNameAndLocation_WSE_Contours = arcpy.GetParameterAsText(2)
LayerFileNameAndLocation_DTW_Contours = arcpy.GetParameterAsText(3)

arcpy.env.overwriteOutput = True
##GeoDatabaseNameAndLocation = "G:\Documents\GIS\HydstraData\HydstraMeasurementsDeep\Contours_Daily_20130625_20130731.gdb"
##LayerFileNameAndLocation_Wells = "G:\Documents\GIS\HydstraData\Template_WellPoints.lyr"
##LayerFileNameAndLocation_WSE_Contours = "G:\Documents\GIS\HydstraData\Template_WSE_Contours.lyr"
##LayerFileNameAndLocation_DTW_Contours = "G:\Documents\GIS\HydstraData\Template_DTW_Contours.lyr"

GeoDatabaseName = os.path.basename(GeoDatabaseNameAndLocation)
GeoDatabaseLocation = os.path.dirname(GeoDatabaseNameAndLocation)
##Split GeoDatabaseName and get variables for later use.
GeoDatabaseSplitParts = GeoDatabaseName.split("_")
TimeInterval = GeoDatabaseSplitParts[1]
arcpy.AddMessage(TimeInterval)
StartTime = GeoDatabaseSplitParts[2]
arcpy.AddMessage(StartTime)
EndTime = GeoDatabaseSplitParts[3][:8]
arcpy.AddMessage(EndTime)

##Determine the TimeWindowUnits.
if TimeInterval == "Daily":
    TimeWindowUnits = "DAYS"
elif TimeInterval == "Weekly":
    TimeWindowUnits = "WEEKS"
elif TimeInterval == "Monthly":
    TimeWindowUnits = "MONTHS"
elif TimeInterval == "Annually":
    TimeWindowUnits = "YEARS"
arcpy.AddMessage(TimeWindowUnits)

##Reference the Current map document.
mxd = arcpy.mapping.MapDocument("CURRENT")
df = arcpy.mapping.ListDataFrames(mxd)[0]

arcpy.env.workspace = GeoDatabaseLocation

##Add WellPoints Featureclass to map.
arcpy.AddMessage("Adding WellPoints Featureclass to map.")
##WellPtsLyrFile = os.path.join(LayerFileLocation,"Template_WellPoints.lyr")
Wells_lyr = arcpy.mapping.Layer(LayerFileNameAndLocation_Wells)
##Replace the Layer DataSource.
Wells_lyr.replaceDataSource(GeoDatabaseNameAndLocation,"NONE","WellPoints")
##Show labels for WellPoints.
if Wells_lyr.supports("LABELCLASSES"):
    Wells_lyr.labelClasses[0].expression =  "[StateWellNumber]"
    Wells_lyr.showLabels = True
arcpy.mapping.AddLayer(df, Wells_lyr, "TOP")

ContoursToAdd = AddContours("WSE",LayerFileNameAndLocation_WSE_Contours)
ContoursToAdd = AddContours("DTW",LayerFileNameAndLocation_DTW_Contours)

if Wells_lyr.supports("TIME"):
    arcpy.AddMessage("TIME is supported.")
    lyrTime = Wells_lyr.time
    if Wells_lyr.time.isTimeEnabled:
        arcpy.AddMessage("TIME is enabled.")
    else:
        arcpy.AddMessage("TIME is NOT enabled.")
else:
    arcpy.AddMessage("TIME is NOT supported.")

StartTime = datetime.datetime.strptime(StartTime,"%Y%m%d")
EndTime = datetime.datetime.strptime(EndTime,"%Y%m%d")

df.time.resetTimeExtent()
df.time.currentTime = StartTime
df.time.startTime = StartTime
df.time.endTime = EndTime
df.time.timeWindowUnits = TimeWindowUnits
df.time.timeWindow = 0

##Turn off the "DTW_Contours" layer.
arcpy.mapping.Layer("DTW_Contours").visible = False
arcpy.RefreshTOC()
arcpy.RefreshActiveView()
0 Kudos
T__WayneWhitley
Frequent Contributor
Wow, good work!...if your script is performing well for you, that's great.  If you have any further questions or performance issues, I'd like to help.  Yes, I'd like to see the movie files when finished - you have my email, and if the files are too large to send, just let me know where you post them.

Wayne
0 Kudos
CarolineMerz
New Contributor
Hey Jon -

I found your post via a google search and was wondering if you had any advice (I know this thread was from a while ago).

I am creating a model for time-enabled layers to display flu data over a period of a year.  I am not sure how this compares to your project but I am having the same issue you had where I needed to enable the time on the layer.  I thought I was going to be able to do this when I did the symbology but -just like you added-there is no place to enable time.

I will try your code out and see if it will work.  But were you able to call the time slider automatically suing your code? Or did you use animation? I saw that you asid something about creating a movie file so I was curious which route you took.  And did you do that through code or manually?

I apologize for all of the questions, especially so far after you posted this.  Any tips or tricks would be great, would love to see the final result of what you did, or anything similar (if you even still have it)!

Thanks!

Caroline
0 Kudos