Source code for geos_posp.visu.pythonViewUtils.Figure2DGenerator
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies.
# SPDX-FileContributor: Alexandre Benedicto
from typing import Any
import pandas as pd # type: ignore[import-untyped]
from matplotlib import axes, figure, lines # type: ignore[import-untyped]
from matplotlib.font_manager import ( # type: ignore[import-untyped]
FontProperties, # type: ignore[import-untyped]
)
from typing_extensions import Self
import geos_posp.visu.pythonViewUtils.functionsFigure2DGenerator as fcts
from geos.utils.Logger import Logger, getLogger
[docs]
class Figure2DGenerator:
def __init__(
self: Self, dataframe: pd.DataFrame, userChoices: dict[str, list[str]]
) -> None:
"""Utility to create cross plots using Python View.
We want to plot f(X) = Y where in this class,
"X" will be called "variable", "Y" will be called "curves".
Args:
dataframe (pd.DataFrame): data to plot
userChoices (dict[str, list[str]]): user choices.
"""
self.m_dataframe: pd.DataFrame = dataframe
self.m_userChoices: dict[str, Any] = userChoices
self.m_fig: figure.Figure
self.m_axes: list[axes._axes.Axes] = []
self.m_lines: list[lines.Line2D] = []
self.m_labels: list[str] = []
self.m_logger: Logger = getLogger("Python View Configurator")
try:
# apply minus 1 multiplication on certain columns
self.initMinus1Multiplication()
# defines m_fig, m_axes, m_lines and m_lables
self.plotInitialFigure()
# then to edit and customize the figure
self.enhanceFigure()
self.m_logger.info("Data were successfully plotted.")
except Exception as e:
mess: str = "Plot creation failed due to:"
self.m_logger.critical(mess)
self.m_logger.critical(e, exc_info=True)
[docs]
def initMinus1Multiplication(self: Self) -> None:
"""Multiply by -1 certain columns of the input dataframe."""
df: pd.DataFrame = self.m_dataframe.copy(deep=True)
minus1CurveNames: list[str] = self.m_userChoices["curveConvention"]
for name in minus1CurveNames:
df[name] = df[name] * (-1)
self.m_dataframe = df
[docs]
def enhanceFigure(self: Self) -> None:
"""Apply all the enhancement features to the initial figure."""
self.changeTitle()
self.changeMinorticks()
self.changeAxisScale()
self.changeAxisLimits()
[docs]
def plotInitialFigure(self: Self) -> None:
"""Generates a figure and axes objects from matplotlib.
The figure plots all the curves along the X or Y axis, with legend and
label for X and Y.
"""
if self.m_userChoices["plotRegions"]:
if not self.m_userChoices["reverseXY"]:
(fig, ax_all, lines, labels) = fcts.multipleSubplots(
self.m_dataframe, self.m_userChoices
)
else:
(fig, ax_all, lines, labels) = fcts.multipleSubplotsInverted(
self.m_dataframe, self.m_userChoices
)
else:
if not self.m_userChoices["reverseXY"]:
(fig, ax_all, lines, labels) = fcts.oneSubplot(
self.m_dataframe, self.m_userChoices
)
else:
(fig, ax_all, lines, labels) = fcts.oneSubplotInverted(
self.m_dataframe, self.m_userChoices
)
self.m_fig = fig
self.m_axes = ax_all
self.m_lines = lines
self.m_labels = labels
[docs]
def changeTitle(self: Self) -> None:
"""Update title of the first axis of the figure based on user choices."""
if self.m_userChoices["displayTitle"]:
title: str = self.m_userChoices["title"]
fontTitle: FontProperties = fcts.buildFontTitle(self.m_userChoices)
self.m_fig.suptitle(title, fontproperties=fontTitle)
[docs]
def changeMinorticks(self: Self) -> None:
"""Set the minorticks on or off for every axes."""
choice: bool = self.m_userChoices["minorticks"]
if choice:
for ax in self.m_axes:
ax.minorticks_on()
else:
for ax in self.m_axes:
ax.minorticks_off()
[docs]
def changeAxisScale(self: Self) -> None:
"""Set the minorticks on or off for every axes."""
for ax in self.m_axes:
if self.m_userChoices["logScaleX"]:
ax.set_xscale("log")
if self.m_userChoices["logScaleY"]:
ax.set_yscale("log")
[docs]
def changeAxisLimits(self: Self) -> None:
"""Update axis limits."""
if self.m_userChoices["customAxisLim"]:
for ax in self.m_axes:
xmin, xmax = ax.get_xlim()
if self.m_userChoices["limMinX"] is not None:
xmin = self.m_userChoices["limMinX"]
if self.m_userChoices["limMaxX"] is not None:
xmax = self.m_userChoices["limMaxX"]
ax.set_xlim(xmin, xmax)
ymin, ymax = ax.get_ylim()
if self.m_userChoices["limMinY"] is not None:
ymin = self.m_userChoices["limMinY"]
if self.m_userChoices["limMaxY"] is not None:
ymax = self.m_userChoices["limMaxY"]
ax.set_ylim(ymin, ymax)
[docs]
def getFigure(self: Self) -> figure.Figure:
"""Acces the m_fig attribute.
Returns:
figure.Figure: Figure containing all the plots.
"""
return self.m_fig