Interactivity
Envision is mostly aimed at long-running batch processing executed on dedicated servers, and dashboards are mostly static data output from those runs. Dashboards come out of the box with standard interactivity features: tables can be filtered, charts allow hovering to view individual data points, tooltips are shown on mouse-over, etc.
For going beyond standard interactivity, Envision provides a small subset of reactive programming to describe operations that should be performed while the dashboard is being displayed, and based on the viewer’s input. Such operations are introduced by the dash
keyword.
Table of contents
The execution of the Envision script is cut into two consecutive phases:
- The processing phase, which runs on dedicated servers and produces a data package that serves as the basis for displaying the dashboard.
- The interactive phase, which runs in the viewer’s web browser, and processes that data package in order to display the dashboard. This phase runs continuously, so that any changes applied to the data by the user cause the dashboard contents to be re-computed and re-displayed.
The following example displays a table with an editable column T.Value
, and paints every line in red if T.Value
is not between T.Min
and T.Max
.
read upload "values" as Submitted with
Id : text
Value : number
Comment : text
table Values = with
[| "A" as Id, 1 as Min, 5 as Max |]
[| "B" , 0 , 10 |]
[| "C" , -5, , 5 |]
Values.Comment = single(Submitted.Comment) by Submitted.Id at Values.Id
mutable Values.Value = single(Submitted.Value) by Submitted.Id at Values.Id
dash Values.IsValid = Values.Min <= Values.Value and Values.Value <= Values.Max
dash Values.Color = if Values.IsValid then "default" else "red"
show table "Values" editable: "values" { .., ..10 } with
Values.Id { columnReadOnly: true }
mutable Values.Value { cellBackground: #[Values.Color] }
Values.Min { columnReadOnly: true }
Values.Max { columnReadOnly: true }
Values.Comment
Dash variables and dash expressions
An assignment dash Table.Variable = ...
creates a dash variable.
Its value is always computed in the reactive phase, and therefore it will not be available during the processing phase.
Expressions which contain dash variables are called dash expressions, and are also always computed in the reactive phase.
Attempting to use a dash variable or a dash expression for a non-dashboard operation will be rejected by the Envision compiler with an error message:
table T = extend.range(10)
dash T.M = T.N * 2
// Error: Cannot use dash variable 'T.M' in a non-dash assignment
T.Bad = T.M + 1
write T as "file.csv" with
T.N
// Error: Cannot use dash variable 'T.M' in a 'write' statement
T.M
Always-supported types and operations
Dash variables and dash expressions can only be of following types: number
, boolean
, text
, date
, week
, month
, markdown
, and all enum
types. Tuples are also supported.
The following operations are always allowed in dash expressions:
- Reading from a non-dash variable
- The comparison operators:
<
<=
>
>=
==
!=
~~
!~
like
, - The basic arithmetic and boolean operators
+
-
*
/
^
mod
and
or
not
, - Conditional
if then else
expressions andmatch
statements, - Text concatenation and interpolation,
- Broadcasting a scalar value into any table,
- Built-in pure functions annotated as
dash
in the documentation.
Please note that a dash variable written before a where
is usually not allowed to be read inside that where
! The only exception here is when the variable belongs to a table that is tiny.
Using dash expressions
As mentioned above, many code locations forbid the use dash variables or dash expressions. This is the most common case, and includes write
statements, where
conditions, for
loops, and assignments without the dash
keyword. An error is reported when attempting to use a dash variable in such a location.
// Error: Cannot use dash variable 'T.M' in a non-dash assignment.
T.Bad = T.M + 1
Conversely, assignment statements with the dash
keyword require a dash expression. An error is reported if the expression contains an operation or type that is not allowed in a dash expression.
read "/forecasts.ion" as Forecasts with
Demand : ranvar
// Error: This operation is not supported in a dash expression.
dash Forecasts.Mean = mean(Forecasts.Demand)
Finally, a third category allows both dash expressions and non-dash expressions; those are the expressions that are intended to be displayed in the dashboard:
- StyleCode values included with
#(..)
or#[..]
- The title of a
show
or theas
label of ashow
column - The value of a
show
column
The rule is that if such an expression contains at least one dash variable, then it will be expected to be a dash expression, and if it contains no dash variable, then it will be expected to be a non-dash expression.
Dash-mutable variables
An assignment mutable Table.Variable = ...
creates a dash-mutable variable. These are the fundamental tool for implementing interactivity, since their value can be changed by the dashboard’s viewer. Dash-mutable variables can be used like normal dash-variables, but when the value of a dash-mutable variable is changed, the dashboard automatically re-computes all values that depend on that variable.
The assignment is used to provide the initial value of the variable. It is not, and cannot be, a dash
assignment: the initial value must always computed during the processing phase.
Going back to the above example:
mutable Values.Value = single(Submitted.Value) by Submitted.Id at Values.Id
dash Values.IsValid = Values.Min <= Values.Value and Values.Value <= Values.Max
dash Values.Color = if Values.IsValid then "default" else "red"
show table "Values" editable: "values" { .., ..10 } with
Values.Id { columnReadOnly: true }
mutable Values.Value { cellBackground: #[Values.Color] }
Values.Min { columnReadOnly: true }
Values.Max { columnReadOnly: true }
Values.Comment
Here, Values.Value
is created as a dash-mutable variable, initialized with the output of the single(Submitted.Value)
aggregation.
From Values.Value
, the Values.IsValid
boolean dash variable is created, and from there, the Values.Color
text dash variable.
The show table
statement uses:
- The value of
Values.Color
as thecellBackground
StyleCode property. - The
Values.Value
is used as a column, with themutable
annotation.
The mutable
annotation tells Envision that any changes applied to the editable column should also be applied to the dash-mutable variable. If the annotation is not present, the column is still editable (consider the Values.Comment
column, which is editable despite the lack of annotation), but the edits are not applied to the dash-mutable variable.
When a dash-mutable variable is defined in a script, Envision will check that there is at least one use of that variable with the mutable
annotation.
If there are several uses with the mutable
annotation, then all those uses become linked together, and changes applied in one location are applied to all locations automatically.
Mutable contexts
The mutable
annotation can be used in specific locations, called write contexts. The previous example illustrated that a column of a show table
with the editable:
option is a write context, but there are others.
A column of a show form
is a write context:
table T = extend.range(10)
mutable Min = 0
mutable Max = 10
show form "Bounds" { ..3, ..5 } with
mutable Min
mutable Max
dash T.IsValid = Min <= T.N and T.N <= Max
show table "Values" { 4.., ..10 } with
T.N { cellBackground: #[if T.IsValid then "default" else "red"] }
Note that Envision will not report an error even though there is no read form
matching the Min
and Max
fields of the show form
. The reason for reporting this error in the first place is because it is unlikely for a show form
to let the viewer edit fields that will never be submitted or used—it is instead far more likely that the script author made an error and forgot to include or use those fields. However, if those fields are annotated as mutable
, that is a good indication that the script author did not make an error, and truly intended those fields to be used only to improve the dashboard interactivity.
Advanced topics
Sliced assignments
The Slices
table cannot contain dash variables, since by definition it is not present in the dashboard—the dashboard instead views the data one slice at a time.
Assigning a value in Slices
(or a cross-table of Slices
) to a dash variable causes the assignment to be performed separately on every slice.
dash X = Slices.X
The assigned expression is expected to be in the Slices
table, and the assigned variable must be a scalar. The value of X
will be equal to the value of Slices.X
for the slice currently being displayed (and therefore, it can be different on every slice).
Markdown
Envision supports Markdown columns based on interpolation:
T.ToolTip = """
This column can only contain values between 0 and \{T.Max}.
"""
To avoid using vast amounts of storage for the markdown column T.ToolTip
, Envision stores it in a format where the constant portions of the Markdown are de-duplicated across all lines of the table. When displaying the Markdown value in the web browser, the actual contents are reconstituted from this compressed format.
While this is technically done in the browser, it does not count as part of the interactive phase—it is conceptually closer to how displaying a numeric value on a dashboard will take a number stored in an IEEE754 32-bit floating-point format and turn it into text that can be displayed.
As such, T.ToolTip
does not need to be a dash variable, and the above assignment does not require a dash
annotation. The restrictions on T.ToolTip
are also lighter than for dash variables: it can be used inside a where
, or broadcast from one table to another, even if the tables involved are not tiny.
However, if any of the variables involved in the interpolation are dash-variables, then the normal rules for dash-variables apply: the assignment must be annotated with dash, the resulting Markdown variable must be a dash variable, and will be subject to all the standard restrictions of dash variables.
In the example below, the value of T.ToolTip
uses the dash variable T.FuzzMax
, and so T.ToolTip
must be assigned with a dash
annotation and becomes a dash variable itself.
mutable FuzzFactor = 1.5
dash T.FuzzMax = floor(T.Max * FuzzFactor)
dash T.ToolTip = """
This column can only contain values between 0 and \{T.FuzzMax}.
"""