-
Notifications
You must be signed in to change notification settings - Fork 297
Tags for series
WeeWX Version 4.5 introduces limited support of tags for working with series. The results can be formatted either as JSON, or as a string. This document describes the syntax.
NOTE: This syntax is still experimental and subject to change!
The tags used to specify a series is very similar to tags used for regular scalars, except they
include the keyword series
:
$period.obstype.series[.optional_unit_conversion][.optional_rounding][.optional_formatting]
The tags .optional_unit_conversion
, .optional_rounding
, and .optional_formatting
are
explained below.
The tag .series()
can take a number of optional parameters:
.series(aggregate_type=None,
aggregate_interval=None,
time_series='both',
time_unit='unix_epoch')
Parameter | Effect |
---|---|
aggregate_type |
The type of aggregation (max , avg , etc.) to perform. |
aggregate_interval |
The length of each aggregation time in seconds. "Nicknames" (such as "day") are allowed. |
time_series |
Which time variables to include in the results. Choices are start , stop , or both . |
time_unit |
What time unit to use for the results. Choices are unix_epoch , unix_epoch_ms , or unix_epoch_ns . |
Here's an example of asking for a series with the temperature for all records in the day. We will
display it with an HTML <pre>
tag so that the embedded newlines work.
<pre>
$day.outTemp.series
</pre>
This would result in something like this:
12:00:00 AM, 12:05:00 AM, 43.8°F
12:05:00 AM, 12:10:00 AM, 43.8°F
12:10:00 AM, 12:15:00 AM, 42.7°F
12:15:00 AM, 12:20:00 AM, 41.3°F
...
The first column is the start time of each point in the series, the second column is the stop time. From this example, we can see that the data have a 5 minute archive period.
You can request that only the start, or stop, times be included. Here's an example where only the start time is included:
<pre>
$day.outTemp.series(time_series='start')
</pre>
Results:
12:00:00 AM, 43.8°F
12:05:00 AM, 43.8°F
12:10:00 AM, 42.7°F
12:15:00 AM, 41.3°F
...
Suppose you would like the maximum temperature for each day of the month. This is an aggregation
(maximum temperature, in this case), over a time period (one day). This can be specified with
optional parameters aggregate_type
and aggregate_interval
to the series
tag. Here's
an example:
<pre>
$month.outTemp.series(aggregate_type='max', aggregate_interval=86400)
</pre>
where 86400
is the number of seconds in the day. As an alternative, you can use the string day
:
<pre>
$month.outTemp.series(aggregate_type='max', aggregate_interval='day')
</pre>
Either way, the results would be:
03/01/2021 12:00:00 AM, 03/02/2021 12:00:00 AM, 58.2°F
03/02/2021 12:00:00 AM, 03/03/2021 12:00:00 AM, 55.8°F
03/03/2021 12:00:00 AM, 03/04/2021 12:00:00 AM, 59.6°F
03/04/2021 12:00:00 AM, 03/05/2021 12:00:00 AM, 57.8°F
03/05/2021 12:00:00 AM, 03/06/2021 12:00:00 AM, 50.2°F
03/06/2021 12:00:00 AM, 03/07/2021 12:00:00 AM, 42.0°F
...
The first column is the start of the aggregation period, the second the end of the period, and the final column the maximum temperature for aggregation period. In this example, because the aggregation period is one day, the start and stop fall on daily boundaries.
Just like scalars, the unit system of the resultant series can be changed. Only the data part, not the time part, is converted. For example,
<pre>
$month.outTemp.series(aggregate_type='max', aggregate_interval='day').degree_C
</pre>
Results in
03/01/2021 12:00:00 AM, 03/02/2021 12:00:00 AM, 14.6°C
03/02/2021 12:00:00 AM, 03/03/2021 12:00:00 AM, 13.2°C
03/03/2021 12:00:00 AM, 03/04/2021 12:00:00 AM, 15.3°C
03/04/2021 12:00:00 AM, 03/05/2021 12:00:00 AM, 14.3°C
03/05/2021 12:00:00 AM, 03/06/2021 12:00:00 AM, 10.1°C
03/06/2021 12:00:00 AM, 03/07/2021 12:00:00 AM, 5.6°C
...
Similar to its scalar cousins, custom formatting can be applied to the results. Currently, there are two types of formatting: one for strings, and one for JSON.
The format of the data can be changed with optional suffix .format()
. Only the data is affected.
If you want to change the formatting of the start and stop times, you must use iteration. See
the section Iteration below.
Example:
$month.outTemp.series(aggregate_type='max', aggregate_interval='day').format("%.2f")
yields something like
03/01/2021 12:00:00 AM, 03/02/2021 12:00:00 AM, 58.20°F
03/02/2021 12:00:00 AM, 03/03/2021 12:00:00 AM, 55.80°F
03/03/2021 12:00:00 AM, 03/04/2021 12:00:00 AM, 59.60°F
03/04/2021 12:00:00 AM, 03/05/2021 12:00:00 AM, 57.80°F
03/05/2021 12:00:00 AM, 03/06/2021 12:00:00 AM, 50.20°F
03/06/2021 12:00:00 AM, 03/07/2021 12:00:00 AM, 42.00°F
...
By adding the suffix .json()
to the tag, the results will be formatted as JSON. This option has
one optional parameter order_by
, It can also pass on parameters to the json.loads()
call.
.json(order_by=['row'|'column'],
**kwargs)
Parameter | Effect |
---|---|
order_by |
The returned JSON can either be organized by rows, or by columns. The default is row . |
kwargs |
Optional keyword arguments that are passed on to the Python json.dumps() call. |
Here's an example of the maximum temperature for all days of the current month, formatted in JSON
<pre>
$month.outTemp.series(aggregate_type='max', aggregate_interval='day').json
</pre>
This results in:
[[1614585600, 1614672000, 58.2], [1614672000, 1614758400, 55.8], [1614758400, 1614844800, 59.6], [1614844800, 1614931200, 57.8], [1614931200, 1615017600, 50.2], [1615017600, 1615104000, 42.0]]
The default is to order by row. If you want it by column:
<pre>
$month.outTemp.series(aggregate_type='max', aggregate_interval='day').json(order_by='column')
</pre>
Results:
[[1614585600, 1614672000, 1614758400, 1614844800, 1614931200, 1615017600], [1614672000, 1614758400, 1614844800, 1614931200, 1615017600, 1615104000], [58.2, 55.8, 59.6, 57.8, 50.2, 42.0]]
The above examples include both start and stop times of each interval.
If you want only the start times, then use the optional argument time_series
:
<pre>
$month.outTemp.series(aggregate_type='max', aggregate_interval='day', time_series='start').json
</pre>
Results:
[[1614585600, 58.2], [1614672000, 55.8], [1614758400, 59.6], [1614844800, 57.8], [1614931200, 50.2], [1615017600, 42.0]]
Suppose you want the previous example, except that you want the unix epoch time to be in
miliseconds. To do this, add optional argument time_unit
to series()
:
<pre>
$month.outTemp.series(aggregate_type='max', aggregate_interval='day', time_series='start', time_unit='unix_epoch_ms').json
</pre>
Results:
[[1614585600000, 58.2], [1614672000000, 55.8], [1614758400000, 59.6], [1614844800000, 57.8], [1614931200000, 50.2], [1615017600000, 42.0]]
Suppose you want the results in °C, rather than °F. Then including a .degree_C
between the
.series
and .json
tags will give the desired results:
<pre>
$month.outTemp.series(aggregate_type='max', aggregate_interval='day', time_series='start').degree_C.json
</pre>
[[1614585600, 14.555555555555555], [1614672000, 13.222222222222221], [1614758400, 15.333333333333334], [1614844800, 14.333333333333334], [1614931200, 10.111111111111112], [1615017600, 5.555555555555555]]
Note that the previous example demonstrating unit conversion resulted in many extra decimal digits.
It's an accurate representation of the internal data, but you may not want to transmit that much
data over the network. You can limit the number of decimal digits by using an optional tag
.round(ndigits)
, where ndigits
is the number of decimal digits to retain. For example:
<pre>
$month.outTemp.series(aggregate_type='max', aggregate_interval='day', time_series='start').degree_C.round(2).json
</pre>
This gives a much more compact representation:
[[1614585600, 14.56], [1614672000, 13.22], [1614758400, 15.33], [1614844800, 14.33], [1614931200, 10.11], [1615017600, 5.56]]
A series over types windvec
and windgustvec
return a series of complex numbers. For example,
<pre>
$month.windvec.series(aggregate_type='max', aggregate_interval='day').json(indent=2)
</pre>
yields
[
[
1614585600,
1614672000,
[
-6.0,
-7.347880794884119e-16
]
],
[
1614672000,
1614758400,
[
-9.0,
-1.102182119232618e-15
]
],
[
1614758400,
1614844800,
[
-1.1480502970952693,
-2.77163859753386
]
],
...
]
There are a number of conversion operators that can yield various parts of the complex results.
Operator | Effect |
---|---|
.x |
Just the x-components |
.y |
Just the y-components |
.magnitude |
Just the total (absolute) magnitude |
.direction |
Just the compass direction (in degrees 0°=N, 90°=E, etc.) |
.polar |
As polar coordinates (magnitude , direction ) |
Note that direction uses compass directions.
Here's an example. Other operators are similar. Suppose we would like the output in polar
notation, that is a 2-way tuple of (magnitude
, direction
), where direction
is the compass
direction.
<pre>
$month.windvec.series(aggregate_type='max', aggregate_interval='day').polar.json(indent=2)
</pre>
yields
[
[
1614585600,
1614672000,
[
6.0,
270.0
]
],
[
1614672000,
1614758400,
[
9.0,
270.0
]
],
[
1614758400,
1614844800,
[
2.9999999999999996,
202.5
]
],
...
If you want finer control over formatting, you can iterate over the series and apply precise formatting. Here's an example:
<table>
<tr>
<td>Start date</td>
<td>Max temperature</td>
</tr>
#for ($start, $stop, $data) in $month.outTemp.series(aggregate_type='max', aggregate_interval='day') ## 1
<tr>
<td>$start.format("%Y-%m-%d")</td> ## 2
<td>$data.format("%.2f")</td> ## 3
</tr>
#end for
</table>
Here, we create a table. Each row is individually formatted. Comments below refer to the marked lines:
-
Once evaluated, the tag
$month.outTemp.series(aggregate_type='max', aggregate_interval='day')
returns aSeriesHelper
. Normally, in order to embed the results into a document, Cheetah would try to convert this into a string. However, in this case, we are iterating over the tag. Iterating over aSeriesHelper
returns a 3-way tuplestart
,stop
, anddata
, each an instance ofValueHelper
. They can be formatted like any otherValueHelper
. -
We will work only with the start times and data. On line 2, we apply a custom formatting for the start times, so that only the date (no time) is shown.
-
Similarly, we apply some custom formatting for the datum to show two decimal points.
The final results look like:
<table>
<tr>
<td>Start date</td>
<td>Max temperature</td>
</tr>
<tr>
<td>2021-03-01</td>
<td>58.20°F</td>
</tr>
<tr>
<td>2021-03-02</td>
<td>55.80°F</td>
</tr>
<tr>
<td>2021-03-03</td>
<td>59.60°F</td>
</tr>
<tr>
<td>2021-03-04</td>
<td>57.80°F</td>
</tr>
<tr>
<td>2021-03-05</td>
<td>50.20°F</td>
</tr>
<tr>
<td>2021-03-06</td>
<td>42.00°F</td>
</tr>
</table>
Unfortunately, this Markdown document cannot show rendered HTML but, once rendered, it would look something like:
Start date Max temperature
2021-03-01 58.20°F
2021-03-02 55.80°F
2021-03-03 59.60°F
2021-03-04 57.80°F
2021-03-05 50.20°F
2021-03-06 42.00°F
We saw some examples above where the results of a tag can be formatted as JSON. However, there are cases where you need to combine several queries together to get the results you desire. Here's a common example: you wish to create a JSON structure with the minimum and maximum temperature for each day in a month.
Creating separate series of minimums and maximums is easy enough,
$month.outTemp.series(aggregate_type='min', aggregate_interval='day').json
$month.outTemp.series(aggregate_type='max', aggregate_interval='day').json
but how do you combine them into a single structure? Here's one way to do it:
#set $min_sh = $month.outTemp.series(aggregate_type='min', aggregate_interval='day')
#set $max_sh = $month.outTemp.series(aggregate_type='max', aggregate_interval='day')
<pre>
$jsonize($zip($min_sh.start.raw, $min_sh.data.raw, $max_sh.data.raw))
</pre>
The values $min_sh
and $max_sh
are SeriesHelper
, each of which have three attributes:
.start
, .stop
, and .data
, which are, respectively, the start times, stop times, and data.
So, $min_sh.start
will be a series with just the start times. Similarly, $min_sh.data
will a
series with the aggregated minimum values, $max_sh.data
a series with the aggregated maximum
values.
We then use the Python function zip()
to
interleave the start times, minimums, and maximums together. This results in a list of 3-way tuples
(time, minimum, maximum). The WeeWX helper function $jsonize()
is then used to convert this to
JSON. The result looks something like this:
[[1609488000, 38.9, 45.6], [1609574400, 41.6, 46.2], [1609660800, 40.7, 49.5], ... ]