19
19
"""
20
20
from dataclasses import dataclass
21
21
import datetime
22
+ import enum
22
23
from typing import Iterable , Optional , Generic , Union , Callable , Tuple , List
23
24
24
25
from markupsafe import Markup
@@ -118,6 +119,32 @@ def get_connectors(self) -> Iterable[WebUIConnector]:
118
119
return self .connectors
119
120
120
121
122
+ class ChartPlotStyle (enum .Enum ):
123
+ #: Uses `LINE_DOTS` for aggregated values, otherwise `LINE_FILLED`
124
+ AUTO = "auto"
125
+ #: A simple line plot, no dots, no background filling
126
+ LINE = "line"
127
+ #: A line plot with dots, no background filling
128
+ LINE_DOTS = "line_dots"
129
+ #: A pretty line plot with slightly colored background area
130
+ LINE_FILLED = "line_filled"
131
+ #: An area plot without visible line but stronger colored filled area
132
+ AREA = "area"
133
+
134
+
135
+ class ChartLineInterpolation (enum .Enum ):
136
+ #: Uses `SMOOTH` for aggregated values, otherwise `LINEAR`
137
+ AUTO = "auto"
138
+ #: Use bezier line interpolation
139
+ SMOOTH = "smooth"
140
+ #: Use linear interpolation (straight lines between data points)
141
+ LINEAR = "linear"
142
+ #: Use stepped graph, beginning a horizontal line at each data point
143
+ STEP_BEFORE = "before"
144
+ #: Use stepped graph with horizontal lines ending at each data point
145
+ STEP_AFTER = "after"
146
+
147
+
121
148
@dataclass
122
149
class ChartDataSpec :
123
150
"""Specification of one data log source and the formatting of its datapoints within a :class:`ChartWidget`"""
@@ -134,6 +161,12 @@ class ChartDataSpec:
134
161
scale_factor : float = 1.0
135
162
#: Unit symbol to be shown after the value in the Chart tooltip
136
163
unit_symbol : str = ""
164
+ #: If not None, this data row will be stacked upon (values added to) previous data rows with the same `stack_group`
165
+ stack_group : Optional [str ] = None
166
+ #: Select different plot styles (area vs. line plot, dots on/off)
167
+ plot_style : ChartPlotStyle = ChartPlotStyle .AUTO
168
+ #: Select different line interpolation styles (smoothed, linear, stepped)
169
+ line_interpolation : ChartLineInterpolation = ChartLineInterpolation .AUTO
137
170
138
171
139
172
class ChartWidget (WebPageItem ):
@@ -213,14 +246,22 @@ def __init__(self, interval: datetime.timedelta, data_spec: List[ChartDataSpec]
213
246
aggregation_interval , align_to = self .align_ticks_to ,
214
247
converter = None if spec .scale_factor == 1.0 else lambda x : x * spec .scale_factor ,
215
248
include_previous = True )
249
+ line_interpolation = spec .line_interpolation
250
+ if line_interpolation == ChartLineInterpolation .AUTO :
251
+ line_interpolation = ChartLineInterpolation .SMOOTH if is_aggregated else ChartLineInterpolation .LINEAR
252
+ plot_style = spec .plot_style
253
+ if plot_style == ChartPlotStyle .AUTO :
254
+ plot_style = ChartPlotStyle .LINE_DOTS if is_aggregated else ChartPlotStyle .LINE_FILLED
216
255
self .connectors .append (connector )
217
256
self .row_specs .append ({'id' : id (connector ),
218
- 'stepped_graph' : is_aggregated ,
219
- 'show_points' : is_aggregated ,
220
257
'color' : spec .color if spec .color is not None else self .COLORS [i % len (self .COLORS )],
221
258
'label' : spec .label ,
222
259
'unit_symbol' : spec .unit_symbol ,
223
- 'extend_graph_to_now' : not is_aggregated })
260
+ 'extend_graph_to_now' : not is_aggregated ,
261
+ 'stack_group' : spec .stack_group ,
262
+ 'style' : plot_style .value ,
263
+ 'interpolation' : line_interpolation .value ,
264
+ })
224
265
225
266
async def render (self ) -> str :
226
267
return await jinja_env .get_template ('log/chart.htm' ).render_async (
0 commit comments