Source code for wrf_nlcd_lulc_converter.colormap

"""
Colormap and normalization utilities for WRF NLCD LULC converter.
"""

import matplotlib.colors as mcolors
import matplotlib.pyplot as plt
import numpy as np


[docs] def get_lulc_colormap(): """ Get the 40-class LULC colormap from the original notebook. Returns: tuple: (colormap, labels, colors, vmin, vmax) """ # Define the exact 40-class LULC mapping from the notebook lulc_dict = { 1: {"label": "Evergreen Needleleaf Forest", "color": "#05450a"}, 2: {"label": "Evergreen Broadleaf Forest", "color": "#086a10"}, 3: {"label": "Deciduous Needleleaf Forest", "color": "#54a708"}, 4: {"label": "Deciduous Broadleaf Forest", "color": "#78d203"}, 5: {"label": "Mixed Forests", "color": "#009900"}, 6: {"label": "Closed Shrublands", "color": "#c6b044"}, 7: {"label": "Open Shrublands", "color": "#dcd159"}, 8: {"label": "Woody Savannas", "color": "#dade48"}, 9: {"label": "Savannas", "color": "#fbff13"}, 10: {"label": "Grasslands", "color": "#b6ff05"}, 11: {"label": "Permanent Wetlands", "color": "#27ff87"}, 12: {"label": "Croplands", "color": "#006400"}, 13: {"label": "Urban and Built Up", "color": "#FF0000"}, 14: {"label": "Cropland/Natural Vegetation Mosaic", "color": "#ADFF2F"}, 15: {"label": "Permanent Snow and Ice", "color": "#69fff8"}, 16: {"label": "Barren or Sparsely Vegetated", "color": "#f9ffa4"}, 17: {"label": "IGBP Water", "color": "#1c0dff"}, 18: {"label": "Unclassified", "color": "#cccccc"}, 19: {"label": "Fill Value", "color": "#999999"}, 20: {"label": "Unclassified", "color": "#cccccc"}, 21: {"label": "Open Water", "color": "#1c0dff"}, 22: {"label": "Perennial Ice/Snow", "color": "#69fff8"}, 23: {"label": "Developed Open Space", "color": "#ffb3b3"}, 24: {"label": "Developed Low Intensity", "color": "#ff6666"}, 25: {"label": "Developed Medium Intensity", "color": "#cc0000"}, 26: {"label": "Developed High Intensity", "color": "#990000"}, 27: {"label": "Barren Land (Rock/Sand/Clay)", "color": "#e2e2e2"}, 28: {"label": "Deciduous Forest", "color": "#b2df8a"}, 29: {"label": "Evergreen Forest", "color": "#33a02c"}, 30: {"label": "Mixed Forest", "color": "#6a3d9a"}, 31: {"label": "Dwarf Scrub", "color": "#cab2d6"}, 32: {"label": "Shrub/Scrub", "color": "#ffff99"}, 33: {"label": "Grassland/Herbaceous", "color": "#b15928"}, 34: {"label": "Sedge/Herbaceous", "color": "#8dd3c7"}, 35: {"label": "Lichens", "color": "#fb8072"}, 36: {"label": "Moss", "color": "#80b1d3"}, 37: {"label": "Pasture/Hay", "color": "#fdb462"}, 38: {"label": "Cultivated Crops", "color": "#ffd92f"}, 39: {"label": "Woody Wetlands", "color": "#a6cee3"}, 40: {"label": "Emergent Herbaceous Wetlands", "color": "#1f78b4"}, } # Extract color list and label list in order for plotting lulc_colors = [lulc_dict[i]["color"] for i in range(1, 41)] lulc_labels = [lulc_dict[i]["label"] for i in range(1, 41)] # Create colormap cmap_40 = mcolors.ListedColormap(lulc_colors) # Define normalization bounds vmin = 1 - 0.5 vmax = 40 + 0.5 return cmap_40, lulc_labels, lulc_colors, vmin, vmax
[docs] def get_lulc_normalization(): """ Get the normalization for LULC data plotting. Returns: tuple: (vmin, vmax, ticks, tick_labels) """ _, labels, _, vmin, vmax = get_lulc_colormap() # Create ticks and tick labels ticks = np.arange(1, 41) tick_labels = [f"{i+1}: {labels[i]}" for i in range(40)] return vmin, vmax, ticks, tick_labels
[docs] def get_urban_colormap(): """ Get a colormap specifically for urban classes (21-26). Returns: tuple: (colormap, labels, colors, vmin, vmax) """ # Urban class colors urban_colors = [ "#1c0dff", # 21: Open Water "#69fff8", # 22: Perennial Ice/Snow "#ffb3b3", # 23: Developed Open Space "#ff6666", # 24: Developed Low Intensity "#cc0000", # 25: Developed Medium Intensity "#990000", # 26: Developed High Intensity ] urban_labels = [ "Open Water", "Perennial Ice/Snow", "Developed Open Space", "Developed Low Intensity", "Developed Medium Intensity", "Developed High Intensity" ] # Create colormap cmap_urban = mcolors.ListedColormap(urban_colors) # Define normalization bounds vmin = 21 - 0.5 vmax = 26 + 0.5 return cmap_urban, urban_labels, urban_colors, vmin, vmax
[docs] def get_urban_normalization(): """ Get the normalization for urban data plotting. Returns: tuple: (vmin, vmax, ticks, tick_labels) """ _, labels, _, vmin, vmax = get_urban_colormap() # Create ticks and tick labels ticks = np.arange(21, 27) tick_labels = [f"{i}: {labels[i-21]}" for i in range(21, 27)] return vmin, vmax, ticks, tick_labels
[docs] def create_colorbar(ax, mappable, orientation='vertical', fraction=0.046, pad=0.04): """ Create a standardized colorbar for LULC plots. Parameters: ax: Matplotlib axes object mappable: Mappable object (e.g., pcolormesh result) orientation (str): Colorbar orientation fraction (float): Colorbar fraction pad (float): Colorbar padding Returns: matplotlib.colorbar.Colorbar: The created colorbar """ vmin, vmax, ticks, tick_labels = get_lulc_normalization() cbar = plt.colorbar(mappable, ax=ax, orientation=orientation, fraction=fraction, pad=pad, ticks=ticks) cbar.set_label('LULC Class') cbar.set_ticks(ticks) cbar.set_ticklabels(tick_labels) return cbar
[docs] def create_urban_colorbar(ax, mappable, orientation='vertical', fraction=0.046, pad=0.04): """ Create a standardized colorbar for urban plots. Parameters: ax: Matplotlib axes object mappable: Mappable object (e.g., pcolormesh result) orientation (str): Colorbar orientation fraction (float): Colorbar fraction pad (float): Colorbar padding Returns: matplotlib.colorbar.Colorbar: The created colorbar """ vmin, vmax, ticks, tick_labels = get_urban_normalization() cbar = plt.colorbar(mappable, ax=ax, orientation=orientation, fraction=fraction, pad=pad, ticks=ticks) cbar.set_label('Urban LULC Class') cbar.set_ticks(ticks) cbar.set_ticklabels(tick_labels) return cbar
[docs] def get_class_info(class_number): """ Get information for a specific LULC class. Parameters: class_number (int or float): LULC class number (1-40) Returns: dict: Dictionary with 'label' and 'color' keys """ cmap, labels, colors, _, _ = get_lulc_colormap() # Convert to integer if it's a float class_number = int(class_number) if 1 <= class_number <= 40: return { "label": labels[class_number - 1], "color": colors[class_number - 1] } else: return {"label": "Unknown", "color": "#000000"}
[docs] def get_urban_classes(): """ Get list of urban development classes. Returns: list: List of urban class numbers """ return [21, 22, 23, 24, 25, 26]
[docs] def plot_colormap_legend(save_path=None, dpi=150): """ Create a legend showing all LULC classes and their colors. Parameters: save_path (str): Path to save the legend (optional) dpi (int): DPI for saved image """ cmap, labels, colors, _, _ = get_lulc_colormap() fig, ax = plt.subplots(1, 1, figsize=(12, 16)) # Create color patches for i, (label, color) in enumerate(zip(labels, colors)): ax.add_patch(plt.Rectangle((0, i), 1, 1, facecolor=color, edgecolor='black')) ax.text(1.1, i + 0.5, f"{i+1:2d}: {label}", va='center', fontsize=10) ax.set_xlim(0, 8) ax.set_ylim(0, 40) ax.set_title("LULC Class Legend", fontsize=14, fontweight='bold') ax.axis('off') if save_path: plt.savefig(save_path, dpi=dpi, bbox_inches='tight') print(f"Legend saved to: {save_path}") plt.show() return fig, ax