• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SPF-OST / pytrnsys_process / 12007828987

22 Nov 2024 09:39AM UTC coverage: 94.037% (+1.1%) from 92.933%
12007828987

push

github

web-flow
Merge pull request #14 from SPF-OST/13-create-initial-pipeline-for-processing-one-simulation

added sim processing:

183 of 189 new or added lines in 8 files covered. (96.83%)

1 existing line in 1 file now uncovered.

410 of 436 relevant lines covered (94.04%)

1.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.89
/pytrnsys_process/plotters.py
1
import typing as _tp
2✔
2
from abc import abstractmethod
2✔
3
from dataclasses import dataclass
2✔
4

5
import matplotlib.pyplot as _plt
2✔
6
import numpy as _np
2✔
7
import pandas as _pd
2✔
8

9
import pytrnsys_process.headers as h
2✔
10

11

12
# TODO: provide A4 and half A4 plots to test sizes in latex # pylint: disable=fixme
13
# TODO: provide height as input for plot?  # pylint: disable=fixme
14
# TODO: deal with legends (curve names, fonts, colors, linestyles) # pylint: disable=fixme
15
# TODO: clean up old stuff by refactoring # pylint: disable=fixme
16
# TODO: make issue for docstrings of plotting # pylint: disable=fixme
17

18

19
@dataclass
2✔
20
class ChartBase(h.HeaderValidationMixin):
2✔
21
    X_LABEL = ""
2✔
22
    Y_LABEL = ""
2✔
23
    TITLE = ""
2✔
24
    COLOR_MAP = "viridis"
2✔
25
    SIZE_A4 = (7.8, 3.9)
2✔
26
    SIZE_A4_HALF = (3.8, 3.9)
2✔
27
    DATE_FORMAT = "%b %Y"
2✔
28
    LABEL_FONT_SIZE = 10
2✔
29
    LEGEND_FONT_SIZE = 8
2✔
30
    TITLE_FONT_SIZE = 12
2✔
31

32
    def configure(self, ax: _plt.Axes) -> _plt.Axes:
2✔
33
        ax.set_xlabel(self.X_LABEL, fontsize=self.LABEL_FONT_SIZE)
2✔
34
        ax.set_ylabel(self.Y_LABEL, fontsize=self.LABEL_FONT_SIZE)
2✔
35
        ax.set_title(self.TITLE, fontsize=self.TITLE_FONT_SIZE)
2✔
36
        _plt.tight_layout()
2✔
37
        return ax
2✔
38

39
    def plot(
2✔
40
            self,
41
            df: _pd.DataFrame,
42
            columns: list[str],
43
            **kwargs,
44
    ) -> _plt.Figure:
NEW
45
        return self._do_plot(df, columns, **kwargs)
×
46

47
    # TODO: Test validation # pylint: disable=fixme
48
    def plot_with_column_validation(
2✔
49
            self,
50
            df: _pd.DataFrame,
51
            columns: list[str],
52
            headers: h.Headers,
53
            **kwargs,
54
    ) -> _plt.Figure:
55
        """Base plot method with header validation.
56

57
        Args:
58
            df: DataFrame containing the data to plot
59
            columns: List of column names to plot
60
            headers: Headers instance for validation
61
            **kwargs: Additional plotting arguments
62

63
        Raises:
64
            ValueError: If any columns are missing from the headers index
65
        """
66
        # TODO: Might live somewhere else in the future # pylint: disable=fixme
67
        is_valid, missing = self.validate_headers(headers, columns)
2✔
68
        if not is_valid:
2✔
69
            missing_details = []
×
70
            for col in missing:
×
71
                missing_details.append(f"'{col}' not found in any files")
×
72
            raise ValueError(
×
73
                "The following columns are not available in the headers index:\n"
74
                + "\n".join(missing_details)
75
            )
76

77
        return self._do_plot(df, columns, **kwargs)
2✔
78

79
    @abstractmethod
2✔
80
    def _do_plot(
2✔
81
            self,
82
            df: _pd.DataFrame,
83
            columns: list[str],
84
            use_legend: bool = True,
85
            size: tuple[float, float] = SIZE_A4,
86
            **kwargs: _tp.Any,
87
    ) -> _plt.Figure:
88
        """Implement actual plotting logic in subclasses"""
89

90

91
class StackedBarChart(ChartBase):
2✔
92

93
    # def plot(self, columns: list[str]) -> Tuple[_plt.Figure | None, _plt.Axes]:
94
    #     # TODO: deal with datetime formatting without pandas defaults  # pylint: disable=fixme
95
    #     df_for_plotting = self.df
96
    #     df_for_plotting.index = [
97
    #         timestamp.strftime(self.DATE_FORMAT)
98
    #         for timestamp in df_for_plotting.index
99
    #     ]
100
    #     self.df[columns].plot(
101
    #         kind=self.PLOT_KIND,
102
    #         stacked=True,
103
    #         ax=self.ax,
104
    #         colormap=self.COLOR_MAP,
105
    #     )
106
    #     self.configure()
107
    #     return self.fig, self.ax
108

109
    # TODO: Add colormap support # pylint: disable=fixme
110
    def _do_plot(
2✔
111
            self,
112
            df: _pd.DataFrame,
113
            columns: list[str],
114
            use_legend: bool = True,
115
            size: tuple[float, float] = ChartBase.SIZE_A4,
116
            **kwargs: _tp.Any,
117
    ) -> _plt.Figure:
118
        """The matplot date formatter does not work when using df.plot func.
119
        This is an example to plot a stacked bar chart without df.plot"""
120
        fig, ax = _plt.subplots(figsize=size)
2✔
121
        x = df.index
2✔
122
        bottom = _np.zeros(len(df.index))
2✔
123
        for col in columns:
2✔
124
            ax.bar(x, df[col], label=col, bottom=bottom, width=0.35)
2✔
125
            bottom += df[col]
2✔
126
        if use_legend:
2✔
127
            ax.legend()
2✔
128
        # ax.set_xticklabels(
129
        #     _pd.to_datetime(df.index).strftime(self.DATE_FORMAT)
130
        # )
131
        self.configure(ax)
2✔
132
        return fig
2✔
133

134
    # TODO Idea for what an energy balance plot method could look like # pylint: disable=fixme
135
    @staticmethod
2✔
136
    def create_energy_balance_monthly(
2✔
137
        df: _pd.DataFrame,
138
        q_in_columns: list[str],
139
        q_out_columns: list[str],
140
        imbalance_column: str,
141
    ) -> _tp.Tuple[_plt.Figure, _plt.Axes]:
142
        raise NotImplementedError
×
143

144

145
class BarChart(ChartBase):
2✔
146

147
    def _do_plot(
2✔
148
            self,
149
            df: _pd.DataFrame,
150
            columns: list[str],
151
            use_legend: bool = True,
152
            size: tuple[float, float] = ChartBase.SIZE_A4,
153
            **kwargs: _tp.Any,
154
    ) -> _plt.Figure:
155
        """Creates a bar chart with multiple columns displayed as grouped bars.
156

157
        Args:
158
            df: DataFrame containing the data to plot
159
            columns: List of column names to plot as bars
160
            use_legend: Whether to show the legend
161
            size: Figure size tuple (width, height)
162

163
        Returns:
164
            matplotlib Figure object
165

166
        The bars for each column are grouped together, with each group centered on the x-tick.
167
        The bars within a group are positioned side-by-side with a small gap between them.
168
        The x-axis shows the datetime index formatted according to self.DATE_FORMAT.
169
        """
170
        fig, ax = _plt.subplots(figsize=size)
2✔
171
        x = _np.arange(len(df.index))
2✔
172
        width = 0.8 / len(columns)
2✔
173

174
        for i, col in enumerate(columns):
2✔
175
            ax.bar(x + i * width, df[col], width, label=col)
2✔
176

177
        if use_legend:
2✔
178
            ax.legend()
2✔
179

180
        ax.set_xticks(x + width * (len(columns) - 1) / 2)
2✔
181
        ax.set_xticklabels(
2✔
182
            _pd.to_datetime(df.index).strftime(self.DATE_FORMAT)
183
        )
184
        ax.tick_params(axis="x", labelrotation=90)
2✔
185
        self.configure(ax)
2✔
186
        return fig
2✔
187

188

189
class LinePlot(ChartBase):
2✔
190

191
    PLOT_KIND = "line"
2✔
192

193
    def _do_plot(
2✔
194
            self,
195
            df: _pd.DataFrame,
196
            columns: list[str],
197
            use_legend: bool = True,
198
            size: tuple[float, float] = ChartBase.SIZE_A4,
199
            **kwargs: _tp.Any,
200
    ) -> _plt.Figure:
201
        fig, ax = _plt.subplots(figsize=size)
2✔
202
        ax = self.configure(ax)
2✔
203
        plot_kwargs = {
2✔
204
            "kind": self.PLOT_KIND,
205
            "colormap": self.COLOR_MAP,
206
            "legend": use_legend,
207
            "ax": ax,
208
            **kwargs,
209
        }
210
        df[columns].plot(**plot_kwargs)
2✔
211
        return fig
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc