Source code for ncd

# -*- coding: utf-8 -*-
"""
Created on Wed Sep 25 09:18:24 2024

@author: jablonski
"""

import logging
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import matplotlib.patheffects as path_effects
import matplotlib.patches as mpatches
try:
    from PT3S import Rm
except:
    import Rm

logger = logging.getLogger('PT3S')

[docs]def pNcd_pipes(ax=None, gdf=None, attribute=None, colors=['darkgreen', 'magenta'], legend_fmt=None, legend_values=None, norm_min=None, norm_max=None, query=None, line_width_factor=10, zorder=None): """ pNcd_pipes: Plots pipes on axis with customization options. :param ax: Matplotlib axis object. If None, a new axis is created. :type ax: matplotlib.axes.Axes, optional :param gdf: Geospatial DataFrame containing the data to plot. :type gdf: geopandas.GeoDataFrame :param attribute: Column name in gdf of the data that should be plotted. :type attribute: str :param colors: List of colors to use for the colormap. Default is ['darkgreen', 'magenta']. :type colors: list, optional :param legend_fmt: Legend text for attribute. Default is attribute + '{:.4f}'. :type legend_fmt: str, optional :param legend_values: Specific values to use for value steps in legend. Default is None. :type legend_values: list, optional :param norm_min: Minimum value for normalization. Default is None. :type norm_min: float, optional :param norm_max: Maximum value for normalization. Default is None. :type norm_max: float, optional :param query: Query string to filter the data. Default is None. :type query: str, optional :param line_width_factor: Factor to influence width of the lines in the plot. Default is 10. :type line_width_factor: float, optional :param zorder: Determines order of plotting when calling the function multilpe times. Default is None. :type zorder: float, optional :return: patches. :rtype: matplotlib.patches.Patch """ logStr = "{0:s}.{1:s}: ".format(__name__, sys._getframe().f_code.co_name) logger.debug("{0:s}{1:s}".format(logStr, 'Start.')) try: if ax is None: fig, ax = plt.subplots(figsize=(11.7, 8.3)) # A3 size logger.debug("{0:s}{1:s}".format(logStr, 'Created new axis.')) if gdf is None or gdf.empty: logger.debug("{0:s}{1:s}".format(logStr, 'No plot data provided.')) return if isinstance(attribute, list): pass else: # Set default legend_fmt if not provided if legend_fmt is None: legend_fmt = attribute + ' {:4.0f}' logger.debug("Fine 1") # Create Colormap cmap = mcolors.LinearSegmentedColormap.from_list('cmap', colors, N=256) norm_min = norm_min if norm_min is not None else gdf[attribute].min() norm_max = norm_max if norm_max is not None else gdf[attribute].max() norm = plt.Normalize(vmin=norm_min, vmax=norm_max) logger.debug("{0:s}norm_min: {1:10.2f} norm_max: {2:10.2f}".format(logStr, norm_min, norm_max)) # Filter and Sort Data if Query is Provided df = gdf.query(query) if query else gdf df = df.sort_values(by=[attribute], ascending=True) # Plotting Data with Lines sizes = norm(df[attribute].astype(float)) * line_width_factor # Scale sizes appropriately df.plot(ax=ax, linewidth=sizes, color=cmap(norm(df[attribute].astype(float))), path_effects=[path_effects.Stroke(capstyle="round")], label=attribute, #alpha=0.5, zorder=zorder) # Add label for legend logger.debug("{0:s}{1:s}".format(logStr, f'Plotted {attribute} data.')) plt.axis('off') # Create Legend Patches legend_values = legend_values if legend_values is not None else np.linspace(norm_min, norm_max, num=5) logger.debug("{0:s}legend_values: {1}".format(logStr, legend_values)) patches = [mpatches.Patch(color=cmap(norm(value)), label=legend_fmt.format(value)) for value in legend_values] return patches except Exception as e: logger.error("{0:s}{1:s} - {2}".format(logStr, 'Error.', str(e))) logger.debug("{0:s}{1:s}".format(logStr, 'End.'))
[docs]def pNcd_nodes(ax=None, gdf=None, attribute=None, colors=['darkgreen', 'magenta'], legend_fmt=None, legend_values=None, norm_min=None, norm_max=None, query=None, marker_style='o', marker_size_factor=1000.0, zorder=None): """ pNcd_nodes: Plots nodes on axis with customization options. :param ax: Matplotlib axis object. If None, a new axis is created. :type ax: matplotlib.axes.Axes, optional :param gdf: Geospatial DataFrame containing the data to plot. :type gdf: geopandas.GeoDataFrame :param attribute: Column name in gdf of the data that should be plotted. :type attribute: str :param colors: List of colors to use for the colormap. Default is ['darkgreen', 'magenta']. :type colors: list, optional :param legend_fmt: Legend text for attribute. Default is attribute + '{:.4f}'. :type legend_fmt: str, optional :param legend_values: Specific values to use for value steps in legend. Default is None. :type legend_values: list, optional :param norm_min: Minimum value for normalization. Default is None. :type norm_min: float, optional :param norm_max: Maximum value for normalization. Default is None. :type norm_max: float, optional :param query: Query string to filter the data. Default is None. :type query: str, optional :param marker_style: Style of the markers in the plot. Default is 'o'. :type marker_style: str, optional :param marker_size_factor: Factor to influence size of the markers in the plot. Default is 1000.0. :type marker_size_factor: float, optional :param zorder: Determines order of plotting when calling the function multilpe times. Default is None. :type zorder: float, optional :return: patches. :rtype: matplotlib.patches.Patch """ logStr = "{0:s}.{1:s}: ".format(__name__, sys._getframe().f_code.co_name) logger.debug("{0:s}{1:s}".format(logStr, 'Start.')) try: if ax is None: fig, ax = plt.subplots(figsize=(11.7, 8.3)) # A3 size logger.debug("{0:s}{1:s}".format(logStr, 'Created new axis.')) if gdf is None or gdf.empty: logger.debug("{0:s}{1:s}".format(logStr, 'No plot data provided.')) return # Set default legend_fmt if not provided if legend_fmt is None: legend_fmt = attribute + ' {:4.0f}' # Create Colormap cmap = mcolors.LinearSegmentedColormap.from_list('cmap', colors, N=256) norm_min = norm_min if norm_min is not None else gdf[attribute].min() norm_max = norm_max if norm_max is not None else gdf[attribute].max() norm = plt.Normalize(vmin=norm_min, vmax=norm_max) logger.debug("{0:s}norm_min: {1:10.2f} norm_max: {2:10.2f}".format(logStr, norm_min, norm_max)) # Filter and Sort Data if Query is Provided df = gdf.query(query) if query else gdf df = df.sort_values(by=[attribute], ascending=True) # Plotting Data with Markers sizes = norm(df[attribute].astype(float)) * marker_size_factor # Scale sizes appropriately df.plot(ax=ax, marker=marker_style, markersize=sizes, linestyle='None', # No lines, only markers color=cmap(norm(df[attribute].astype(float))), path_effects=[path_effects.Stroke(capstyle="round")], zorder=zorder) logger.debug("{0:s}{1:s}".format(logStr, f'Plotted {attribute} data.')) plt.axis('off') # Create Legend Patches legend_values = legend_values if legend_values is not None else np.linspace(norm_min, norm_max, num=5) logger.debug("{0:s}legend_values: {1}".format(logStr, legend_values)) patches = [mpatches.Patch(color=cmap(norm(value)), label=legend_fmt.format(value)) for value in legend_values] return patches except Exception as e: logger.error("{0:s}{1:s} - {2}".format(logStr, 'Error.', str(e))) logger.debug("{0:s}{1:s}".format(logStr, 'End.'))
# Quellspektren def mix_colors(vector, colors): """ Mixes colors based on the provided vector. :param vector: A vector of weights for the colors. :type vector: np.ndarray :param colors: An array of colors to be mixed. :type colors: np.ndarray :return: The mixed color as an integer array. :rtype: np.ndarray """ vector = np.array(vector, dtype=float) # Ensure the vector is of type float vector /= vector.sum() # Normalize the vector so that its elements sum to 1 colors_array = np.array(colors, dtype=float) # Ensure the colors are of type float mixed_color = np.dot(vector, colors_array) return mixed_color.astype(int) def convert_to_hex(color_array): """ Converts an RGB color array to a hexadecimal color string. :param color_array: An array with RGB values. :type color_array: np.ndarray :return: The hexadecimal color string. :rtype: str """ hex_color = "#{:02x}{:02x}{:02x}".format(int(color_array[0]), int(color_array[1]), int(color_array[2])) logger.debug(f"Converted color: {hex_color}") return hex_color
[docs]def plot_src_spectrum(ax=None, gdf=None, attribute=None, colors=None, line_width=2): """ Plots the source spectrum based on the provided GeoDataFrame and attributes. :param ax: The axis to plot on. If None, a new axis is created. :type ax: matplotlib.axes.Axes, optional :param gdf: The GeoDataFrame containing the data to plot. :type gdf: geopandas.GeoDataFrame :param attribute: The attribute column in the GeoDataFrame to use for color mixing. :type attribute: str :param colors: The colors to use for mixing. :type colors: list of np.ndarray :param line_width: The width of the lines in the plot. :type line_width: int, optional, default=2 """ logStr = "{0:s}.{1:s}: ".format(__name__, sys._getframe().f_code.co_name) logger.debug("{0:s}{1:s}".format(logStr, 'Start.')) try: if ax is None: fig, ax = plt.subplots(figsize=Rm.DINA3q) # Adjusted to A3 size logger.debug("{0:s}{1:s}".format(logStr, 'Created new axis.')) if gdf is None or gdf.empty: logger.debug("{0:s}{1:s}".format(logStr, 'No plot data provided.')) return gdf['mixed_color'] = gdf[attribute].apply(lambda x: mix_colors(x, colors)) gdf['mixed_color_hex'] = gdf['mixed_color'].apply(lambda x: convert_to_hex(np.array(x).clip(0, 255))) for idx, row in gdf.iterrows(): x, y = row['geometry'].xy color = row['mixed_color_hex'] ax.plot(x, y, color=color, linewidth=line_width) # Create a legend for the colors legend_handles = [] for i, color in enumerate(colors): color_hex = convert_to_hex(color.clip(0, 255)) legend_handles.append(plt.Line2D([0], [0], color=color_hex, lw=line_width, label=f"Source {i+1}")) ax.legend(handles=legend_handles, loc='best') plt.axis('off') except Exception as e: logger.error("{0:s}{1:s} - {2}".format(logStr, 'Error.', str(e)))