loop
The loop keyword offers a mechanism to repeat a short series of Envision
operations. The maximal number of iterations is 30. This low maximum is
intentional as arbitrary loops introduce problems that are better solved
through the other constructs of the Envision language.
loop (n : number), code block
The loop keyword takes a single argument which must be an integer constant
between 1 and 30 (inclusive).
The count may be any constant expression.
a = 1
loop 3
b = a + 1
a = 2 * b
show summary "" with a, b // 22, 11
Ordinary loop does not introduce a new scope; variables defined inside remain visible.
The block is a macro expansion repeated n times.
loop (n : number) in (low : number) .. (high : number), code block
The loop keyword defines an iteration variable over a range of integer
values. The boundaries are inclusive, and must contain between 1 and 30
values.
s = 0
loop n in 11 .. 15
s = s + n
show summary "" with s // 65
loop (n : number) in sequence, code block
The loop keyword defines an iteration variable over an explicit list of
values. The list length (and thus the iteration count) is capped at 30.
Concat = ""
loop channel in ("Online", "Store", "Wholesale")
Concat = "\{Concat}\{channel}"
show scalar "" with Concat // OnlineStoreWholesale
The list can contain arbitrary expressions and tuple unpacking. As an extension
of the same form, loop ... in enum E iterates over the labels of a constant
enum table. The enum table must be non-empty and contain at most 30 values. The
iteration variable is a text value equal to the enum label.
The following example is equivalent to the explicit sequence above, but the sequence is provided by the enum table.
table enum Channel = "Online", "Store", "Wholesale"
Concat = ""
loop channel in enum Channel
Concat = "\{Concat}\{channel}"
show scalar "" with Concat // OnlineStoreWholesale
Compile-time iteration variables
loop const makes the iteration variable a compile-time constant. It can be
used with an integer range, such as loop const batch in 1..2, or an explicit
list, such as loop const batch in (1, 2). The values must be constant, and
the maximum remains 30 iterations.
This form is useful when each iteration needs a different input path. Unlike
an ordinary loop variable, batch below can be interpolated into the path
of a table read statement:
total = 0
loop const batch in 1..2
batchQty = with
table Sales = read "/sample/sales-\{batch}.csv" with
Qty : number
return sum(Sales.Qty)
total = total + batchQty
show scalar "Units sold across both files" with total
This reads /sample/sales-1.csv and /sample/sales-2.csv. Replacing
1..2 with (1, 2) gives the same result. The local with scope keeps each
Sales table separate. The constant iteration variable is not available
after the loop, while total retains the accumulated result.
loop (F : flagset) subset flags(…), code block
The loop keyword can iterate over all subsets of a constant flagset returned
by flags(...). The iteration variable F is a flagset. The loop includes the
empty set and the full set. The number of iterations is 2^k, where k is the
number of flags. At most 16 iterations are allowed (a flagset size of 4).
table Orders[o] = with
[| as o, as Color, as Size, as Brand, as Qty |]
[| 1, "Red", "S", "A", 2 |]
[| 2, "Blue", "M", "B", 1 |]
table OrdersCube = with
loop F subset flags(0, 1, 2)
[| if contains(F, 0) then Orders.Color else "All" as Color,
if contains(F, 1) then Orders.Size else "All" as Size,
if contains(F, 2) then Orders.Brand else "All" as Brand,
o as o,
Orders.Qty as Qty |]
show table "OrdersCube" with
OrdersCube.Color
OrdersCube.Size
OrdersCube.Brand
OrdersCube.o
OrdersCube.Qty
Producing tiles inside a loop
In a dashboard that uses block placements, a stand-alone show statement can
appear inside a loop. Each iteration produces a separate tile. Use
first(n) on one placement axis when the number of
tiles depends on the loop expansion:
table T = extend.range(10)
loop a in 1..2
show scalar "A=\{a}" { 1, first(2) } with count(T.N mod 2 == a - 1)
The first tile occupies { 1, 1..2 }, and the second occupies
{ 1, 4..5 }. For each iteration, first(2) finds the first available span of
two rows among the tiles already placed in the same region.
Restrictions
loop blocks cannot include import, def, write, nested loop, or
ordinary read ... as T statements. Table read statements inside a local
with scope are supported, as illustrated above. Stand-alone show
statements require block placements and
are rejected in old-style dashboards that use only legacy Excel-like
coordinates. Outside a local scope, table declarations can re-apply a filter
to the same table across iterations, but cannot repeatedly create that table.
a = 10
b = 0
table T = extend.range(10)
loop 3
a = a - 1
table T = where T.N < a
b = b + sum(T.N)
loop can be used inside table comprehensions:
table T = with
[| as A |]
loop N in 1..3
[| N |]
loop can also be used inside show ... with bodies. In that context, each
iteration contributes columns or tile-specific sub-blocks to the surrounding
tile rather than introducing nested show statements. This pattern is useful
for monthly reports, where one loop iteration can produce one month column.
keep span date = [date(2024, 1, 1) .. date(2024, 6, 30)]
table Items[item] = with
[| as item |]
[| "shirt" |]
[| "hat" |]
table Sales = with
[| as Item, as Date , as Qty |]
[| "shirt", date(2024, 1, 15), 120 |]
[| "shirt", date(2024, 2, 15), 140 |]
[| "shirt", date(2024, 3, 15), 135 |]
[| "shirt", date(2024, 4, 15), 150 |]
[| "shirt", date(2024, 5, 15), 155 |]
[| "shirt", date(2024, 6, 15), 160 |]
[| "hat" , date(2024, 1, 15), 80 |]
[| "hat" , date(2024, 2, 15), 95 |]
[| "hat" , date(2024, 3, 15), 110 |]
[| "hat" , date(2024, 4, 15), 105 |]
[| "hat" , date(2024, 5, 15), 115 |]
[| "hat" , date(2024, 6, 15), 125 |]
table Monthly[key] = by [Sales.Item, month(Sales.Date)]
Monthly.Item, Monthly.Period = key
Monthly.Qty = sum(Sales.Qty)
latest = max(Month.month)
show table "Last 6 months" with
item as "Item"
loop k in 0..5
Monthly.Qty[item, latest - 5 + k] as text(latest - 5 + k)
See show for the general rules that apply inside tile bodies.