0
# Expressions & Conditions
1
2
Expression system for calculated fields, conditional logic, and dynamic values using Vega expression language with mathematical, string, and logical operations. Expressions enable sophisticated data transformations and conditional visualizations.
3
4
## Capabilities
5
6
### Expression API
7
8
Comprehensive expression interface providing access to mathematical, string, logical, and utility functions from the Vega expression language.
9
10
```python { .api }
11
class ExpressionAPI:
12
"""Main expression interface with extensive function library."""
13
14
# Constants
15
NaN: float
16
PI: float
17
E: float
18
LN2: float
19
LN10: float
20
LOG2E: float
21
LOG10E: float
22
SQRT1_2: float
23
SQRT2: float
24
25
# Mathematical functions
26
def abs(self, value):
27
"""Absolute value."""
28
29
def acos(self, value):
30
"""Arccosine in radians."""
31
32
def asin(self, value):
33
"""Arcsine in radians."""
34
35
def atan(self, value):
36
"""Arctangent in radians."""
37
38
def atan2(self, y, x):
39
"""Two-argument arctangent."""
40
41
def ceil(self, value):
42
"""Ceiling (round up to integer)."""
43
44
def clamp(self, value, min_val, max_val):
45
"""Clamp value to range [min, max]."""
46
47
def cos(self, value):
48
"""Cosine."""
49
50
def exp(self, value):
51
"""Exponential function (e^x)."""
52
53
def floor(self, value):
54
"""Floor (round down to integer)."""
55
56
def log(self, value):
57
"""Natural logarithm."""
58
59
def max(self, *values):
60
"""Maximum of values."""
61
62
def min(self, *values):
63
"""Minimum of values."""
64
65
def pow(self, base, exponent):
66
"""Power function (base^exponent)."""
67
68
def random(self):
69
"""Random number [0, 1)."""
70
71
def round(self, value):
72
"""Round to nearest integer."""
73
74
def sin(self, value):
75
"""Sine."""
76
77
def sqrt(self, value):
78
"""Square root."""
79
80
def tan(self, value):
81
"""Tangent."""
82
83
# String functions
84
def indexof(self, string, substring):
85
"""Index of substring in string."""
86
87
def join(self, array, separator=None):
88
"""Join array elements into string."""
89
90
def lastindexof(self, string, substring):
91
"""Last index of substring in string."""
92
93
def length(self, string_or_array):
94
"""Length of string or array."""
95
96
def lower(self, string):
97
"""Convert to lowercase."""
98
99
def pad(self, string, length, character=None, align=None):
100
"""Pad string to specified length."""
101
102
def regexp(self, string, pattern, flags=None):
103
"""Test string against regular expression."""
104
105
def replace(self, string, pattern, replacement):
106
"""Replace substring or pattern."""
107
108
def slice(self, string_or_array, start, end=None):
109
"""Extract substring or subarray."""
110
111
def split(self, string, separator, limit=None):
112
"""Split string into array."""
113
114
def substring(self, string, start, end=None):
115
"""Extract substring."""
116
117
def trim(self, string):
118
"""Remove leading/trailing whitespace."""
119
120
def truncate(self, string, length, align=None, ellipsis=None):
121
"""Truncate string to specified length."""
122
123
def upper(self, string):
124
"""Convert to uppercase."""
125
126
# Array functions
127
def extent(self, array):
128
"""Min and max values of array."""
129
130
def indexof_array(self, array, value):
131
"""Index of value in array."""
132
133
def lastindexof_array(self, array, value):
134
"""Last index of value in array."""
135
136
def peek(self, array):
137
"""Last element of array."""
138
139
def reverse(self, array):
140
"""Reverse array."""
141
142
def sort(self, array):
143
"""Sort array."""
144
145
# Date/time functions
146
def now(self):
147
"""Current timestamp."""
148
149
def datetime(self, year, month=None, day=None, hour=None, minute=None, second=None, millisecond=None):
150
"""Create date from components."""
151
152
def date(self, datetime):
153
"""Extract date part."""
154
155
def day(self, datetime):
156
"""Day of month (1-31)."""
157
158
def dayofyear(self, datetime):
159
"""Day of year (1-366)."""
160
161
def year(self, datetime):
162
"""Year."""
163
164
def quarter(self, datetime):
165
"""Quarter (0-3)."""
166
167
def month(self, datetime):
168
"""Month (0-11)."""
169
170
def hours(self, datetime):
171
"""Hours (0-23)."""
172
173
def minutes(self, datetime):
174
"""Minutes (0-59)."""
175
176
def seconds(self, datetime):
177
"""Seconds (0-59)."""
178
179
def milliseconds(self, datetime):
180
"""Milliseconds (0-999)."""
181
182
def time(self, datetime):
183
"""Time in milliseconds since epoch."""
184
185
def timezoneoffset(self, datetime):
186
"""Timezone offset in minutes."""
187
188
def utc(self, year, month=None, day=None, hour=None, minute=None, second=None, millisecond=None):
189
"""Create UTC date."""
190
191
# Logical functions
192
def if_(self, test, then, else_=None):
193
"""Conditional expression."""
194
195
def isArray(self, value):
196
"""Test if value is array."""
197
198
def isBoolean(self, value):
199
"""Test if value is boolean."""
200
201
def isDate(self, value):
202
"""Test if value is date."""
203
204
def isDefined(self, value):
205
"""Test if value is defined."""
206
207
def isFinite(self, value):
208
"""Test if value is finite number."""
209
210
def isNaN(self, value):
211
"""Test if value is NaN."""
212
213
def isNumber(self, value):
214
"""Test if value is number."""
215
216
def isObject(self, value):
217
"""Test if value is object."""
218
219
def isRegExp(self, value):
220
"""Test if value is regular expression."""
221
222
def isString(self, value):
223
"""Test if value is string."""
224
225
def isValid(self, value):
226
"""Test if value is valid (not null, undefined, or NaN)."""
227
228
def inrange(self, value, min_val, max_val):
229
"""Test if value is in range [min, max]."""
230
231
# Format functions
232
def format(self, value, specifier):
233
"""Format number with d3-format specifier."""
234
235
def timeFormat(self, datetime, specifier):
236
"""Format date with d3-time-format specifier."""
237
238
def timeParse(self, string, specifier):
239
"""Parse date string with d3-time-format specifier."""
240
241
def utcFormat(self, datetime, specifier):
242
"""Format UTC date."""
243
244
def utcParse(self, string, specifier):
245
"""Parse UTC date string."""
246
247
# Type conversion functions
248
def toBoolean(self, value):
249
"""Convert to boolean."""
250
251
def toDate(self, value):
252
"""Convert to date."""
253
254
def toNumber(self, value):
255
"""Convert to number."""
256
257
def toString(self, value):
258
"""Convert to string."""
259
260
# Statistical functions
261
def sampleNormal(self, mu=None, sigma=None):
262
"""Sample from normal distribution."""
263
264
def cumulativeNormal(self, value, mu=None, sigma=None):
265
"""Cumulative normal distribution."""
266
267
def densityNormal(self, value, mu=None, sigma=None):
268
"""Normal probability density."""
269
270
def quantileNormal(self, p, mu=None, sigma=None):
271
"""Normal quantile function."""
272
273
def sampleLogNormal(self, mu=None, sigma=None):
274
"""Sample from log-normal distribution."""
275
276
def cumulativeLogNormal(self, value, mu=None, sigma=None):
277
"""Cumulative log-normal distribution."""
278
279
def densityLogNormal(self, value, mu=None, sigma=None):
280
"""Log-normal probability density."""
281
282
def quantileLogNormal(self, p, mu=None, sigma=None):
283
"""Log-normal quantile function."""
284
285
def sampleUniform(self, min_val=None, max_val=None):
286
"""Sample from uniform distribution."""
287
288
def cumulativeUniform(self, value, min_val=None, max_val=None):
289
"""Cumulative uniform distribution."""
290
291
def densityUniform(self, value, min_val=None, max_val=None):
292
"""Uniform probability density."""
293
294
def quantileUniform(self, p, min_val=None, max_val=None):
295
"""Uniform quantile function."""
296
297
# Color functions
298
def rgb(self, r, g, b):
299
"""Create RGB color."""
300
301
def hsl(self, h, s, l):
302
"""Create HSL color."""
303
304
def lab(self, l, a, b):
305
"""Create Lab color."""
306
307
def hcl(self, h, c, l):
308
"""Create HCL color."""
309
310
def luminance(self, color):
311
"""Calculate color luminance."""
312
313
def contrast(self, color1, color2):
314
"""Calculate color contrast ratio."""
315
316
# Geographic functions
317
def geoArea(self, feature):
318
"""Geographic area of feature."""
319
320
def geoBounds(self, feature):
321
"""Geographic bounds of feature."""
322
323
def geoCentroid(self, feature):
324
"""Geographic centroid of feature."""
325
326
def geoContains(self, feature, point):
327
"""Test if feature contains point."""
328
329
# Global expression instance
330
expr = ExpressionAPI()
331
```
332
333
### Datum Reference
334
335
Object for referencing fields in the current data record within expressions.
336
337
```python { .api }
338
class DatumExpression:
339
"""Reference to current data record fields."""
340
341
def __getattr__(self, field_name):
342
"""Access field by name: datum.fieldname"""
343
344
def __getitem__(self, field_name):
345
"""Access field by key: datum['field name']"""
346
347
# Global datum instance
348
datum = DatumExpression()
349
```
350
351
### Conditional Functions
352
353
Functions for creating conditional logic and branching expressions.
354
355
```python { .api }
356
def condition(predicate, if_true, if_false=None):
357
"""
358
Create conditional encoding.
359
360
Parameters:
361
- predicate: Test condition (parameter, selection, or expression)
362
- if_true: Value/encoding when condition is true
363
- if_false: Value/encoding when condition is false
364
365
Returns:
366
dict: Conditional specification
367
"""
368
369
def when(predicate):
370
"""
371
Start conditional chain.
372
373
Parameters:
374
- predicate: Test condition
375
376
Returns:
377
ChainedWhen: Object for method chaining
378
"""
379
380
class ChainedWhen:
381
def then(self, value):
382
"""Value when condition is true."""
383
384
class Then:
385
def when(self, predicate):
386
"""Additional condition."""
387
388
def otherwise(self, value):
389
"""Final fallback value."""
390
```
391
392
## Usage Examples
393
394
### Mathematical Expressions
395
396
```python
397
import altair as alt
398
399
# Basic mathematical operations
400
chart = alt.Chart(data).mark_circle().encode(
401
x='x:Q',
402
y='y:Q',
403
size=alt.expr('sqrt(datum.value) * 10')
404
)
405
406
# Complex calculations
407
chart = alt.Chart(data).mark_point().encode(
408
x='x:Q',
409
y='y:Q'
410
).transform_calculate(
411
distance=alt.expr('sqrt(pow(datum.x - 50, 2) + pow(datum.y - 50, 2))'),
412
angle=alt.expr('atan2(datum.y - 50, datum.x - 50) * 180 / PI')
413
)
414
```
415
416
### String Manipulations
417
418
```python
419
# String processing
420
chart = alt.Chart(data).mark_text().encode(
421
x='x:Q',
422
y='y:Q',
423
text=alt.expr('upper(slice(datum.name, 0, 3))')
424
).transform_calculate(
425
short_name=alt.expr('length(datum.name) > 10 ? truncate(datum.name, 10) : datum.name'),
426
initials=alt.expr('split(datum.name, " ")[0][0] + split(datum.name, " ")[1][0]')
427
)
428
```
429
430
### Date/Time Operations
431
432
```python
433
# Date calculations
434
chart = alt.Chart(data).mark_line().encode(
435
x='date:T',
436
y='value:Q'
437
).transform_calculate(
438
year=alt.expr('year(datum.date)'),
439
quarter=alt.expr('quarter(datum.date)'),
440
day_of_year=alt.expr('dayofyear(datum.date)'),
441
is_weekend=alt.expr('day(datum.date) == 0 || day(datum.date) == 6')
442
)
443
```
444
445
### Conditional Logic
446
447
```python
448
# Simple conditional
449
chart = alt.Chart(data).mark_circle().encode(
450
x='x:Q',
451
y='y:Q',
452
color=alt.expr('datum.value > 50 ? "red" : "blue"')
453
)
454
455
# Complex conditional chain
456
chart = alt.Chart(data).mark_circle().encode(
457
x='x:Q',
458
y='y:Q',
459
color=alt.when(
460
alt.datum.value > 80
461
).then(
462
alt.value('red')
463
).when(
464
alt.datum.value > 60
465
).then(
466
alt.value('orange')
467
).when(
468
alt.datum.value > 40
469
).then(
470
alt.value('yellow')
471
).otherwise(
472
alt.value('blue')
473
)
474
)
475
```
476
477
### Statistical Expressions
478
479
```python
480
# Statistical calculations
481
chart = alt.Chart(data).mark_circle().encode(
482
x='x:Q',
483
y='y:Q',
484
size=alt.expr('densityNormal(datum.value, 50, 15) * 1000')
485
).transform_calculate(
486
z_score=alt.expr('(datum.value - 50) / 15'),
487
percentile=alt.expr('cumulativeNormal(datum.value, 50, 15)')
488
)
489
```
490
491
### Color Expressions
492
493
```python
494
# Color calculations
495
chart = alt.Chart(data).mark_circle().encode(
496
x='x:Q',
497
y='y:Q',
498
color=alt.expr('hsl(datum.value * 360 / 100, 0.7, 0.5)'),
499
stroke=alt.expr('contrast("white", hsl(datum.value * 360 / 100, 0.7, 0.5)) > 4.5 ? "black" : "white"')
500
)
501
```
502
503
### Validation and Type Checking
504
505
```python
506
# Data validation expressions
507
chart = alt.Chart(data).mark_circle().encode(
508
x='x:Q',
509
y='y:Q',
510
opacity=alt.expr('isValid(datum.value) && isFinite(datum.value) ? 1.0 : 0.3')
511
).transform_filter(
512
alt.expr('isDefined(datum.x) && isDefined(datum.y)')
513
)
514
```
515
516
### Parameter Integration
517
518
```python
519
# Using parameters in expressions
520
threshold = alt.param(value=50)
521
multiplier = alt.param(value=2)
522
523
chart = alt.Chart(data).add_params(
524
threshold, multiplier
525
).mark_circle().encode(
526
x='x:Q',
527
y='y:Q',
528
size=alt.expr(f'max(10, min(500, datum.value * {multiplier}))'),
529
color=alt.expr(f'datum.value > {threshold} ? "red" : "blue"')
530
)
531
```
532
533
## Types
534
535
```python { .api }
536
from typing import Union, Any, Dict
537
538
# Expression types
539
ExpressionString = str
540
ExpressionRef = Dict[str, Any]
541
Expression = Union[ExpressionString, ExpressionRef]
542
543
# Conditional types
544
ConditionalPredicate = Union[str, Dict[str, Any]]
545
ConditionalValue = Union[Any, Dict[str, Any]]
546
547
# Datum field reference
548
DatumRef = Union[str, Dict[str, Any]]
549
550
# Function result types
551
BooleanExpression = Expression
552
NumberExpression = Expression
553
StringExpression = Expression
554
DateExpression = Expression
555
ColorExpression = Expression
556
ArrayExpression = Expression
557
```