From 19ed98876097dac2ffd4c8d78e69643d2873dfda Mon Sep 17 00:00:00 2001 From: Thomas Fuhrmann Date: Fri, 21 Feb 2025 10:07:53 +0100 Subject: [PATCH] Change color code X to transparent --- FeatureRenderer.pyt | 511 ++++++++++++++++++++++---------------------- 1 file changed, 255 insertions(+), 256 deletions(-) diff --git a/FeatureRenderer.pyt b/FeatureRenderer.pyt index 995065a..dc83c57 100644 --- a/FeatureRenderer.pyt +++ b/FeatureRenderer.pyt @@ -288,13 +288,13 @@ class FeatureRenderer: for layer in map_layers: if layer.name == input_layer: - layers_to_render.append(layer.name) + layers_to_render.append(layer) present = True break if not present: added_layer = active_map.addDataFromPath(input_layer) - layers_to_render.append(added_layer.name) + layers_to_render.append(added_layer) # Retrieve styles that are currently in the project project_styles = project.styles @@ -345,9 +345,11 @@ class FeatureRenderer: custom_labels[row[0]] = f"{row[1]}{label_delimieter}{row[2]}" elif len(fields) == 2: if label_field_1 == primary_key_field: - custom_labels[row[0]] = f"{row[0]}{label_delimieter}{row[1]}" + custom_labels[row[0]] = ( + f"{row[0]}{label_delimieter}{row[1]}" + ) else: - custom_labels[row[0]] = f"{row[1]}" + custom_labels[row[0]] = f"{row[1]}" elif len(fields) == 1: custom_labels[row[0]] = f"{row[0]}" @@ -378,138 +380,87 @@ class FeatureRenderer: outline_codes[str(row[0])] = row[1] # Start rendering process - for layer in map_layers: - if layer.name in layers_to_render: - messages.AddMessage(f"Rendering layer: {layer.name}") + for layer in layers_to_render: + messages.AddMessage(f"Rendering layer: {layer.name}") - sym = layer.symbology - layer_desc = arcpy.Describe(layer) - layer_shape_type = layer_desc.featureClass.shapeType + sym = layer.symbology + layer_desc = arcpy.Describe(layer) + layer_shape_type = layer_desc.featureClass.shapeType - # Check if UniqueValueRenderer is defined - if sym.renderer == "UniqueValueRenderer": - # Apply symbols from gallery - for group in sym.renderer.groups: - for item in group.items: - if item.values[0][0] != "": - leg_id = str(item.values[0][0]) + # Check if UniqueValueRenderer is defined + if sym.renderer == "UniqueValueRenderer": + # Apply symbols from gallery + for group in sym.renderer.groups: + for item in group.items: + if item.values[0][0] != "": + leg_id = str(item.values[0][0]) + else: + leg_id = None + + if leg_id in symbol_codes: + symbol_code = get_symbol_code_for_shape( + layer_shape_type, symbol_codes[leg_id] + ) + + if symbol_code == "#": + continue + + code_components = get_code_components(symbol_code, leg_id) + symbol_key = code_components["symbol_key"] + + if symbol_key: + symbols_from_gallery = ( + item.symbol.listSymbolsFromGallery(symbol_key) + ) + symbol_found = False + for symbol_from_gallery in symbols_from_gallery: + if symbol_from_gallery.name == symbol_key: + symbol_found = True + item.symbol = symbol_from_gallery + break + + # Print message if symbol could not be found + if not symbol_found: + arcpy.AddWarning( + f"Could not find symbol in gallery {symbol_key}" + ) + else: + arcpy.AddWarning(f"{leg_id} is not in legend table") + + # Add user defined labels + if add_labels: + if leg_id in custom_labels: + item.label = custom_labels[leg_id] + + layer.symbology = sym + + # Retrieve CIM to add colors + cim_lyr = layer.getDefinition("V3") + + # Retrieve stroke symbol properties + stroke_symbol_props = {} + if layer_shape_type == "Polygon": + for group in cim_lyr.renderer.groups: + for unique_value_class in group.classes: + if unique_value_class.values[0].fieldValues[0] != "": + leg_id = str( + unique_value_class.values[0].fieldValues[0] + ) else: leg_id = None - if leg_id in symbol_codes: - symbol_code = get_symbol_code_for_shape( - layer_shape_type, symbol_codes[leg_id] - ) + stroke_symbol_props[leg_id] = { + "color": None, + "width": None, + } - if symbol_code == "#": - continue - - code_components = get_code_components( - symbol_code, leg_id - ) - symbol_key = code_components["symbol_key"] - - if symbol_key: - symbols_from_gallery = ( - item.symbol.listSymbolsFromGallery(symbol_key) - ) - symbol_found = False - for symbol_from_gallery in symbols_from_gallery: - if symbol_from_gallery.name == symbol_key: - symbol_found = True - item.symbol = symbol_from_gallery - break - - # Print message if symbol could not be found - if not symbol_found: - arcpy.AddWarning( - f"Could not find symbol in gallery {symbol_key}" - ) - else: - arcpy.AddWarning(f"{leg_id} is not in legend table") - - # Add user defined labels - if add_labels: - if leg_id in custom_labels: - item.label = custom_labels[leg_id] - - layer.symbology = sym - - # Retrieve CIM to add colors - cim_lyr = layer.getDefinition("V3") - - # Retrieve stroke symbol properties - stroke_symbol_props = {} - if layer_shape_type == "Polygon": - for group in cim_lyr.renderer.groups: - for unique_value_class in group.classes: - if ( - unique_value_class.values[0].fieldValues[0] - != "" + for ( + symbol_layer + ) in unique_value_class.symbol.symbol.symbolLayers: + if isinstance( + symbol_layer, + arcpy.cim.CIMSymbols.CIMSolidStroke, ): - leg_id = str( - unique_value_class.values[0].fieldValues[0] - ) - else: - leg_id = None - - stroke_symbol_props[leg_id] = { - "color": None, - "width": None, - } - - for ( - symbol_layer - ) in unique_value_class.symbol.symbol.symbolLayers: - if isinstance( - symbol_layer, - arcpy.cim.CIMSymbols.CIMSolidStroke, - ): - if leg_id in outline_codes: - # Set user defined outline color - outline_code = outline_codes[leg_id] - - if ( - not outline_code - ) or outline_code == "#": - outline_code = CODE_BLK - - color_value = get_symbol_color(outline_code) - - color = ( - arcpy.cim.CreateCIMObjectFromClassName( - "CIMCMYKColor", "V3" - ) - ) - color.values = color_value["CMYK"] - stroke_symbol_props[leg_id]["color"] = color - else: - if symbol_layer.color: - # Set color as it was before - stroke_symbol_props[leg_id][ - "color" - ] = symbol_layer.color - else: - # Set default color - color = arcpy.cim.CreateCIMObjectFromClassName( - "CIMCMYKColor", "V3" - ) - color.values = DEFAULT_COLOR - stroke_symbol_props[leg_id][ - "color" - ] = color - - # Get symbol layer line width - if symbol_layer.width: - # Set width as it was before - stroke_symbol_props[leg_id][ - "width" - ] = symbol_layer.width - - break - - # In case the layer did not have a stroke symbol layer or outline color - if not stroke_symbol_props[leg_id]["color"]: if leg_id in outline_codes: # Set user defined outline color outline_code = outline_codes[leg_id] @@ -518,150 +469,185 @@ class FeatureRenderer: outline_code = CODE_BLK color_value = get_symbol_color(outline_code) + color = arcpy.cim.CreateCIMObjectFromClassName( "CIMCMYKColor", "V3" ) color.values = color_value["CMYK"] stroke_symbol_props[leg_id]["color"] = color else: - # Set default color - color = arcpy.cim.CreateCIMObjectFromClassName( - "CIMCMYKColor", "V3" - ) - color.values = DEFAULT_COLOR - stroke_symbol_props[leg_id]["color"] = color + if symbol_layer.color: + # Set color as it was before + stroke_symbol_props[leg_id][ + "color" + ] = symbol_layer.color + else: + # Set default color + color = ( + arcpy.cim.CreateCIMObjectFromClassName( + "CIMCMYKColor", "V3" + ) + ) + color.values = DEFAULT_COLOR + stroke_symbol_props[leg_id]["color"] = color - # Set outline width - if draw_outlines: - if outline_width: - stroke_symbol_props[leg_id][ - "width" - ] = outline_width - else: - if not stroke_symbol_props[leg_id]["width"]: + # Get symbol layer line width + if symbol_layer.width: + # Set width as it was before stroke_symbol_props[leg_id][ "width" - ] = DEFAULT_LINE_WIDTH + ] = symbol_layer.width + + break + + # In case the layer did not have a stroke symbol layer or outline color + if not stroke_symbol_props[leg_id]["color"]: + if leg_id in outline_codes: + # Set user defined outline color + outline_code = outline_codes[leg_id] + + if (not outline_code) or outline_code == "#": + outline_code = CODE_BLK + + color_value = get_symbol_color(outline_code) + color = arcpy.cim.CreateCIMObjectFromClassName( + "CIMCMYKColor", "V3" + ) + color.values = color_value["CMYK"] + stroke_symbol_props[leg_id]["color"] = color else: - stroke_symbol_props[leg_id]["width"] = 0 + # Set default color + color = arcpy.cim.CreateCIMObjectFromClassName( + "CIMCMYKColor", "V3" + ) + color.values = DEFAULT_COLOR + stroke_symbol_props[leg_id]["color"] = color - new_groups = [] - for group in cim_lyr.renderer.groups: - for unique_value_class in group.classes: - - if unique_value_class.values[0].fieldValues[0] != "": - leg_id = str( - unique_value_class.values[0].fieldValues[0] - ) + # Set outline width + if draw_outlines: + if outline_width: + stroke_symbol_props[leg_id]["width"] = outline_width + else: + if not stroke_symbol_props[leg_id]["width"]: + stroke_symbol_props[leg_id][ + "width" + ] = DEFAULT_LINE_WIDTH else: - leg_id = None + stroke_symbol_props[leg_id]["width"] = 0 - if leg_id in symbol_codes: - symbol_code = get_symbol_code_for_shape( - layer_shape_type, symbol_codes[leg_id] - ) - if symbol_code == "#": - continue + new_groups = [] + for group in cim_lyr.renderer.groups: + for unique_value_class in group.classes: - code_components = get_code_components( - symbol_code, leg_id - ) - color_value = code_components["color"] - symbol_color_value = code_components["symbol_color"] + if unique_value_class.values[0].fieldValues[0] != "": + leg_id = str(unique_value_class.values[0].fieldValues[0]) + else: + leg_id = None - has_background_color = False - for ( - symbol_layer - ) in unique_value_class.symbol.symbol.symbolLayers: - if symbol_color_value: - update_symbol_layer_colors( - symbol_layer, symbol_color_value - ) + if leg_id in symbol_codes: + symbol_code = get_symbol_code_for_shape( + layer_shape_type, symbol_codes[leg_id] + ) + if symbol_code == "#": + continue - if color_value: - # Update background colors - if layer_shape_type == "Polygon": - if isinstance( - symbol_layer, - arcpy.cim.CIMSymbols.CIMSolidFill, - ): - update_color(symbol_layer, color_value) - has_background_color = True + code_components = get_code_components(symbol_code, leg_id) + color_value = code_components["color"] + symbol_color_value = code_components["symbol_color"] - if isinstance( - symbol_layer, - arcpy.cim.CIMSymbols.CIMSolidStroke, - ): - symbol_layer.width = ( - stroke_symbol_props[leg_id]["width"] - ) - symbol_layer.color = ( - stroke_symbol_props[leg_id]["color"] - ) + has_background_color = False + for ( + symbol_layer + ) in unique_value_class.symbol.symbol.symbolLayers: + if symbol_color_value: + update_symbol_layer_colors( + symbol_layer, symbol_color_value + ) - # Draw symbol background colors - if not has_background_color and color_value: + if color_value: + # Update background colors if layer_shape_type == "Polygon": - # Add fill symbol layer - fill_symbol = arcpy.cim.CIMSolidFill() - update_color(fill_symbol, color_value) + if isinstance( + symbol_layer, + arcpy.cim.CIMSymbols.CIMSolidFill, + ): + update_color(symbol_layer, color_value) + has_background_color = True - unique_value_class.symbol.symbol.symbolLayers.append( - fill_symbol - ) - - # Add stroke symbol layer - if stroke_symbol_props[leg_id]: - stroke_symbol = arcpy.cim.CIMSolidStroke() - stroke_symbol.color = stroke_symbol_props[ - leg_id - ]["color"] - stroke_symbol.width = stroke_symbol_props[ + if isinstance( + symbol_layer, + arcpy.cim.CIMSymbols.CIMSolidStroke, + ): + symbol_layer.width = stroke_symbol_props[ leg_id ]["width"] + symbol_layer.color = stroke_symbol_props[ + leg_id + ]["color"] - # Insert at the beginning such that it appears on top of solid fill layer - unique_value_class.symbol.symbol.symbolLayers.insert( - 0, stroke_symbol - ) + # Draw symbol background colors + if not has_background_color and color_value: + if layer_shape_type == "Polygon": + # Add fill symbol layer + fill_symbol = arcpy.cim.CIMSolidFill() + update_color(fill_symbol, color_value) - # Regroup items - if heading_field: - if leg_id in headings: - heading = headings[leg_id] - if not heading: - heading = "Other" - else: - heading = "Other" - - matched_group = next( - ( - group - for group in new_groups - if group.heading == heading - ), - None, - ) - if matched_group: - matched_group.classes.append(unique_value_class) - else: - new_group = arcpy.cim.CreateCIMObjectFromClassName( - "CIMUniqueValueGroup", "V3" + unique_value_class.symbol.symbol.symbolLayers.append( + fill_symbol ) - new_group.heading = heading - new_group.classes.append(unique_value_class) - new_groups.append(new_group) - if heading_field: - cim_lyr.renderer.groups = new_groups + # Add stroke symbol layer + if stroke_symbol_props[leg_id]: + stroke_symbol = arcpy.cim.CIMSolidStroke() + stroke_symbol.color = stroke_symbol_props[ + leg_id + ]["color"] + stroke_symbol.width = stroke_symbol_props[ + leg_id + ]["width"] - # Push changes back to layer object - layer.setDefinition(cim_lyr) + # Insert at the beginning such that it appears on top of solid fill layer + unique_value_class.symbol.symbol.symbolLayers.insert( + 0, stroke_symbol + ) - else: - raise ValueError( - f"Execution aborted: please apply a Unique Value Renderer to layer {layer.name}" - ) + # Regroup items + if heading_field: + if leg_id in headings: + heading = headings[leg_id] + if not heading: + heading = "Other" + else: + heading = "Other" + + matched_group = next( + ( + group + for group in new_groups + if group.heading == heading + ), + None, + ) + if matched_group: + matched_group.classes.append(unique_value_class) + else: + new_group = arcpy.cim.CreateCIMObjectFromClassName( + "CIMUniqueValueGroup", "V3" + ) + new_group.heading = heading + new_group.classes.append(unique_value_class) + new_groups.append(new_group) + + if heading_field: + cim_lyr.renderer.groups = new_groups + + # Push changes back to layer object + layer.setDefinition(cim_lyr) + + else: + raise ValueError( + f"Execution aborted: please apply a Unique Value Renderer to layer {layer.name}" + ) def postExecute(self, _): return @@ -677,10 +663,12 @@ def update_symbol_layer_colors(symbol_layer, symbol_color_value): if isinstance(symbol_layer, arcpy.cim.CIMSymbols.CIMSolidStroke): update_color(symbol_layer, symbol_color_value) - if isinstance(symbol_layer, arcpy.cim.CIMSymbols.CIMHatchFill) and hasattr(symbol_layer, "lineSymbol"): + if isinstance(symbol_layer, arcpy.cim.CIMSymbols.CIMHatchFill) and hasattr( + symbol_layer, "lineSymbol" + ): for sub_symbol_layer in symbol_layer.lineSymbol.symbolLayers: update_color(sub_symbol_layer, symbol_color_value) - + if isinstance( symbol_layer, arcpy.cim.CIMSymbols.CIMCharacterMarker, @@ -710,6 +698,7 @@ def get_symbol_code_for_shape(shape_type, symbol_codes): ) +# code has three components: fill color, symbol key, symbol color def get_code_components(code, leg_id): code_len = len(code) if code_len == 4: @@ -749,15 +738,25 @@ def get_code_components(code, leg_id): def decode_color(color_string, leg_id): - return { - "CMYK": [ - get_percentage_from_letter(color_string[0], leg_id), - get_percentage_from_letter(color_string[1], leg_id), - get_percentage_from_letter(color_string[2], leg_id), - get_percentage_from_letter(color_string[3], leg_id), - 100, - ], - } + if color_string[3] == "X": + return { + "CMYK": [ + 0, + 0, + 0, + 0, + ], + } + else: + return { + "CMYK": [ + get_percentage_from_letter(color_string[0], leg_id), + get_percentage_from_letter(color_string[1], leg_id), + get_percentage_from_letter(color_string[2], leg_id), + get_percentage_from_letter(color_string[3], leg_id), + 100, + ], + } def get_percentage_from_letter(letter, leg_id):