Skip to content

Plotting

Matplotlib bar-plot helpers that consume a Result instance and visualise earth potential rise, branch currents and bus currents either for a specific frequency or as RMS across all frequencies.

plotting

Plotting Module.

This module provides functions for visualizing the results of electrical network calculations, including UEPR (Earth Potential Rise) for buses and branch currents. It utilizes Matplotlib to generate plots that can display both frequency-dependent and RMS (Root Mean Square) values for various electrical parameters. These visualizations aid in analyzing the performance and behavior of the electrical network under different fault conditions.

plot_branch_currents

plot_branch_currents(
    result: Result,
    frequencies: Optional[List[float]] = None,
    figsize: tuple = (12, 6),
    title: str = "Branch Currents",
    yscale: str = "linear",
    show=False,
)

Plot the branch currents for each branch.

This function generates a plot of branch currents in the network. It can plot either frequency-dependent current magnitudes or RMS current values based on the provided parameters.

Parameters:

Name Type Description Default
result Result

The Result object containing the calculation results.

required
frequencies Optional[List[float]]

A list of frequencies (in Hz) to plot. If None or empty, RMS current values are plotted. Defaults to None.

None
figsize tuple

The size of the figure in inches as a (width, height) tuple. Defaults to (12, 6).

(12, 6)
title str

The title of the plot. Defaults to "Branch Currents".

'Branch Currents'
yscale str

The scale for the y-axis. Can be "linear" or "log". Defaults to "linear".

'linear'
show bool

Whether to display the plot immediately. If False, the plot is returned for further manipulation. Defaults to False.

False

Returns:

Type Description

matplotlib.figure.Figure: The Matplotlib figure object containing the plot.

Raises:

Type Description
KeyError

If a specified frequency is not present in the i_s_freq of any branch.

Examples:

>>> import groundinsight as gi
>>> # Assuming 'result' is a Result object obtained from network calculations
>>> fig = gi.plot_branch_currents(result=result, frequencies=[50, 60], title="Branch Currents at 50Hz and 60Hz")
>>> fig.savefig("branch_currents_plot.png")
>>> # Plotting RMS branch currents
>>> fig = gi.plot_branch_currents(result=result, title="RMS Branch Currents")
>>> fig.show()
Source code in src/groundinsight/plotting.py
def plot_branch_currents(
    result: Result,
    frequencies: Optional[List[float]] = None,
    figsize: tuple = (12, 6),
    title: str = "Branch Currents",
    yscale: str = "linear",
    show=False,
):
    """
    Plot the branch currents for each branch.

    This function generates a plot of branch currents in the network. It can plot either
    frequency-dependent current magnitudes or RMS current values based on the provided parameters.

    Args:
        result (Result): The `Result` object containing the calculation results.
        frequencies (Optional[List[float]], optional):
            A list of frequencies (in Hz) to plot. If `None` or empty, RMS current values are plotted.
            Defaults to `None`.
        figsize (tuple, optional):
            The size of the figure in inches as a (width, height) tuple. Defaults to `(12, 6)`.
        title (str, optional):
            The title of the plot. Defaults to `"Branch Currents"`.
        yscale (str, optional):
            The scale for the y-axis. Can be `"linear"` or `"log"`. Defaults to `"linear"`.
        show (bool, optional):
            Whether to display the plot immediately. If `False`, the plot is returned for further manipulation.
            Defaults to `False`.

    Returns:
        matplotlib.figure.Figure: The Matplotlib figure object containing the plot.

    Raises:
        KeyError: If a specified frequency is not present in the `i_s_freq` of any branch.

    Examples:
        >>> import groundinsight as gi
        >>> # Assuming 'result' is a Result object obtained from network calculations
        >>> fig = gi.plot_branch_currents(result=result, frequencies=[50, 60], title="Branch Currents at 50Hz and 60Hz")
        >>> fig.savefig("branch_currents_plot.png")

        >>> # Plotting RMS branch currents
        >>> fig = gi.plot_branch_currents(result=result, title="RMS Branch Currents")
        >>> fig.show()
    """
    # Extract branch names
    branch_names = [branch.name for branch in result.branches]

    # Initialize data structure for plotting
    current_data = {}

    if frequencies:
        # Plot frequency-dependent branch currents
        for freq in frequencies:
            current_values = []
            for branch in result.branches:
                current_complex = branch.i_s_freq.get(freq)
                if current_complex:
                    # Calculate magnitude of the complex current
                    current_magnitude = abs(
                        complex(current_complex.real, current_complex.imag)
                    )
                else:
                    current_magnitude = 0.0  # Handle missing data
                current_values.append(current_magnitude)
            current_data[freq] = current_values

        # Plotting
        fig = plt.figure(figsize=figsize)
        bar_width = 0.8 / len(
            frequencies
        )  # Adjust bar width based on the number of frequencies
        indices = range(len(branch_names))
        for i, (freq, current_values) in enumerate(current_data.items()):
            positions = [x + i * bar_width for x in indices]
            plt.bar(positions, current_values, width=bar_width, label=f"{freq} Hz")
        plt.yscale(yscale)
        plt.xlabel("Branch Name")
        plt.ylabel("Current (A)")
        plt.title(title)
        plt.xticks(
            [x + bar_width * (len(frequencies) - 1) / 2 for x in indices],
            branch_names,
            rotation=45,
            ha="right",
        )
        plt.legend(title="Frequency")
        plt.grid(True, axis="y")
        plt.tight_layout()
        if show:
            plt.show()

    else:
        # Plot RMS values of branch currents
        current_rms_values = []
        for branch in result.branches:
            current_rms = branch.i_s  # RMS value of branch current
            if current_rms is not None:
                current_rms_values.append(current_rms)
            else:
                current_rms_values.append(0.0)  # Handle missing data

        # Plotting
        fig = plt.figure(figsize=figsize)
        plt.bar(branch_names, current_rms_values, label="RMS")
        plt.yscale(yscale)
        plt.xlabel("Branch Name")
        plt.ylabel("Current RMS (A)")
        plt.title(title)
        plt.xticks(rotation=45, ha="right")
        plt.legend()
        plt.grid(True, axis="y")
        plt.tight_layout()
        if show:
            plt.show()

    return fig

plot_bus_currents

plot_bus_currents(
    result: Result,
    frequencies: Optional[List[float]] = None,
    figsize: tuple = (12, 6),
    title: str = "Bus Currents",
    yscale: str = "linear",
    show=False,
)

Plot the bus currents for each bus.

This function generates a plot of bus currents in the network. It can plot either frequency-dependent current magnitudes or RMS current values based on the provided parameters.

Parameters:

Name Type Description Default
result Result

The Result object containing the calculation results.

required
frequencies Optional[List[float]]

A list of frequencies (in Hz) to plot. If None or empty, RMS current values are plotted. Defaults to None.

None
figsize tuple

The size of the figure in inches as a (width, height) tuple. Defaults to (12, 6).

(12, 6)
title str

The title of the plot. Defaults to "Bus Currents".

'Bus Currents'
yscale str

The scale for the y-axis. Can be "linear" or "log". Defaults to "linear".

'linear'
show bool

Whether to display the plot immediately. If False, the plot is returned for further manipulation. Defaults to False.

False

Returns:

Type Description

matplotlib.figure.Figure: The Matplotlib figure object containing the plot.

Raises:

Type Description
KeyError

If a specified frequency is not present in the ia_freq of any bus.

Examples:

>>> import groundinsight as gi
>>> # Assuming 'result' is a Result object obtained from network calculations
>>> fig = gi.plot_bus_currents(result=result, frequencies=[50, 60], title="Bus Currents at 50Hz and 60Hz")
>>> fig.savefig("bus_currents_plot.png")
>>> # Plotting RMS bus currents
>>> fig = gi.plot_bus_currents(result=result, title="RMS Bus Currents")
>>> fig.show()
Source code in src/groundinsight/plotting.py
def plot_bus_currents(
    result: Result,
    frequencies: Optional[List[float]] = None,
    figsize: tuple = (12, 6),
    title: str = "Bus Currents",
    yscale: str = "linear",
    show=False,
):
    """
    Plot the bus currents for each bus.

    This function generates a plot of bus currents in the network. It can plot either
    frequency-dependent current magnitudes or RMS current values based on the provided parameters.

    Args:
        result (Result): The `Result` object containing the calculation results.
        frequencies (Optional[List[float]], optional):
            A list of frequencies (in Hz) to plot. If `None` or empty, RMS current values are plotted.
            Defaults to `None`.
        figsize (tuple, optional):
            The size of the figure in inches as a (width, height) tuple. Defaults to `(12, 6)`.
        title (str, optional):
            The title of the plot. Defaults to `"Bus Currents"`.
        yscale (str, optional):
            The scale for the y-axis. Can be `"linear"` or `"log"`. Defaults to `"linear"`.
        show (bool, optional):
            Whether to display the plot immediately. If `False`, the plot is returned for further manipulation.
            Defaults to `False`.

    Returns:
        matplotlib.figure.Figure: The Matplotlib figure object containing the plot.

    Raises:
        KeyError: If a specified frequency is not present in the `ia_freq` of any bus.

    Examples:
        >>> import groundinsight as gi
        >>> # Assuming 'result' is a Result object obtained from network calculations
        >>> fig = gi.plot_bus_currents(result=result, frequencies=[50, 60], title="Bus Currents at 50Hz and 60Hz")
        >>> fig.savefig("bus_currents_plot.png")

        >>> # Plotting RMS bus currents
        >>> fig = gi.plot_bus_currents(result=result, title="RMS Bus Currents")
        >>> fig.show()
    """
    # Extract bus names
    bus_names = [bus.name for bus in result.buses]

    # Initialize data structure for plotting
    current_data = {}

    if frequencies:
        # Plot frequency-dependent bus currents
        for freq in frequencies:
            current_values = []
            for bus in result.buses:
                current_complex = bus.ia_freq.get(freq)
                if current_complex:
                    # Calculate magnitude of the complex current
                    current_magnitude = abs(
                        complex(current_complex.real, current_complex.imag)
                    )
                else:
                    current_magnitude = 0.0  # Handle missing data
                current_values.append(current_magnitude)
            current_data[freq] = current_values

        # Plotting
        fig = plt.figure(figsize=figsize)
        bar_width = 0.8 / len(
            frequencies
        )  # Adjust bar width based on the number of frequencies
        indices = range(len(bus_names))
        for i, (freq, current_values) in enumerate(current_data.items()):
            positions = [x + i * bar_width for x in indices]
            plt.bar(positions, current_values, width=bar_width, label=f"{freq} Hz")
        plt.yscale(yscale)
        plt.xlabel("Bus Name")
        plt.ylabel("Current (A)")
        plt.title(title)
        plt.xticks(
            [x + bar_width * (len(frequencies) - 1) / 2 for x in indices],
            bus_names,
            rotation=45,
            ha="right",
        )
        plt.legend(title="Frequency")
        plt.grid(True, axis="y")
        plt.tight_layout()
        if show:
            plt.show()

    else:
        # Plot RMS values of bus currents
        current_rms_values = []
        for bus in result.buses:
            current_rms = bus.ia  # RMS value of bus current
            if current_rms is not None:
                current_rms_values.append(current_rms)
            else:
                current_rms_values.append(0.0)  # Handle missing data

        # Plotting
        fig = plt.figure(figsize=figsize)
        plt.bar(bus_names, current_rms_values, label="RMS")
        plt.yscale(yscale)
        plt.xlabel("Bus Name")
        plt.ylabel("Current RMS (A)")
        plt.title(title)
        plt.xticks(rotation=45, ha="right")
        plt.legend()
        plt.grid(True, axis="y")
        plt.tight_layout()
        if show:
            plt.show()
    return fig

plot_bus_voltages

plot_bus_voltages(
    result: Result,
    frequencies: Optional[List[float]] = None,
    figsize: tuple = (12, 6),
    title: str = "UEPR vs Bus Name",
    yscale: str = "linear",
    show=False,
)

Plot the UEPR (Earth Potential Rise) for each bus.

This function generates a bar plot of UEPR values for each bus in the network. It can plot either frequency-dependent UEPR magnitudes or RMS UEPR values based on the provided parameters. Additionally, the y-axis scale can be linear or logarithmic.

Parameters:

Name Type Description Default
result Result

The Result object containing the calculation results.

required
frequencies Optional[List[float]]

A list of frequencies (in Hz) to plot. If None or empty, RMS UEPR values are plotted. Defaults to None.

None
figsize tuple

The size of the figure in inches as a (width, height) tuple. Defaults to (12, 6).

(12, 6)
title str

The title of the plot. Defaults to "UEPR vs Bus Name".

'UEPR vs Bus Name'
yscale str

The scale for the y-axis. Can be "linear" or "log". Defaults to "linear".

'linear'
show bool

Whether to display the plot immediately. If False, the plot is returned for further manipulation. Defaults to False.

False

Returns:

Type Description

matplotlib.figure.Figure: The Matplotlib figure object containing the plot.

Raises:

Type Description
KeyError

If a specified frequency is not present in the uepr_freq of any bus.

Examples:

>>> import groundinsight as gi
>>> fig = gi.plot_bus_voltages(result=result, frequencies=[50, 60], yscale="log")
>>> fig.savefig("uepr_plot.png")
>>> fig = gi.plot_bus_voltages(result=result, yscale="linear", title="RMS UEPR across Buses")
>>> fig.show()
Source code in src/groundinsight/plotting.py
def plot_bus_voltages(
    result: Result,
    frequencies: Optional[List[float]] = None,
    figsize: tuple = (12, 6),
    title: str = "UEPR vs Bus Name",
    yscale: str = "linear",
    show=False,
):
    """
    Plot the UEPR (Earth Potential Rise) for each bus.

    This function generates a bar plot of UEPR values for each bus in the network. It can plot
    either frequency-dependent UEPR magnitudes or RMS UEPR values based on the provided parameters.
    Additionally, the y-axis scale can be linear or logarithmic.

    Args:
        result (Result): The `Result` object containing the calculation results.
        frequencies (Optional[List[float]], optional):
            A list of frequencies (in Hz) to plot. If `None` or empty, RMS UEPR values are plotted.
            Defaults to `None`.
        figsize (tuple, optional):
            The size of the figure in inches as a (width, height) tuple. Defaults to `(12, 6)`.
        title (str, optional):
            The title of the plot. Defaults to `"UEPR vs Bus Name"`.
        yscale (str, optional):
            The scale for the y-axis. Can be `"linear"` or `"log"`. Defaults to `"linear"`.
        show (bool, optional):
            Whether to display the plot immediately. If `False`, the plot is returned for further manipulation.
            Defaults to `False`.

    Returns:
        matplotlib.figure.Figure: The Matplotlib figure object containing the plot.

    Raises:
        KeyError: If a specified frequency is not present in the `uepr_freq` of any bus.

    Examples:
        >>> import groundinsight as gi
        >>> fig = gi.plot_bus_voltages(result=result, frequencies=[50, 60], yscale="log")
        >>> fig.savefig("uepr_plot.png")

        >>> fig = gi.plot_bus_voltages(result=result, yscale="linear", title="RMS UEPR across Buses")
        >>> fig.show()
    """
    # Extract bus names
    bus_names = [bus.name for bus in result.buses]

    # Initialize data structure for plotting
    uepr_data = {}

    if frequencies:
        # Plot frequency-dependent UEPR values
        for freq in frequencies:
            uepr_values = []
            for bus in result.buses:
                uepr_complex = bus.uepr_freq.get(freq)
                if uepr_complex:
                    # Calculate magnitude of the complex UEPR value
                    uepr_magnitude = abs(complex(uepr_complex.real, uepr_complex.imag))
                else:
                    uepr_magnitude = 0.0  # Handle missing data
                uepr_values.append(uepr_magnitude)
            uepr_data[freq] = uepr_values

        # Plotting
        fig = plt.figure(figsize=figsize)
        bar_width = 0.8 / len(frequencies)
        indices = range(len(bus_names))
        for i, (freq, uepr_values) in enumerate(uepr_data.items()):
            positions = [x + i * bar_width for x in indices]
            plt.bar(positions, uepr_values, width=bar_width, label=f"{freq} Hz")

        plt.xticks(
            [x + bar_width * (len(frequencies) - 1) / 2 for x in indices],
            bus_names,
            rotation=45,
            ha="right",
        )
    else:
        # Plot RMS values of UEPR
        uepr_rms_values = [
            bus.uepr if bus.uepr is not None else 0.0 for bus in result.buses
        ]
        fig = plt.figure(figsize=figsize)
        plt.bar(bus_names, uepr_rms_values, label="RMS")

    # Configure plot
    plt.yscale(yscale)
    plt.xlabel("Bus Name")
    plt.ylabel("UEPR (V)")
    plt.title(title)
    plt.xticks(rotation=45, ha="right")
    plt.legend(title="Frequency")
    plt.grid(True, axis="y")
    plt.tight_layout()

    if show:
        plt.show()

    return fig