6. Transformations

6.1. From table to widget

Data from one or more Explorer tables need to be converted into a format that is understood by a widget. Transformations allow widgets to perform these conversions. Take for example the following table:

_images/transformations_table.png

The raw data looks like this:

[
  {
    "header": [
      { "name": "No." },
      { "name": "Referentiedatum" },
      { "name": "Groep grootte" }
    ],
    "poprows": [
      [null, "Alles", 66228]
    ],
    "preset": "DB_VERLOOP",
    "rows": [
      [1, "2016-06-01", 4719],
      [2, "2016-07-01", 4663],
      [3, "2016-08-01", 4714],
      [4, "2016-09-01", 4495],
      [5, "2016-10-01", 4592],
      [6, "2016-11-01", 4582],
      [7, "2016-12-01", 4612],
      [8, "2017-01-01", 4705],
      [9, "2017-02-01", 4998],
      [10, "2017-03-01", 5649],
      [11, "2017-04-01", 6087],
      [12, "2017-05-01", 6163],
      [13, "2017-06-01", 6249]
    ]
  }
]

If we want to display this data in a barline chart, we can configure the widget as follows:

widget_barlinechart:
  title: Voorbeeld staaflijngrafiek
  type: barlinechart
  data:
    app: explorer_patient
    parameters:
      preset: DB_VERLOOP
    transformations:
      bar:
        - table(0)
        - column(2)
      line:
        - table(0)
        - column(2)
        - smooth(moving_average,3)
      labels:
        - table(0)
        - column(1)

This widget needs three items: bar (array of values for the y-axis of the bar), line (array of values for the y-axis of the line) and labels (array of values for the labels on the x-axis).

For bar we select the first (and only) table and then a single column with index 2.

For line we select the same column, but then perform a smoothing function on it, i.e. a moving average with window size 3.

For labels we select a single column with index 1.

When the backend has performed the transformations, the data for the widget looks like this:

{
  "bar": [
    4719,
    4663,
    4714,
    4495,
    4592,
    4582,
    4612,
    4705,
    4998,
    5649,
    6087,
    6163,
    6249
  ],
  "line": [
    4719.00,
    4691.00,
    4698.67,
    4624.00,
    4600.33,
    4556.33,
    4595.33,
    4633.00,
    4771.67,
    5117.33,
    5578.00,
    5966.33,
    6166.33
  ],
  "labels": [
    "2016-06-01",
    "2016-07-01",
    "2016-08-01",
    "2016-09-01",
    "2016-10-01",
    "2016-11-01",
    "2016-12-01",
    "2017-01-01",
    "2017-02-01",
    "2017-03-01",
    "2017-04-01",
    "2017-05-01",
    "2017-06-01"
  ],
  "timestamp": "2023-12-04 15:38:37"
}

Then we get the following widget:

_images/widget_barlinechart2.png

6.2. Transformation variables

Transformations construct_array and construct_value can reference the output of other transformations. Each transformation key that starts with an underscore is treated as a variable. The result of these transformations can be used in other transformations, but are not returned to the widget. Variables must be declared before they are used, i.e. all transformation keys with an underscore should appear before all other transformation keys.

The following example creates two variables (_processed and _total), which are used in the calculations of the actual widget data in percentage and value.

transformations:
  _processed:
    - table(0)
    - row(0)
    - index(2)
  _total:
    - table(0)
    - poprow(0)
    - index(2)
  percentage:
    - construct_value(_processed/_total*100)
  value:
    - construct_value(_processed)

6.3. Available transformations

From

To

Transformations

explorertables

explorertable

table

explorertable

table

columns, find_rows, poprows, rows

explorertable

array

column, find_row, header, poprow, row

explorertable

value

table

table

construct_table, replace_table, slice_table, transpose_table

table

array

merge_table

table

value

aggregate_table

array

table

array_to_table

array

array

default_array, label_array, reverse_array, slice_array, smooth_array

array

value

aggregate_array, index

value

table

value

array

value_to_array

value

value

default_value, format_value

any

table

any

array

construct_array, literal_array

any

value

construct_value, literal_value

class AggregateArrayTransformation
>>> input = [1, 2, 3]
>>> func = 'aggregate_array(max)'
>>> transform(func, input)
3
>>> func = 'aggregate_array(sum)'
>>> transform(func, input)
6
class AggregateTableTransformation
>>> input = [[1, 2, 3], [4, 5, 6]]
>>> func = 'aggregate_table(column_count)'
>>> transform(func, input)
3
>>> func = 'aggregate_table(row_count)'
>>> transform(func, input)
2
class ArrayToTableTransformation
>>> input = [1, 2, 3]
>>> func = 'array_to_table()'
>>> transform(func, input)
[[1, 2, 3]]
class ColumnTransformation
>>> input = { 'header': [{'name': 'Date'}, {'name': 'Value'}], 'rows': [['2020-01-01', 3], ['2020-02-01', 5]] }
>>> func = 'column(1)'
>>> transform(func, input)
[3, 5]
>>> func = 'column(Value)'
>>> transform(func, input)
[3, 5]
class ColumnsTransformation
>>> input = { 'header': [{'name': 'Date'}, {'name': 'Value1'}, {'name': 'Value2'}], 'rows': [['2020-01-01', 3, 30], ['2020-02-01', 5, 50]] }
>>> func = 'columns(1,2)'
>>> transform(func, input)
[[3, 5], [30, 50]]
>>> func = 'columns(Date,Value2)'
>>> transform(func, input)
[['2020-01-01', '2020-02-01'], [30, 50]]
class ConstructArrayTransformation
>>> input = [5, 6, 7]
>>> func = 'construct_array(input@0,input@1+input@2)'
>>> transform(func, input)
[5, 13]
>>> func = 'construct_array(20,20-input@0)'
>>> transform(func, input)
[20, 15]
>>> input = [10, 15, 25]
>>> func = 'construct_array((input@2-input@0)/(input@0+input@1+input@2)*100)'
>>> transform(func, input)
[30]
>>> func = 'construct_array(nps(input@0;input@1;input@2))'
>>> transform(func, input)
[30]
class ConstructTableTransformation
>>> input = [[5, 6, 7], [8, 9, 10]]
>>> func = 'construct_table(row@0,row@1+row@2)'
>>> transform(func, input)
[[5, 13], [8, 19]]
>>> func = 'construct_table(nps(row@0;row@1;row@2))'
>>> transform(func, input)
[[11], [7]]
class ConstructValueTransformation
>>> input = 6
>>> func = 'construct_value(input+1)'
>>> transform(func, input)
7
>>> func = 'construct_value(input/2)'
>>> transform(func, input)
3
>>> input = [1, 2, 3]
>>> func = 'construct_value(nps(input@0;input@1;input@2))'
>>> transform(func, input)
33
class DefaultArrayTransformation
>>> input = ['Value A', '', 'Value B']
>>> func = 'default_array(Unknown)'
>>> transform(func, input)
['Value A', 'Unknown', 'Value B']
class DefaultValueTransformation
>>> input = ''
>>> func = 'default_value(Unknown)'
>>> transform(func, input)
'Unknown'
class FindRowTransformation
>>> input = { 'header': [{'name': 'Date'}, {'name': 'Value'}], 'rows': [['2020-01-01', 3],['2020-02-01', 5]] }
>>> func = 'find_row(Value,5)'
>>> transform(func, input)
['2020-02-01', 5]
>>> func = 'find_row(0,2020-02-01,Value,5)'
>>> transform(func, input)
['2020-02-01', 5]
class FindRowsTransformation
>>> input = { 'header': [{'name': 'Date'}, {'name': 'Value'}], 'rows': [['2020-01-01', 3],['2020-02-01', 5]] }
>>> func = 'find_rows(Value,5)'
>>> transform(func, input)
[['2020-02-01', 5]]
>>> func = 'find_rows(0,2020-02-01,Value,5)'
>>> transform(func, input)
[['2020-02-01', 5]]
class FormatValueTransformation
>>> input = 3
>>> func = 'format_value(n = {})'
>>> transform(func, input)
'n = 3'
>>> input = 3.45678
>>> func = 'format_value(n = {.00})'
>>> transform(func, input)
'n = 3,46'
class HeaderTransformation
>>> input = { 'header': [{'name': 'Date'}, {'name': 'Value'}], 'poprows': [['All', 234]], 'rows': [['2020-01-01', 3],['2020-02-01', 5]] }
>>> func = 'header()'
>>> transform(func, input)
['Date', 'Value']
class IndexTransformation
>>> input = [3, 5, 7, 9]
>>> func = 'index(2)'
>>> transform(func, input)
7
class LabelArrayTransformation
>>> input = ['Age >= 10', 'Value = 42']
>>> func = 'label_array(strip_grouplabel)'
>>> transform(func, input)
['>= 10', '42']
>>> input = ['short string', 'a longer string']
>>> func = 'label_array(wrap,12)'
>>> transform(func, input)
[['short string'], ['a longer', 'string']]
class LiteralArrayTransformation
>>> input = None
>>> func = 'literal_array(January,February,March)'
>>> transform(func, input)
['January', 'February', 'March']
class LiteralValueTransformation
>>> input = None
>>> func = 'literal_value(January)'
>>> transform(func, input)
'January'
class MergeTableTransformation
>>> input = [[2022, 7, 5], [2023, 9, 13], [2024, 11, 21]]
>>> func = 'merge_table(year_month,0,1)'
>>> transform(func, input)
['2022-07', '2023-09', '2024-11']
>>> func = 'merge_table(year_month_day,0,1,2)'
>>> transform(func, input)
['2022-07-05', '2023-09-13', '2024-11-21']
class PoprowTransformation
>>> input = { 'header': [{'name': 'Date'}, {'name': 'Value'}], 'poprows': [['All', 234]], 'rows': [['2020-01-01', 3],['2020-02-01', 5]] }
>>> func = 'poprow(0)'
>>> transform(func, input)
['All', 234]
class PoprowsTransformation
>>> input = { 'header': [{'name': 'Date'}, {'name': 'Value'}], 'poprows': [['All', 234], ['Group 1', 180], ['Group 2', 54]], 'rows': [['2020-01-01', 3],['2020-02-01', 5]] }
>>> func = 'poprows(1,2)'
>>> transform(func, input)
[['Group 1', 180], ['Group 2', 54]]
>>> func = 'poprows(2)'
>>> transform(func, input)
[['Group 2', 54]]
class ReplaceTableTransformation
>>> input = [[1, 3, 5], [3, 4, 6]]
>>> func = 'replace_table(3,30)'
>>> transform(func, input)
[[1, 30, 5], [30, 4, 6]]
class ReverseArrayTransformation
>>> input = [1, 2, 3]
>>> func = 'reverse_array()'
>>> transform(func, input)
[3, 2, 1]
class RowTransformation
>>> input = { 'header': [{'name': 'Date'}, {'name': 'Value'}], 'rows': [['2020-01-01', 3],['2020-02-01', 5]] }
>>> func = 'row(0)'
>>> transform(func, input)
['2020-01-01', 3]
class RowsTransformation
>>> input = { 'header': [{'name': 'Date'}, {'name': 'Value'}], 'rows': [['2020-01-01', 3],['2020-02-01', 5]] }
>>> func = 'rows(0,1)'
>>> transform(func, input)
[['2020-01-01', 3], ['2020-02-01', 5]]
>>> func = 'rows(1)'
>>> transform(func, input)
[['2020-02-01', 5]]
class SliceArrayTransformation
>>> input = [3, 5, 7, 9]
>>> func = 'slice_array(1,3)'
>>> transform(func, input)
[5, 7]
>>> func = 'slice_array(,,2)'
>>> transform(func, input)
[3, 7]
>>> func = 'slice_array(1,,2)'
>>> transform(func, input)
[5, 9]
class SliceTableTransformation
>>> input = [[1, 3, 5, 7, 9, 11], [2, 4, 6, 8, 10, 12]]
>>> func = 'slice_table(1,4,2)'
>>> transform(func, input)
[[3, 7], [4, 8]]
>>> func = 'slice_table(1,,2)'
>>> transform(func, input)
[[3, 7, 11], [4, 8, 12]]
>>> func = 'slice_table(,,2)'
>>> transform(func, input)
[[1, 5, 9], [2, 6, 10]]
class SmoothArrayTransformation
>>> input = [50, 60, 70, 40, 40, 40, 90, 90]
>>> func = 'smooth_array(average)'
>>> transform(func, input)
[60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0]
>>> func = 'smooth_array(moving_average,2)'
>>> transform(func, input)
[50.0, 55.0, 65.0, 55.0, 40.0, 40.0, 65.0, 90.0]
class TableTransformation
>>> input = [{ 'header': [{'name': 'Date'}, {'name': 'Value1'}, {'name': 'Value2'}], 'rows': [['2020-01-01', 3, 30], ['2020-02-01'], 5, 50] }]
>>> func = 'table(0)'
>>> transform(func, input)
{'header': [{'name': 'Date'}, {'name': 'Value1'}, {'name': 'Value2'}], 'rows': [['2020-01-01', 3, 30], ['2020-02-01'], 5, 50]}
class Transformation

Base transformation class.

class TransformationDataTypes(value)
class TransposeTableTransformation
>>> input = [[1, 2, 3], [4, 5, 6]]
>>> func = 'transpose_table()'
>>> transform(func, input)
[[1, 4], [2, 5], [3, 6]]
class ValueToArrayTransformation
>>> input = 42
>>> func = 'value_to_array()'
>>> transform(func, input)
[42]