The encoding property of a steam defines how to map data variables to auditory variables.
While Erie uses many Vega-Lite conventions, each encoding channel may have different properties and usage patterns.
This is because data sonification is defined on a sound space.
For example, a time channel plays two roles: an encoding channel and a sonification canvas at the same time.
This documentation describes overall structure and common properties of encoding channels.
Supported encoding channels
| Channel | Description |
|---|---|
time |
(Required) The time when a tone is played. |
time2 |
The time when a tone is finished, with a data field sharing the same scale with that of the time channel. |
duration |
The length of a tone being played, with a data field not sharing the same scale with that of the time channel. |
tapSpeed |
The number of tapping sounds evenly distributed over the specified duration of time. |
tapCount |
The number of tapping sounds of the same specified length. |
pitch |
The pitch frequency of a tone. For a synth instrument, this changes the carrier’s frequency. |
detune |
(Only for noise tones) The amount of detuning a tone. |
loudness |
The volume or loudness of a tone. For a synth instrument, this changes the carrier’s frequency. It is controled by gain. |
pan |
The stereo panning (left and right spatial positioing) of a tone. |
postReverb |
The length of the reverb sound played after a tone. |
speechBefore |
The speech text played before playing a tone. |
speechAfter |
The speech text played after playing a tone. |
repeat |
Repeating streams of the same structure (i.e., encoding and tone design) over one or more nominal/ordinal variables. |
modulation |
Modultaiotn index for a synth tone (the higher the index, the more warping the sound for FM; the larger the sound for AM). |
harmonicity |
Harmony between AM carrier and modulator (non-linear channel). |
For more details about the modulation, please refer to frequency modulation and amplitude modulation (or harmonicity).
Common encoding channel properties
| Property | Type | Description |
|---|---|---|
field |
String or Array[String] |
(Mostly required) A field to encode in a channel. Only the repeat channel can use an array expression. |
type |
String |
(Required, but auto-detected) The data type of a field. Allowed values: nominal, ordinal, quantitative, and temporal. |
aggregate |
String |
(Optional) The data aggregation method for the channel. For count-based aggregate methods, field is ignored. See aggregate documentation for details. |
bin |
Boolean or Object |
(Optional) For an autoamted binning, set as true. For more detailed bin settings, see below. |
condition |
Object |
Conditional value assignment. |
value |
any |
(Optional) A static sound for a channel. |
scale |
Object |
(Optional, but highly suggested) The detail of scaling. See below for details. |
ramp |
true|false|'abrupt'|'linear'|'exponential' |
(Optional, for continuous tones) Whether/how to ramp audio properties. true is 'linear' and false is 'abrupt'. |
speech |
Boolean |
(Optional, for repeat channel only, default: true) Whether to announce the name of value for the repeat channel. |
tick |
object|string |
(Optional, default: null; only for time channel) An audio axis. If it is String, then it should be a registered tick’s name. |
format |
String |
(Optional) The format of numerical values for a scale description or read out. See this D3 documentations (number format, time format) for the expression. |
formatType |
'number'|'datetime' |
(Optional, default: 'datetime') The type of formatting. |
Inline aggregate
Possible aggregate values
count: the count of elementsvalid: the number of valid items in a variabledistinct: the number of distinct items in a variablemean/average: the mean of a variablemode: the mode of a variablemedian: the median of a variablequantile: thepquantile value of a variablestdev: the standard deviation of a variablestdevp: the population standard deviation of a variablevariance: the variance of a variablevariancep: the population variance of a variablesum: the sum of a variableproduct: the product (multiplication) of a variablemax: the maximum value of a variablemin: the min value of a variable
Note: double-field aggregates (corr, covariance, and covariancep) are not available for inline aggregate.
See the transform documentation for further details.
Bin
The simplest way to use in-channel binning is setting the bin property as true.
To provide more details, one can use a bin Object with details.
| Property | Type | Description |
|---|---|---|
nice |
Boolean |
(Optional) Whether to use ‘nicely’ separated bins (default: true). |
maxbins |
integer |
(Optional) The maximum number of bins (default: 10). |
step |
Number |
(Optional) The exact size acrass all bins. |
exact |
Array[Number] |
(Optional) The eaxct bin sizes for each bin. For example, if it is [0, 10, 15, 20], then the resulting bins are [0, 10), [10, 15), and [15, 20). |
Scale
The scale propoerty describes further details about the mapping between the specified data variable and the targeted auditory channel.
A scale object can have the following properties.
Each encoding channel may have different scale properties, so refer to relevant documentations for details.
| Property | Type | Description |
|---|---|---|
domain |
Array[Any] |
(Optional) An array of domain intervals. domain must have the same length with range. The data type should be in accordance with the field’s type. |
range |
Array[Any] |
(Optional) An array of range intervals. range must have the same length with domain. The data type should be in accordance with the targeted channel’s type (e.g., Number for pitch, String for timbre). |
polarity |
'positive'|'negative' |
(Optional) The mapping direction. If it is 'positive', then a higher data value maps to a higher auditory value (e.g., more loud, higher pitch, right pan). If it is 'negative', then a higher data value maps to a lower auditory value (e.g., less loud, lower pitch, left pan). |
maxDistinct |
Boolean |
(Optional, default: true) When range is not specified and maxDistinct is true, then the range becomes the maximum-possible range of that channel (e.g., from the lowest pitch to the highest pitch, from the pan of -1—leftmost to pan of 1–rightmost). |
times |
Number |
(Optional) A direct scale factor. When provided, for a value v, the auditory value is v * times. If the max(value) * times or min(value) * times goes beyond the possible auditory value for each channel, then the specified times is adjusted. |
zero |
Boolean |
(Optional, default: false) Whether to include the zero value in the scale for a quantitative encoding. The default value is false, so as to maximalize the discriminability of auditory values because some audio values have limited possible range. |
description |
'nonskip'|'skip',null, ordescriptionMarkup |
(Optional, default: 'nonskip') Specifying the description of a scale. If it is 'skip' or null, then description is not played. If provided as a string that is not 'skip' or 'nonskip', then the provided string or markked-up expression is played instead. See below for the description markup. |
title |
String |
(Optional, default is the field’s name) If provided, it replaces the field name in the default description. |
length |
Number (unit: second) |
(Optional, only for the time channel) The entire length of a sonfication stream with an absolute timing (a shortcut to range). |
band |
Number (unit: second) |
(Optional) For the time channel, the length of each tone. For the tapSpeed channel, the length of time duration. For the tapCount channel, the length of each tapping sound. |
timing |
'relative'|'absolute'|'simultaneous' |
(Optional) The timing (when it starts) of each tone (default: 'absolute'). |
API usage
JSON
{
...
"encoding" : {
"[channel]": {
"field": "FieldName",
"type": "DataType",
"aggregate": "AggregateMethod", // only for a `quantitative` channel
"bin": {
"nice": true // or false,
"maxbins": 10,
"step": 5, // Number
"exact": false // or true
}, // or true or false
"scale": {
"domain": [ ... ],
"range": [ ... ],
"polarity": "positive" // or "negative",
"maxDistinct": true // or false,
"times": ..., // Number,
"zero": false // or true,
"description": "nonskip" // or "skip",
// only for `time` channel
"length": ..., // Seconds,
"timing": "absolute", // or "relative"
// only for `time`, `tapSpeed`, and `tapCount` channels
"band": ..., // Seconds,
},
"value": ...,
"condition": [
{"test": [ value1, value2, ... ], "value": ... }, // as array
{"test": {"not": [ value1, value2, ... ]}, "value": ... }, // "not"
{"test": "d.field > 0", "value": ... } // conditional
],
"speech": true // or false,
"format": '.2', // (rounding at the second decimal point), no default value
"formatType": "number" // default value
}
}
...
}JavaScript
let stream = new Erie.Stream();
// method 1 (more reusable)
let channel = new Erie.{ChannelName}();
channel.field("Origin", "nominal");
// or let channel = new Erie.Channel("Origin", "nominal");
let maxbins = 10, nice = true, step;
channel.bin(maxbins, step, nice);
// channel.bin(true);
// channel.bin(false);
// let exact = [0, 10, 15, 20];
// channel.bin(exact);
channel.aggregate("mean");
channel.scale("timing", "relative"); // key & value
channel.scale("domain", [0, 10]);
channel.scale("timing", "relative");
// static
channel.value(...);
channel.condition.add([ value1, value2, ... ], ...);
channel.condition.add({"not": [ value1, value2, ... ]}, ...);
channel.condition.add("d.field > 0", ...);
// format
channel.format('.2', 'number');
channel.format('.2');
channel.formatType('number');
stream.encoding.{channelName}.set(channel); // provided for reusability;
// method 2 (more direct)
stream.encoding.{channelName}.field("Origin", "nominal");
stream.encoding.{channelName}.scale("timing", "relative");
// method 1 + 2
stream.encoding.{channelName} = new Erie.Channel("Origin", "nominal");
stream.encoding.{channelName}.scale("timing", "relative");Scale description markup
For the description property of a scale, you can provide a marked-up expression
to be read out before playing the sonification or be separately played.
How to mark up a description text
There are three four types of elements in a description text.
- Plain text → Just give that text
- A discrete audio legend →
<sound value="X" duration="D">
X: a “data” value or reserved keywoard to be mapped using the scale.D: the duration of this sound (default: 0.5 seconds or 1 beat). Ifconfig.timeUnitisbeatthen the unit is beat counts, and when it issecond, then the unit is seconds.
- A continuous audio legend →
<sound v0="X1" v1="X2" duration="D">
vn:Xn(n=0,1,2, …): breakpoints, the “data” values or reserved keywoards to be mapped using the scale! Provide as many point as you need. They will be timed relatively.D: the duration of this sound (default: 0.5 seconds or 1 beat multipled by the number of breakpoints). Ifconfig.timeUnitisbeatthen the unit is beat counts, and when it issecond, then the unit is seconds.
- A datum list →
<list item="A" first="F" last="L" join="S" and="N">
A: an array/list of items or a keyword to be listed. If not provided, all the domain values will be sounded. They should be comma separated. For example,<list item="apple,pear, juice" ... >(O) but<list item="[apple,pear, 'juice']" ... >(may work, but may cause error). Spaces before and after each item is trimmed.F: the firstFitems to read outL: the lastFitems to read out
Note: <list item="apple,pear,juice,melon,grape" first="2" last="2" join=", "> will result in ‘apple, pear, melon, grape’.
See the examples for how to use.
S: a string between each consecutive pair of items. This considers a space (for iternationalization). The default is,N: a string between the last two consecutive items. This considers a space (for iternationalization). There is no default value provided.
Note: For the time channel, while the rest can be “compiled,” it won’t really play the audio.
Reserved keywords
To use in a plan text, use them with < and > (e.g., <domain.min>)
domain.min: the minimum domain valuedomain.max: the maximum domain valuedomain.length: the number of domain values specifieddomain[n]: then-th domain valuedomain: the entire domainchannel: the channel namefield: the channel’s fieldaggregate: the channel’s aggregate methodtitle: the channel’s display name (if not provided, it usesfield).
Examples
Case 1: Consider a pitch channel that maps [0, 50] (data, field: 'weight') to [300, 500] (Hz).
The description text is
The <channel> channel represents <title>. The minimum value <domain.min> is <sound value="domain.min"> and <domain.max> is <sound value="domain.max">.
This is compiled to The pitch channel represents weight. The minimum value 0 is (sound with pitch 300) and 50 is (sound with pitch 500).
Case 2: Consider a pan channel that maps [100, 300] (data, field: 'height') to [-1, 1].
The description text is
The <channel> channel is for <title>. The minimum value of <domain.min> and the maximum value of <domain.max> are mapped to <sound v0="domain.min" v1="domain.max" duration="0.3">.
This is compiled to The pan channel is for height. The minimum value 100 and the maximum value of 300 are mapped to (pan-sweep from -1 to 1 for 0.6 seconds).
Case 3: Consider a time channel that maps [apple,pear,kiwi,melon,grape,mango,orange] (data, field: 'type') to relative timing.
The description text is
The <field> has <domain.unique> itmes. They are played from <list first="2" join=" and "> to <list last="2" join=" and ">.
This is compiled to The type has 7 items. They are played from apple and pear to mango and orange.
How to play a description
- Play it before a sonification
Quick answer: Nothing to be done.
- Play it separately
In config, first set skipScaleSpeech as true.
JSON
{
...
"config": {
"skipScaleSpeech": true
}
}JavaScript
let spec = new Erie.Stream();
...
spec.config('skipScaleSpeec', true);After you compile the sonification spec, run the playDescription method.
let spec = new Erie.Stream();
...
let audio;
Erie.compileAuidoGraph(spec)
.then((audio_graph) => {
let audio = audio_graph;
...
audio.playScaleDescription();
audio.playScaleDescription('time'); // play only for the time channel
audio.stopScaleDescription(); // to stop whatever being played
});
...If scale.description is set to 'skip' or null, then it is also not played with the playScaleDescription method.
Scale consistency for multi-stream sonifications
It is possible (and default) to use a consistent scales unless otherwise specified.
For example, suppose a sequence consisting of one single stream and one three-stream overlay, so there are four streams defined.
Let’s name them ‘Stream-A’, ‘Overlay-1’, ‘Overlay-2’, and ‘Overlay-3’, respectively.
‘Overlay-1’, ‘Overlay-2’, and ‘Overlay-3’ comprise ‘Stream-B’
The specification will look like:
{"sequence": [ {... Stream-A ...}, { "overlay": [Overlay-1, Overaly-2, Overlay-3]}]}.
Then, assume these streams use a pitch channel.
Case 1: Global
‘Stream-A’ defines a pitch channel, while the others do not.
Then, ‘Overlay-1’, ‘Overlay-2’, and ‘Overlay-3’ use the same pitch scale as defined in ‘Stream-A’
as long as they rely on the same dataset and field, and are of the same encoding type (e.g., nominal, quantitative).
If the overlaid streams use a different dataset or of a different encoding type,
then the scale will be different.
Case 2: Nested
‘Stream-A’ and ‘Overlay-1’ define a pitch channel, while the others do not.
Then, ‘Overlay-2’, and ‘Overlay-3’ use the same pitch scale as defined in ‘Overlay-1’
as long as they rely on the same dataset and field, and are of the same encoding type (e.g., nominal, quantitative).
If ‘Overlay-2’, and ‘Overlay-3’ use a different dataset, field, or encoding type,
then the scale will be different.
Case 3: I just need individually defined scales
If it is necessary to use individually defined scales,
then set overlayScaleConsistency (for overlay) or sequenceScaleConsistency (for sequence) to false,
in the closest config object.
To make inconsistent scales between ‘Stream-A’ and ‘Stream-B’,
then set sequenceScaleConsistency as false in the top-level sequence.
To make inconsistent scales among ‘Overlay-1’, ‘Overlay-2’, and ‘Overlay-3’,
then set overlayScaleConsistency as false in the overlay object.
When two scale definitions conflicts, a property defined earliest is applied.
This can also done by channels, for example { "sequenceScaleConsistency": { "pitch" : false } }.
Erie Documentation (Future)