Skip to content

Commit

Permalink
added curve plot
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastian-swob committed Nov 12, 2024
1 parent 929ea52 commit b5b1c3d
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 63 deletions.
94 changes: 46 additions & 48 deletions pytrnsys_process/plotters.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,42 @@
import pandas as _pd


# 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
# TODO: deal with legends (curve names, fonts, colors, linestyles) # pylint: disable=fixme
# TODO: clean up old stuff by refactoring # pylint: disable=fixme
# TODO: make issue for docstrings of plotting # pylint: disable=fixme


class ChartBase:
X_LABEL = ""
Y_LABEL = "Energy Flows"
TITLE = ""
COLOR_MAP = "viridis"
SIZE_A4 = (7.8, 3.9)
SIZE_A4_HALF = (3.8, 3.9)
DATE_FORMAT = "%m-%y"
LABEL_FONT_SIZE = 10
LEGEND_FONT_SIZE = 8
TITLE_FONT_SIZE = 12

def __init__(self, df, x_label=X_LABEL, y_label=Y_LABEL, title=TITLE, size=SIZE_A4):

def __init__(
self, df, x_label=X_LABEL, y_label=Y_LABEL, title=TITLE, size=SIZE_A4
):
self.df = df
self.x_label = x_label
self.y_label = y_label
self.title = title

self.fig, self.ax = _plt.subplots(figsize=size)

def configure(self):
self.ax.set_xlabel(self.x_label)
self.ax.set_ylabel(self.y_label)
self.ax.set_title(self.title)
self.ax.set_xlabel(self.x_label, fontsize=self.LABEL_FONT_SIZE)
self.ax.set_ylabel(self.y_label, fontsize=self.LABEL_FONT_SIZE)
self.ax.set_title(self.title, fontsize=self.TITLE_FONT_SIZE)
#TODO This line does not seem to work as excpected, figure out why # pylint: disable=fixme
# self.ax.xaxis.set_major_formatter(_mpd.DateFormatter(self.DATE_FORMAT))
_plt.tight_layout()

@abstractmethod
Expand All @@ -32,65 +49,46 @@ def plot(self, *args, **kwargs):

# makes no sense
# def _plot(self, df, columns: list[str]):
# # TODO: check if this makes sense.
# # TODO: check if this makes sense. # pylint: disable=fixme
# self.plot(df, columns)
# self.configure()


class MonthlyBarChart(ChartBase):

def plot(
self, columns: list[str]
) -> Tuple[_plt.Figure | None, _plt.Axes]:
PLOT_KIND = "bar"

def plot(self, columns: list[str]) -> Tuple[_plt.Figure | None, _plt.Axes]:
self.df[columns].plot(
kind="bar", stacked=True, ax=self.ax, colormap="viridis"
kind=self.PLOT_KIND,
stacked=True,
ax=self.ax,
colormap=self.COLOR_MAP,
)

self.configure()
return self.fig, self.ax

# class HourlyCurvePlot(ChartBase)
#
# def plot(self,):

class Plotter:

@staticmethod
def create_bar_chart_for_hourly(df: _pd.DataFrame, columns: list[str]):
monthly_data = df.resample("M").sum()
monthly_data[columns].plot(
kind="bar", stacked=True, figsize=(10, 6), colormap="viridis"
)
_plt.xlabel("Month")
_plt.ylabel("Energy Values")
_plt.title("Monthly Energy Consumption by Type")
_plt.xticks(rotation=45)
_plt.legend(title="Energy Types")
_plt.tight_layout()
_plt.show()

@staticmethod
def create_bar_chart_for_monthly(
df: _pd.DataFrame,
columns: list[str],
) -> Tuple[_plt.Figure, _plt.Axes]:
ax = df[columns].plot(
kind="bar", stacked=True, figsize=(10, 6), colormap="tab20"
)
_plt.xlabel("Month")
_plt.ylabel("Energy Values")
_plt.title("Monthly Energy Consumption by Type")
_plt.xticks(rotation=45)
_plt.legend(title="Energy Types")
_plt.tight_layout()
_plt.show()
return ax.get_figure(), ax

#TODO Idea for what an energy balance plot method could look like # pylint: disable=fixme
@staticmethod
def create_energy_balance_monthly(
df: _pd.DataFrame,
q_in_columns: list[str],
q_out_columns: list[str],
imbalance_column: str,
) -> (_plt.Figure, _plt.Axes):
) -> Tuple[_plt.Figure, _plt.Axes]:
raise NotImplementedError


class HourlyCurvePlot(ChartBase):

PLOT_KIND = "line"

def plot(self, columns: list[str], use_legend: bool = True) -> Tuple[_plt.Figure | None, _plt.Axes]:
self.df[columns].plot(
kind=self.PLOT_KIND,
colormap=self.COLOR_MAP,
legend=use_legend,
ax=self.ax,
)
self.configure()
return self.fig, self.ax
2 changes: 1 addition & 1 deletion pytrnsys_process/readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def read_hourly(
header=Reader.HEADER,
delimiter=Reader.DELIMITER,
)
hours = _dt.timedelta(hours=1) * df["TIME"]
hours = _dt.timedelta(hours=1) * df["TIME"] # type: ignore
start_of_year = _dt.datetime(day=1, month=1, year=starting_year)
actual_ends_of_month = start_of_year + hours
df = df.drop(columns=["Period", "TIME"])
Expand Down
12 changes: 7 additions & 5 deletions tests/pytrnsys_process/test_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ class TestHeaders:

PATH_TO_RESULTS = _pl.Path(__file__).parent / "data/results"

PATH_TO_BENCHMARK_RESULTS = _pl.Path("C:/Development/data/results")


def test_init_headers(self):
headers = Headers(self.PATH_TO_RESULTS)

Expand All @@ -22,14 +19,19 @@ def test_init_headers(self):
assert headers.header_index.get("QSnk417PauxEvap_kW") == [
("sim-2", "ENERGY_BALANCE_MO_HP_417.Prt")
]
class TestBenchmarkHeaders:
"""Initial test have shown multi threading is slower than single thread for this problem.
Rerunning these tests requires a more comprehensive data set"""

PATH_TO_RESULTS = _pl.Path(__file__).parent / "data/results"

def test_init_headers_benchmark(self, benchmark):
def init_headers():
Headers(self.PATH_TO_BENCHMARK_RESULTS).init_headers()
Headers(self.PATH_TO_RESULTS).init_headers()
benchmark(init_headers)

def test_init_headers_benchmark_multi_thread(self, benchmark):
def init_headers():
Headers(self.PATH_TO_BENCHMARK_RESULTS).init_headers_multi_thread()
Headers(self.PATH_TO_RESULTS).init_headers_multi_thread()
benchmark(init_headers)

41 changes: 32 additions & 9 deletions tests/pytrnsys_process/test_plotters.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
import os as _os
import pathlib as _pl
import tempfile as _tf

import matplotlib.testing.compare as _mpltc
import pytest

import tests.pytrnsys_process.constants as const
from pytrnsys_process.plotters import MonthlyBarChart
from pytrnsys_process.plotters import MonthlyBarChart, HourlyCurvePlot
from pytrnsys_process.readers import Reader


class TestPlotter:

HOURLY_RESULTS = _pl.Path(__file__).parent / "data/hourly/Src_Hr.Prt"
MONTHLY_RESULTS = (
_pl.Path(__file__).parent
/ "data/results/sim-1/temp/ENERGY_BALANCE_MO_60_TESS.Prt"
)
# HOURLY_RESULTS = _pl.Path(__file__).parent / "data/hourly/Src_Hr.Prt"

# def test_create_bar_chart_for_hourly(self):
# Plotter.create_bar_chart_for_hourly(
# Reader.read_hourly(self.HOURLY_RESULTS),
# columns=["QSrc1TIn", "QSrc1TOut", "QSrc1dT"],
# )

# TODO figure out why not passing # pylint: disable=fixme
@pytest.mark.skip(reason="broken")
def testMplInstallation(self):
"""Checks whether Inkscape is installed correctly."""
assert "pdf" in _mpltc.comparable_formats()
Expand All @@ -33,9 +31,11 @@ def test_create_stacked_bar_chart_for_monthly(self):
const.DATA_FOLDER / "plots/stacked-bar-chart/expected.png"
)
actual_file = const.DATA_FOLDER / "plots/stacked-bar-chart/actual.png"
df = Reader.read_monthly(
self.MONTHLY_RESULTS, starting_month=11, periods=14
result_data = (
const.DATA_FOLDER
/ "results/sim-1/temp/ENERGY_BALANCE_MO_60_TESS.Prt"
)
df = Reader.read_monthly(result_data, starting_month=11, periods=14)
columns = [
"QSnk60PauxCondSwitch_kW",
"QSnk60dQ",
Expand All @@ -56,6 +56,29 @@ def test_create_stacked_bar_chart_for_monthly(self):
is None
)

def test_create_curve_plot_for_hourly(self):
result_data = const.DATA_FOLDER / "hourly/Src_hr.Prt"
expected_fig = (
const.DATA_FOLDER / "plots/curve-plot/expected.png"
)
actual_fig = (const.DATA_FOLDER / "plots/curve-plot/actual.png")
df = Reader.read_hourly(result_data)
columns = ["QSrc1TIn", "QSrc1TOut"]


curve_plot = HourlyCurvePlot(df)
fig, ax = curve_plot.plot(columns)
fig.savefig(actual_fig)


assert (
_mpltc.compare_images(
str(actual_fig), str(expected_fig), tol=0.001
)
is None
)


# def test_create_energy_balance_monthly(self):
# manual = False
#
Expand Down

0 comments on commit b5b1c3d

Please sign in to comment.