5.1 Class Object
5.1.1 Object properties
5.1.2 Object methods
+ (integer$)length(void)
Returns the size (e.g., length) of the receiving object. This is equivalent to the length() (or size()) function; in other words, for any object x, the return value of the function call length(x) equals the return value of the class method call x.length(). This method is provided solely for syntactic convenience. Note that +length() is a synonym for +size().
+ (void)methodSignature([Ns$ methodName = NULL])
Prints the method signature for the method specified by methodName, or for all methods supported by the receiving object if methodName is NULL (the default).
+ (void)propertySignature([Ns$ propertyName = NULL])
Prints the property signature for the property specified by propertyName, or for all properties supported by the receiving object if propertyName is NULL (the default).
+ (integer$)size(void)
Returns the size of the receiving object. This is equivalent to the size() (or length()) function; in other words, for any object x, the return value of the function call size(x) equals the return value of the class method call x.size(). This method is provided solely for syntactic convenience. Note that +length() is a synonym for +size().
– (void)str(void)
Prints the internal property structure of the receiving object; in particular, the element type of the object is printed, followed, on successive lines, by all of the properties supported by the object, their types, and a sample of their values.
– (string$)stringRepresentation(void)
Returns a singleton string value that represents the receiving object. By default, this is simply the name of the class of the receiving object; however, many subclasses of Object provide a different string representation. The value returned by stringRepresentation() is the same string that would be printed by print() for the object, so stringRepresentation() allows the same representation to be used in other contexts such as paste() and cat().
5.2 Class DataFrame
(object<DataFrame>$)DataFrame(...)
The DataFrame constructor can be called in the same ways as the constructor for Dictionary (its superclass): with no parameters to make an empty DataFrame, with key-value pairs, with a singleton Dictionary (or a subclass of Dictionary, like DataFrame) to make a copy, or with a string in JSON format. See the Dictionary class for further documentation. However, note that DataFrame can only use string keys; integer keys are not allowed.
5.2.1 DataFrame properties
colNames => (string)
A vector containing all of the string column names in the DataFrame, in order. This property is currently an alias for the Dictionary property allKeys.
dim => (integer)
A two-element vector containing the dimensions of the DataFrame. The 0th element is the number of rows (as provided by nrow), and the 1st element is the number of columns (as provided by ncol).
ncol => (integer$)
The number of columns in the DataFrame; this will be equal to the length of colNames.
nrow => (integer$)
The number of rows in the DataFrame (i.e., the number of elements in a column). This will be the same for every column, by definition.
5.2.2 DataFrame methods
– (*)asMatrix(void)
Returns a matrix representation of the DataFrame. The matrix will have the same type as the elements of the DataFrame; if the DataFrame contains more than one type of element, an error will be raised. The order of the columns of the DataFrame will be preserved. This method is useful, for example, if you wish to read in a text file as a matrix; you can use readCSV() to read the file as a DataFrame, and then convert it to a matrix with asMatrix().
– (void)cbind(object<Dictionary> source, ...)
Adds all of the columns contained by source (which must be a Dictionary or a subclass of Dictionary such as DataFrame) to the receiver. This method makes the target DataFrame wider, by adding new columns. If source contains a column name that is already defined in the target, an error will result. As always for DataFrame, the columns of the resulting DataFrame must all be the same length.
The source parameter may be a non-singleton vector containing multiple Dictionary objects, and additional Dictionary vectors may be supplied (thus the ellipsis in the signature). Each Dictionary supplied will be added to the target, in the order supplied.
This method is similar to the Dictionary method addKeysAndValuesFrom(), which may be used instead if replacement of duplicate columns is desired.
– (void)rbind(object<Dictionary> source, ...)
Appends all of the columns contained by source (which must be a Dictionary or a subclass of Dictionary such as DataFrame) to the receiver. This method makes the DataFrame taller, by adding new rows. If the source and target do not contain the same column names in the same order, an error will result. As always for DataFrame, the columns of the resulting DataFrame must all be the same length.
The source parameter may be a non-singleton vector containing multiple Dictionary objects, and additional Dictionary vectors may be supplied (thus the ellipsis in the signature). Each Dictionary supplied will be appended to the target, in the order supplied.
This method is similar to the Dictionary method appendKeysAndValuesFrom(), which may be used instead if one wishes the append to work even when the columns are in different orders, or other such situations.
– (*)subset([Nli rows = NULL], [Nlis cols = NULL])
Returns the elements in the selected rows and columns of the target DataFrame. The selection logic is based upon that for subsetRows() and subsetColumns(), respectively; in short, rows may be selected by integer indices or by a logical vector, and columns may be selected by integer indices, by a logical vector, or by a string vector of column names. In addition, however, NULL may be passed for either rows or cols to select all of the rows or all of the columns, respectively; this is the default for both parameters. If you want entire rows (rather than selecting particular columns), pass NULL for cols; if you want entire columns (rather than selecting particular rows), pass NULL for rows.
The first step performed by subset() is to produce a DataFrame that contains the selected rows and columns. If that DataFrame contains more than one column, it is simply returned, and the behavior of subset() is identical to calling subsetRows() and subsetColumns() in sequence (in either order). If, however, the resulting DataFrame contains only a single column, then subset() will return a vector containing the elements in that column – unlike the behavior of subsetRows() and subsetColumns(), which always return a DataFrame. This method is therefore a convenient way to get a single value, or multiple values from the same column, from a DataFrame. (Note that the Dictionary method getValue() can also be used to get all of the values from a given DataFrame column.)
– (object<DataFrame>$)subsetColumns(lis index)
Returns a new DataFrame containing values for the selected columns of the target DataFrame. The selection logic described below is similar to how the subset operator [] in Eidos works, selecting the columns of the target DataFrame.
The index parameter may be either integer, logical, or string; we will discuss the integer case first. If index is a singleton integer, the returned DataFrame will contain the index’th column of the target (counting from the left, from 0). If index is a non-singleton integer vector, the returned DataFrame will contains all of the selected columns, in the order that they are selected by index. If any index value is out of range for the target DataFrame (such that the DataFrame does not have an index’th column), an error will result. If the same column is specified more than once, unique column names will be automatically generated for the additional copies of the column.
If index is a string vector, the returned DataFrame will contain copies of the columns in the target named by index. As with an integer vector, it is an error if a given column does not exist in the target; and unique column names will be generated for additional copies of a column.
Finally, if index is a logical vector, the length of index must be equal to the number of columns in the target. In this case, the T values in index select the columns which will be included in the returned DataFrame. The columns in the returned DataFrame will be in the same order as in the target.
– (object<DataFrame>$)subsetRows(li index, [logical$ drop = F])
Returns a new DataFrame containing values for selected rows of the target DataFrame. The selection logic described below works exactly as the subset operator [] does in Eidos, selecting the rows of the target DataFrame.
The index parameter may be either integer or logical; we will discuss the integer case first. If index is a singleton integer, the returned DataFrame will contain the index’th element of the value of each key of the target, under the same keys; this is a single row of the target DataFrame. If index is a non-singleton integer vector, the returned DataFrame will contain the values for all of the selected rows, in the order that they are selected by index. If any index value in index is out of range for the target DataFrame (such that that DataFrame does not have an index’th row), an error will result.
If index is logical, the length of index must be equal to the number of rows in the target. In this case, the T values in index select the rows which will be included in the returned DataFrame. The values of each column in the returned DataFrame will be in the same order as in the target.
If the values of index are such that no value for a given key is selected, the drop parameter controls the resulting behavior. If drop is F (the default), the key will be included in the returned dictionary with a zero-length value of matching type, such as integer(0) or string(0). If drop is T, the key will be omitted from the returned dictionary.
5.3 Class Dictionary
(object<Dictionary>$)Dictionary(...)
Creates a new Dictionary object. Called without arguments, as Dictionary(), this creates a new empty Dictionary.
Alternatively, key-value pairs can be passed to set up the initial state of the new Dictionary. These are set, sequentially, on the new Dictionary, just as setValue() would do. For example, calling Dictionary("a", 0:3, "b", c("foo", "bar")) is equivalent to calling Dictionary() and then calling setValue("a", 0:3) and then setValue("b", c("foo", "bar")) on it; it is just a shorthand for convenience. Keys may be of type string or integer, but must all be of the same type; Dictionary supports using either string or integer keys, but they cannot be mixed in a single Dictionary object.
Another alternative is to call Dictionary() with a singleton Dictionary as its only argument; this creates a new Dictionary that is a copy of the Dictionary passed, containing the same keys and values. This is equivalent to creating a new empty Dictionary and then calling addKeysAndValuesFrom() to copy key-value pairs over; it is just a shorthand for convenience.
A final alternative is to call Dictionary() with a string vector as its only argument; this creates a new Dictionary from the string, assuming that it is a data archive in JSON format. If the string value is not a singleton, its elements will be joined together by newlines to make a singleton string value; this allows the result from readFile() to be passed directly to Dictionary() even for a multiline (prettyprinted) JSON file. Note that a JSON string can be generated from the serialize() method of Dictionary; together with this way of creating a Dictionary, this provides the ability to persist arbitrary information to a string (perhaps a file on disk) and back again. The recreated Dictionary should be identical to the original, except that zero length vectors such as integer(0), float(0), logical(0), and string(0) will all be serialized as "[]" and recreated as integer(0) since JSON does not provide a way to specify the type of a zero-length array.
5.3.1 Dictionary properties
allKeys => (is)
A vector containing all of the string or integer keys that have been assigned values using setValue(), in sorted (ascending alphabetic or numeric) order.
5.3.2 Dictionary methods
– (void)addKeysAndValuesFrom(object<Dictionary>$ source)
Adds all of the key-value pairs contained by source (which must be a Dictionary or a subclass of Dictionary) to the receiver. If the target already contains a key that is defined in source, the target’s value for that key will be replaced by the value in source (contrast this with appendKeysAndValuesFrom()).
– (void)appendKeysAndValuesFrom(object<Dictionary> source)
Appends all of the key-value pairs contained by source (which must be a Dictionary or a subclass of Dictionary) to the receiver. If the target already contains a key that is defined in source, the value from source will be appended to the target’s existing value, which must be of the same type (contrast this with addKeysAndValuesFrom()); if the target does not already contain a key that is defined in source, that key-value pair will simply be added to the target.
In the current implementation, it is an error for either of the values involved in an append to be a matrix or array; values in these Dictionary objects should be simple vectors. This limitation preserves the future option to expand this method’s functionality to do smart things with matrices and arrays.
– (void)clearKeysAndValues(void)
Removes all key-value pairs from the receiver.
– (integer)compactIndices([logical$ preserveOrder = F])
Compacts the receiver, which must use integer keys. After this operation, the receiver will contain only values that have a length greater than zero (discarding all key–value pairs for which the value is a zero-length vector). In addition, the keys used will be compacted down to begin at 0 and count upward sequentially. If preserveOrder is F (the default), the keys may end up in a different numerical order; this allows the compaction to be performed more efficiently. If preserveOrder is T, on the other hand, the numerical order of the keys will be preserved. The returned integer vector contains the original keys that were kept across the compaction operation, in the order in which they were used in the compaction; keys that were not kept (because their value was zero-length) are omitted from this result vector.
For example, with a dictionary that contains key–value pairs -5="a", 17="b", 37="c", 53=integer(0), and 82="d", compactIndices(preserveOrder=T) will transform the dictionary to contain 0="a", 1="b", 2="c", and 3="d", while key 53 (and its zero-length value) is dropped; the returned vector will be (5, 17, 37, 82). The result from compactIndices(preserveOrder=F) has a non-deterministic order, but one possibility for the same example inout is that it would transform the dictionary to contain key–value pairs 0="c", 1="d", 2="a", and 3="b", with a returned vector of (37, 82, 5, 17); the same key–value pairs are kept, and they are again placed in sequential keys beginning with 0, but their order is no longer preserved across the compaction.
This method is particularly useful when you have a Dictionary d that contains results from some operation on a vector x, such that each key n in d has a value that is the result of processing the n’th element of x. In this case, order=d.compactIndices(preserveOrder=F) will transmogrify d to contain only the non-zero-length results, in sequential indices counting from 0, and x[order] provides the elements of x that produced those results, in the same order as in d after compaction. Using preserveOrder=T additionally keeps d in the same order as the original order of x, for cases in which that ordering is important.
– (object<Dictionary>$)getRowValues(li index, [logical$ drop = F])
Returns a new Dictionary containing values for selected “rows” of the target Dictionary, allowing Dictionary to act similarly to a DataFrame. See the subsetRows() method of class DataFrame for comparison; the main utility of getRowValues() is that it can be used on a Dictionary that has ragged “rows”. The selection logic described below works similarly to the subset operator [] in Eidos, selecting the “rows” of the target Dictionary.
The index parameter may be either integer or logical; we will discuss the integer case first. If index is a singleton integer, the returned Dictionary will contain the index’th element of the value of each key of the target, under the same keys; this is a single “row” of the target Dictionary. If index is a non-singleton integer vector, the returned Dictionary will contain the values for all of the selected rows, in the order that they are selected by index. If any index value in index is out of range for any key of the target Dictionary (such that that key does not have an index’th value), the returned dictionary will simply not have a value for that “row” of that key.
If index is logical, the T values in index select the “rows” which will be included in the returned Dictionary. The values within each column in the returned Dictionary will be in the same order as in the target. The length of index need not match any column of the Dictionary; excess “rows” beyond the length of index will not be selected, and excess values in index beyond the end of the longest “column” will have no effect.
If the values of index are such that no value for a given key is selected, the drop parameter controls the resulting behavior. If drop is F (the default), the key will be included in the returned dictionary with a zero-length value of matching type, such as integer(0) or string(0). If drop is T, the key will be omitted from the returned dictionary.
– (*)getValue(is$ key)
Returns the value previously set for the dictionary entry identifier key using setValue(), or NULL if no value has been set.
– (logical$)identicalContents(object<Dictionary>$ x)
Returns T if the target Dictionary is equal to x in all respects – containing the same keys, with values that are identical in the sense defined by the identical() function in Eidos – or returns F otherwise.
Note that if Dictionary objects are contained, as values, by the dictionaries being tested for equality, they will be compared according to the standards of identical(), and must therefore actually be the same Dictionary object, shared by both dictionaries, for isEqual() to return T.
– (string)serialize([string$ format = "slim"])
Returns a serialized form of the dictionary’s contents as a string singleton or vector. Five formats are supported at present, as chosen with the format parameter: "slim", "pretty", and "json" produce a singleton string, whereas "csv" and "tsv" produce a string vector. These serializations can be written to disk with writeFile() or writeTempFile(), written to the output stream with cat(), or used in any other way.
The default "slim" format is intended for simple, informal use where a very easily parseable string is desired. For a simple dictionary containing only keys with singleton non-object values, this will be a semicolon-delimited string like '"string1"=value1;"string2"=value2;' or 'int1=value1;int2=value2;'. Values of type string will be quoted, and will be escaped with backslash escape sequences, including \\, \", \', \t, \r, and \n. Values that are not singleton will be separated by spaces, such as '"string1"=1 2 3;', while values that are themselves dictionaries will be delimited by braces, such as '"string1"={int1=value1;int2=value2;};'. Keys that are of type string will be quoted (always; note that this is a change in behavior starting in SLiM 4.1) and backslash-escaped (as needed, as for string values); keys that are of type integer are not quoted. No facility for parsing "slim" serializations back into Eidos is presently provided.
For a more extended example, here is an input Dictionary, assigned into a variable x:
x = Dictionary("a", 17, "b", 1:5, "c", c("foo", "bar"),
"d", Dictionary("seq", 1.5:5),
"e", Dictionary());
and here is the result of x.serialize("json"), omitting the enclosing quotes that would indicate that this is a string value:
"a"=17;"b"=1 2 3 4 5;"c"="foo" "bar";"d"={"seq"=1.5 2.5 3.5 4.5;};"e"={};
The "pretty" format is intended for human-readable output, for purposes such as debugging output. It is similar to the "slim" format, but (1) it prints an enclosing set of braces at the top level, (2) it adds newlines inside braces, (3) it tracks an indentation level that increments for nested dictionaries, (4) it adds whitespace it some positions for readability, such as around the equals signs that separate keys from values, and (5) it omits the semicolon at the end of a value, adding a newline instead. No facility for parsing "pretty" serializations back into Eidos is presently provided.
For the same extended example Dictionary as above, here is the result of x.serialize("pretty"), again omitting the enclosing quotes that would indicate that this is a string value:
{
"a" = 17
"b" = 1 2 3 4 5
"c" = "foo" "bar"
"d" = {
"seq" = 1.5 2.5 3.5 4.5
}
"e" = {}
}
The "json" format, introduced in Eidos 2.7 (SLiM 3.7), provides serialization of the Dictionary into the standard JSON format, which may not be quite as brief or human-readable, but which can be used as a standard interchange format and read by the Dictionary() constructor in Eidos as well as by many other programs. For example, a Dictionary with a key "key1" with integer value 1:3 and key "key2" with string value "value2" would produce the JSON serialization '{"key1":[1,2,3],"key2":["value2"]}', where the outer single quotes are not part of the serialization itself, but are indicating that the serialization is a string value. Note that since all Eidos values are vectors, even singleton values are serialized into JSON as arrays by Eidos; the hope is that this will make automated parsing of these JSON strings easier, since the singleton case will not have to be special-cased. For example, Dictionary("a", 1, "b", Dictionary("x", 2)) would be serialized into JSON as '{"a":[1],"b":[{"x":[2]}]}'. Note that dictionaries that use integer keys cannot be serialized into JSON, because JSON does not support integer keys. Documentation on the JSON format can be found online.
The "csv" and "tsv" formats produce standard comma-separated value (CSV) or tab-separated value (TSV) data. These formats are primarily intended for output from DataFrame, since that class is used to represent the sort of data tables that CSV/TSV are typically used for; but it may be used with Dictionary too, particularly if it is being used to represent a data table with ragged columns (missing values will just be skipped over, producing two commas or two tabs in sequence). Values of type string will always be quoted, with double quotes (with a repeated double quote used to indicate the presence of a double quote inside a string value, as usual in CSV); values of other types never will. Decimal points (not decimal commas, regardless of system localization) will always be used for float values, and will never be used for integer values. Values of logical type will be serialized as TRUE or FALSE, without quotes. A header line providing the names of the columns (i.e., the keys of the target Dictionary) will always be generated; those column names will also be quoted (if the keys of the dictionary are type string; integer keys are not quoted). One string element will be generated for each row of the target, plus one string element for the header line; newlines will not be present in the resulting string vector unless newlines were present within the string values in the Dictionary. The resulting data, if written to a file, should be readable in Eidos using readCSV() (as long as there are no ragged columns or missing values), as well as in other software such as R and Excel.
– (void)setValue(is$ key, * value)
Sets a value for the dictionary entry identifier key. The key may be a string or an integer; either is allowed, unless the target dictionary has already begun using keys of a given type, in which case it must continue using the same key type (a given dictionary cannot have both string and integer keys). The value, which may be of any type, can be fetched later using getValue(). Setting a key to a value of NULL removes that key from the dictionary.
If value is of type object, any object class is allowed; all objects may be added as values to a dictionary. However, additional scoping restrictions may apply if the object class is not under an internal memory-management scheme called “retain-release”; in particular, it may not be legal to keep an object in a dictionary “long term” if it is not under retain-release, where “long term” is a scoping semantic defined by the Context. All object classes defined by Eidos itself (Dictionary, DataFrame, Image) are under retain-release, so this restriction does not affect pure Eidos code. See the SLiM manual (section “SLiM scoping rules”) for further discussion of this topic.
+ (void)setValuesVectorized(is$ key, * values)
This class method sets a singleton value from values into each target dictionary, using the same dictionary entry identifier key for each. The number of elements in values must be equal to the number of target dictionaries, so that the 0th element of values is set as the value for the 0th target object, the 1st element of values is set as the value for the 1st target object, and so forth.
This is a vectorized version of setValue(); dicts.setValuesVectorized("key", values) is equivalent to for (dict in dicts, value in values) dict.setValue("key", value), but is faster since the for loop is vectorized internally. The speedup is not enormous, however; the larger reason for the existence of this method is convenience.
The values are set into the target dictionaries in exactly the same way as the setValue() method would do; see that method for details about string versus integer keys, scoping restrictions for values of type object, and so forth. Note that it is not possible to remove values from the target dictionaries, however, since it is not possible to pass NULL as a value here.
5.4 Class Image
(object<Image>$)Image(...)
Creates a new Image object. This can be called in a few different ways.
Passed a singleton string, as Image(string$ filePath), it creates a new Image from the PNG file at filePath. If the file represents a grayscale image, an 8-bit grayscale (K) Image will be created; all other PNG files will yield a 24-bit color (RGB) Image.
Passed an integer or float vector, as Image(numeric matrix), it creates a new grayscale Image from the values in matrix, which must be a matrix as its name suggests. If matrix is integer, its values must be in [0, 255], and will be used directly as 8-bit pixel values without translation; if matrix is float, its values must be in [0.0, 1.0], and will be translated into 8-bit pixel values. The dimensions of the image, in pixels, will be equal to the dimensions of the matrix. The orientation of the image will match that of the matrix, in the sense that the image will appear as the matrix does when printed in the Eidos console; internally this requires a transposition of values, as discussed further below. For the integer case, the integerK property of the resulting image will recover the original matrix exactly; for the float case, the floatK property will only approximately recover the original matrix since the translation into 8-bit pixel values involves quantization, but values of 0.0 and 1.0 will be recovered exactly.
5.4.1 Image properties
width => (integer$)
The width of the image, in pixels.
height => (integer$)
The height of the image, in pixels.
isGrayscale => (logical$)
This flag is T if the image is grayscale, with only a K channel; it is F if the image is color, with R/G/B channels.
bitsPerChannel => (integer$)
The number of bits used to represent a single pixel, in one channel of the image. At present this is always 8; grayscale (K) images are 8-bit, color (RGB) images are 24-bit. It could be extended to support 16-bit channels in future.
integerR => (integer)
The red (R) channel of the image, represented as a 2D integer matrix. Values will be in [0,255]. See the floatR property for an alternative representation. If the image is grayscale, this property is unavailable.
integerG => (integer)
The green (G) channel of the image, represented as a 2D integer matrix. Values will be in [0,255]. See the floatG property for an alternative representation. If the image is grayscale, this property is unavailable.
integerB => (integer)
The blue (R) channel of the image, represented as a 2D integer matrix. Values will be in [0,255]. See the floatB property for an alternative representation. If the image is grayscale, this property is unavailable.
integerK => (integer)
The gray (K) channel of the image, represented as a 2D integer matrix. Values will be in [0,255]. See the floatK property for an alternative representation. If the image is color, this property is unavailable.
floatR => (float)
The red (R) channel of the image, represented as a 2D float matrix. Values will be in [0,1], obtained by dividing the integerR layer by 255. See the integerR property for an alternative representation. If the image is grayscale, this property is unavailable.
floatG => (float)
The green (G) channel of the image, represented as a 2D float matrix. Values will be in [0,1], obtained by dividing the integerG layer by 255. See the integerG property for an alternative representation. If the image is grayscale, this property is unavailable.
floatB => (float)
The blue (B) channel of the image, represented as a 2D float matrix. Values will be in [0,1], obtained by dividing the integerB layer by 255. See the integerB property for an alternative representation. If the image is grayscale, this property is unavailable.
floatK => (float)
The gray (K) channel of the image, represented as a 2D float matrix. Values will be in [0,1], obtained by dividing the integerK layer by 255. See the integerK property for an alternative representation. If the image is color, this property is unavailable.
5.4.2 Image methods
– (void)write(string$ filePath)
Writes the image to the given filesystem path filePath as PNG data. It is suggested, but not required, that filePath should end in a .png or .PNG filename extension. If the file cannot be written, an error will result. At present, since bitsPerChannel is always 8, grayscale data will be written as an 8-bit grayscale PNG while color (RGB) data will be written as a 24-bit color PNG without alpha.