Skip to content

Commit

Permalink
added energy balance
Browse files Browse the repository at this point in the history
changed how scatter is plotted
  • Loading branch information
sebastian-swob committed Dec 16, 2024
1 parent fc2b2ae commit b92f146
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 64 deletions.
2 changes: 1 addition & 1 deletion pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ max-args=6
max-positional-arguments=6

# Maximum number of attributes for a class (see R0902).
max-attributes=7
max-attributes=11

# Maximum number of boolean expressions in an if statement (see R0916).
max-bool-expr=5
Expand Down
94 changes: 81 additions & 13 deletions pytrnsys_process/plotting/plot_wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def line_plot(
>>>
>>> # run the single scenario on a single simulation
>>> api.process_single_simulation(
>>> _pl.Path("data/results/complete-0-SnkScale0.6000-StoreScale8"),
>>> _pl.Path("path/to/single/simulation"),
>>> create_line_plot,
>>> )
Expand Down Expand Up @@ -87,7 +87,7 @@ def bar_chart(
>>>
>>> # run the single scenario on a single simulation
>>> api.process_single_simulation(
>>> _pl.Path("data/results/complete-0-SnkScale0.6000-StoreScale8"),
>>> _pl.Path("path/to/single/simulation"),
>>> create_bar_chart,
>>> )
Expand Down Expand Up @@ -133,7 +133,7 @@ def stacked_bar_chart(
>>>
>>> # run the single scenario on a single simulation
>>> api.process_single_simulation(
>>> _pl.Path("data/results/complete-0-SnkScale0.6000-StoreScale8"),
>>> _pl.Path("path/to/single/simulation"),
>>> create_stacked_bar_chart,
>>> )
Expand Down Expand Up @@ -179,7 +179,7 @@ def histogram(
>>>
>>> # run the single scenario on a single simulation
>>> api.process_single_simulation(
>>> _pl.Path("data/results/complete-0-SnkScale0.6000-StoreScale8"),
>>> _pl.Path("path/to/single/simulation"),
>>> create_histogram,
>>> )
Expand All @@ -195,7 +195,6 @@ def histogram(

def scatter_plot(
df: _pd.DataFrame,
columns: list[str],
x_column: str,
y_column: str,
use_legend: bool = True,
Expand All @@ -206,7 +205,6 @@ def scatter_plot(
Args:
df: DataFrame containing the data to plot
columns: List of column names to plot
x_column: Name of the column to use for x-axis values
y_column: Name of the column to use for y-axis values
use_legend: Whether to show the legend
Expand All @@ -221,7 +219,6 @@ def scatter_plot(
>>> def create_scatter_plot(simulation: api.Simulation):
>>> fig, ax = api.scatter_plot(
... simulation.hourly,
... columns=["var1", "var2", "var3"],
... x_column="var1",
... y_column="var2",
... )
Expand All @@ -233,21 +230,92 @@ def scatter_plot(
>>>
>>> # run the single scenario on a single simulation
>>> api.process_single_simulation(
>>> _pl.Path("data/results/complete-0-SnkScale0.6000-StoreScale8"),
>>> _pl.Path("path/to/single/simulation"),
>>> create_scatter_plot,
>>> )
For additional customization options, refer to:
- Matplotlib documentation: https://matplotlib.org/stable/api/
- Pandas plotting: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.plot.scatter.html
"""
plotter = pltrs.ScatterPlot()
fig, ax = _plt.subplots(figsize=size)
columns = [x_column, y_column]
df[columns].plot.scatter(
legend=use_legend,
ax=ax,
x=x_column,
y=y_column,
**kwargs,
)
ax = pltrs.configure(ax)

return fig, ax


def energy_balance(
df: _pd.DataFrame,
q_in_columns: list[str],
q_out_columns: list[str],
q_imb_column: _tp.Optional[str] = None,
use_legend: bool = True,
size: tuple[float, float] = const.PlotSizes.A4.value,
**kwargs: _tp.Any,
) -> tuple[_plt.Figure, _plt.Axes]:
"""Create a stacked bar chart showing energy balance with inputs, outputs and imbalance.
This function creates an energy balance visualization where:
- Input energies are shown as positive values
- Output energies are shown as negative values
- Energy imbalance is either provided or calculated as (sum of inputs + sum of outputs)
Args:
df: DataFrame containing the energy data
q_in_columns: List of column names representing energy inputs
q_out_columns: List of column names representing energy outputs
q_imb_column: Optional column name containing pre-calculated energy imbalance
use_legend: Whether to show the legend
size: Figure size tuple (width, height)
**kwargs: Additional plotting arguments passed to the stacked bar chart
Returns:
Tuple of (matplotlib Figure object, matplotlib Axes object)
Example:
>>> from pytrnsys_process import api
>>> def create_energy_balance(simulation: api.Simulation):
>>> fig, ax = api.energy_balance(
... simulation.monthly,
... q_in_columns=['solar_gain', 'auxiliary_power'],
... q_out_columns=['thermal_losses', 'consumption'],
... )
>>> ax.set_xlabel('Time')
>>> ax.set_ylabel('Energy [kWh]')
>>> ax.set_title('Monthly Energy Balance')
>>> ax.grid(True)
>>> # run the single scenario on a single simulation
>>> api.process_single_simulation(
>>> _pl.Path("path/to/single/simulation"),
>>> create_energy_balance,
>>> )
"""
df_modified = df.copy()

for col in q_out_columns:
df_modified[col] = -df_modified[col]

if q_imb_column is None:
q_imb_column = "Qimb"
df_modified[q_imb_column] = df_modified[
q_in_columns + q_out_columns
].sum(axis=1)

columns_to_plot = q_in_columns + q_out_columns + [q_imb_column]

plotter = pltrs.StackedBarChart()
return plotter.plot(
df,
columns,
df_modified,
columns_to_plot,
use_legend=use_legend,
size=size,
x=x_column,
y=y_column,
**kwargs,
)
69 changes: 26 additions & 43 deletions pytrnsys_process/plotting/plotters.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import pytrnsys_process.constants as const
import pytrnsys_process.headers as h

from pytrnsys_process import settings as sett

# TODO: provide A4 and half A4 plots to test sizes in latex # pylint: disable=fixme
# TODO: provide height as input for plot? # pylint: disable=fixme
Expand All @@ -18,23 +18,24 @@
# TODO: Add colormap support # pylint: disable=fixme


# TODO find a better place for this to live in # pylint : disable=fixme
plot_settings = sett.settings.plot


def configure(ax: _plt.Axes) -> _plt.Axes:
ax.set_xlabel(
plot_settings.x_label, fontsize=plot_settings.label_font_size
)
ax.set_ylabel(
plot_settings.y_label, fontsize=plot_settings.label_font_size
)
ax.set_title(plot_settings.title, fontsize=plot_settings.title_font_size)
_plt.tight_layout()
return ax


@dataclass
class ChartBase(h.HeaderValidationMixin):
X_LABEL = ""
Y_LABEL = ""
TITLE = ""
COLOR_MAP = "viridis"
DATE_FORMAT = "%b %Y"
LABEL_FONT_SIZE = 10
LEGEND_FONT_SIZE = 8
TITLE_FONT_SIZE = 12

def configure(self, ax: _plt.Axes) -> _plt.Axes:
ax.set_xlabel(self.X_LABEL, fontsize=self.LABEL_FONT_SIZE)
ax.set_ylabel(self.Y_LABEL, fontsize=self.LABEL_FONT_SIZE)
ax.set_title(self.TITLE, fontsize=self.TITLE_FONT_SIZE)
_plt.tight_layout()
return ax

def plot(
self,
Expand Down Expand Up @@ -101,16 +102,16 @@ def _do_plot(
fig, ax = _plt.subplots(figsize=size)
plot_kwargs = {
"stacked": True,
"colormap": self.COLOR_MAP,
"colormap": plot_settings.color_map,
"legend": use_legend,
"ax": ax,
**kwargs,
}
ax = df[columns].plot.bar(**plot_kwargs)
ax.set_xticklabels(
_pd.to_datetime(df.index).strftime(self.DATE_FORMAT)
_pd.to_datetime(df.index).strftime(plot_settings.date_format)
)
ax = self.configure(ax)
ax = configure(ax)

return fig, ax

Expand Down Expand Up @@ -147,10 +148,10 @@ def _do_plot(

ax.set_xticks(x + width * (len(columns) - 1) / 2)
ax.set_xticklabels(
_pd.to_datetime(df.index).strftime(self.DATE_FORMAT)
_pd.to_datetime(df.index).strftime(plot_settings.date_format)
)
ax.tick_params(axis="x", labelrotation=90)
self.configure(ax)
configure(ax)
return fig, ax


Expand All @@ -166,13 +167,13 @@ def _do_plot(
) -> tuple[_plt.Figure, _plt.Axes]:
fig, ax = _plt.subplots(figsize=size)
plot_kwargs = {
"colormap": self.COLOR_MAP,
"colormap": plot_settings.color_map,
"legend": use_legend,
"ax": ax,
**kwargs,
}
df[columns].plot.line(**plot_kwargs)
ax = self.configure(ax)
ax = configure(ax)
return fig, ax


Expand All @@ -190,30 +191,12 @@ def _do_plot(
) -> tuple[_plt.Figure, _plt.Axes]:
fig, ax = _plt.subplots(figsize=size)
plot_kwargs = {
"colormap": self.COLOR_MAP,
"colormap": plot_settings.color_map,
"legend": use_legend,
"ax": ax,
"bins": self.bins,
**kwargs,
}
df[columns].plot.hist(**plot_kwargs)
ax = self.configure(ax)
return fig, ax


class ScatterPlot(ChartBase):
def _do_plot(
self,
df: _pd.DataFrame,
columns: list[str],
use_legend: bool = True,
size: tuple[float, float] = const.PlotSizes.A4.value,
**kwargs: _tp.Any,
) -> tuple[_plt.Figure, _plt.Axes]:
fig, ax = _plt.subplots(figsize=size)
# TODO: cleanup the other Plotters to remove the stringy dictionary.
df[columns].plot.scatter(
colormap=self.COLOR_MAP, legend=use_legend, ax=ax, **kwargs
)
ax = self.configure(ax)
ax = configure(ax)
return fig, ax
9 changes: 9 additions & 0 deletions pytrnsys_process/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ class Plot:

inkscape_path: str = "C://Program Files//Inkscape//bin//inkscape.exe"

x_label: str = ""
y_label: str = ""
title: str = ""
date_format: str = "%b %Y"
color_map: str = "viridis"
label_font_size: int = 10
legend_font_size: int = 8
title_font_size: int = 12


@dataclass
class Reader:
Expand Down
10 changes: 5 additions & 5 deletions pytrnsys_process/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import matplotlib.pyplot as _plt

from pytrnsys_process import settings as _set
from pytrnsys_process import settings as sett
from pytrnsys_process.logger import logger


Expand All @@ -19,8 +19,8 @@ def get_sim_folders(path_to_results: _pl.Path) -> _abc.Sequence[_pl.Path]:

def get_files(
sim_folders: _abc.Sequence[_pl.Path],
results_folder_name: str = _set.settings.reader.folder_name_for_printer_files,
get_mfr_and_t: bool = _set.settings.reader.read_step_files,
results_folder_name: str = sett.settings.reader.folder_name_for_printer_files,
get_mfr_and_t: bool = sett.settings.reader.read_step_files,
) -> _abc.Sequence[_pl.Path]:
sim_files: list[_pl.Path] = []
for sim_folder in sim_folders:
Expand Down Expand Up @@ -74,7 +74,7 @@ def export_plots_in_configured_formats(
>>> # etc.
"""
plot_settings = _set.settings.plot
plot_settings = sett.settings.plot
plots_folder = path_to_directory / "plots"
plots_folder.mkdir(exist_ok=True)

Expand All @@ -95,7 +95,7 @@ def export_plots_in_configured_formats(

def convert_svg_to_emf(file_no_suffix: _pl.Path) -> None:
try:
inkscape_path = _set.settings.plot.inkscape_path
inkscape_path = sett.settings.plot.inkscape_path
if not _pl.Path(inkscape_path).exists():
raise OSError(f"Inkscape executable not found at: {inkscape_path}")
emf_filepath = file_no_suffix.with_suffix(".emf")
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit b92f146

Please sign in to comment.