cleave | R Documentation |
Cleave, as in "to cleave together," moves data from separate spines (or paths) into
new fields in the same spine(s).
Under the hood, cleave()
essentially runs a specialized call to make the humdrum table
"wider," similar to R functions like cast(), spread(), or pivot_wider().
In fact, a humdrumR method for pivot_wider() is defined, which is equivalent to cleave()
.
The cleave()
function is essentially the inverse of rend()
.
cleave(humdrumR, ..., field = selectedFields(humdrumR)[1], newFields = NULL)
## S3 method for class 'humdrumR'
pivot_wider(data, names_from = "Spine", values_from = selectedFields(data)[1])
cleaveSpines(humdrumR, field = selectedFields(humdrumR)[1])
cleavePaths(humdrumR, field = selectedFields(humdrumR)[1])
cleaveStops(humdrumR, field = selectedFields(humdrumR)[1])
humdrumR |
HumdrumR data. Must be a humdrumR data object. |
... |
What to cleave? Must be natural numbers, |
field |
Which field cleave data from. Defaults to first selected field. Must be a |
newFields |
Names to use for new fields created by the cleave. By default generates names by structure/number (like Must be non-empty |
Many humdrum datasets encode data across multiple spines, spine-paths, or stops.
By default, humdrumR
parses each separate spine, spine-path, and stop as their own individual
data points, taking up one row in the humdrum table.
If we want to treat data in multiple spines/paths/stops as different aspects of the same data
it is easiest to reshape the data so that the information is in different humdrumR fields
rather than separate spines/paths/stops.
In the humdrum syntax view, the spines (or path/stops) are moved "on top" of each other, cleaving them
together.
The convenient cleaveSpines()
, cleaveStops()
, and cleavePaths()
functions automatically cleave all stops/paths in a dataset
onto the first spine/stop/path, creating new fields named, e.g., Path1
, Path2
, etc.
The cleave()
function takes any number of ...
arguments specifying groups of spines/paths/stops
to cleave together.
cleave(humData, Spine = 1:2)
will cleave the first and second spine.
cleave(humData, Spine = 1:4)
will cleave the first four spines.
cleave(humData, Spine = 1:2, Spine = 3:4)
will cleave spine 1 with spine 2, and separately, spine 3 with spine 4.
The default is to cleave spines, so you can actually omit the Spine =
part: e.g., cleave(humData, 1:2)
is the same
as cleave(humData, Spine = 1:2)
.
If you want to cleave spine paths, you'll need to explicitly call something like cleave(humData, Path = 0:1)
.
The first element in each group is used as the original location which all other spines/paths/stops are cleaved into.
The ordering of the remaining elements is irrelevant.
By default, the same cleaving will be applied in all pieces (if the pieces have the target spines/paths/stops).
However, you can use an alternate argument structure to apply differerent cleaves to different pieces.
To do so, provide groups to cleave arguments in a list, with each element in the list representing cleave group
in one piece.
If the listed groups are unnamed, the groups are mapped to pieces by index.
For example, the call cleave(humData, list(1:2, 2:3, 3:4, NULL, 1:3))
will result in the following cleaves:
In piece 1, cleave spines 1 and 2.
In piece 2, cleave spines 2 and 3.
In piece 3, cleave spines 3 and 4.
In piece 4, no cleave (no changes).
In piece 5, cleave the first three spines.
In any remaining pieces (6 or greater), no cleaves.
Alternatively, you can name the list elements with integers corresponding to pieces.
For example, cleave(humData, Path = list("1" = 0:1, 5 = 0:2"))
will cleave paths 0 and 1 in
piece 1, and paths 0:2
in piece 5.
When cleaving spines, you can specify spines using character strings representing exclusive interpretations.
So you can call cleave(humData, c('kern', 'silbe'))
, which will cause **kern
and **silbe
spines in each piece to
be cleaved.
Note that any exclusive interpretations which aren't "mentioned" in the call remain in their original field.
The behavior of exclusive cleaving depends on the relative number of each target exclusive interpretation in each piece.
If there are equal numbers of each interpretation, the spines are grouped in parallel.
For example, if a piece has the spines **kern **silbe **kern **silbe
, the command cleave(humData, c('kern', 'silbe'))
will see that there are two **kern
/**silbe
pairs, and cleave them just like cleave(humData, 1:2, 3:4)
.
If there are different numbers of spines matching each exclusive interpretation, the cleave behavior depends on which
field is the first field in your input argument—we'll call that the "target" exclusive.
Consider a file with spines **kern **kern **harm
.
If we specify a cleave call cleave(humData, c('kern', 'harm'))
that means we want **kern
to be the "target" exclusive.
Since there are fewer **harm
spines than **kern
spines, the data in the **harm
spine will be duplicated, can cleaved
to both **kern
spines in parallel.
If we instead call cleave(humData, c('harm', 'kern'))
, making **harm
the "target", the two **kern
spines will both be "piled" atop
the single **harm
spine, making two new **kern
fields.
Cleaving can (for now) only be applied to one field in our data, which defaults to the first selected field;
You can change the target field with the field
argument.
Cleaving will always introduce new fields into your data.
The first spine/path/stop in each cleave group is left in it's original (target) field.
Other spine/path/stops will be put into new fields.
So if you call humData |> select(Token) |> cleave(humData, 1:2)
, spine 1 will remain in the Token
field and spine 2 data will be put in a new field.
By default, the new field(s) will be automatically named by appending the type of cleave (spine vs path vs stop)
to the number.
In the cleave(humData, 1:2)
case, the new field will be called Spine2
.
You can control the name with the newFields
argument, which must be a character
vector.
You can provide as many new field names as there will be new fields.
If you provide too few field names, your name(s) will have numbers appended as necceasary to cover all the new fields;
If you provide too many field names, the extra names will simply be ignored.
When cleaving by exclusive interpretation newFields
can be used in the exact same way.
However, by default (if newFields
is NULL
), cleave()
will names fields by their exclusive interpretation.
Note that the original target field (specified by the field
) argument will not have it's name changed.
So for example, humData |> select(Token) |> cleave(humData, c('kern', 'silbe'))
will result in the spines Token
and Silbe
.
No Kern
field is created, because the Kern
data is left in the Token
field.
The complement/opposite of cleave()
is rend()
.
The collapse family of functions serves a somewhat
similar function to cleave()
.
Other Humdrum table reshaping functions:
collapseHumdrum()
,
expandPaths()
,
rend()
Other Humdrum table pivoting functions:
rend()
humData <- readHumdrum(humdrumRroot, "HumdrumData/MozartVariations/.*.krn")
humData |> cleave(3:4)
humData |> cleave(Path = 0:1, newFields = 'Ossia')
humData |> cleavePaths()
humData |> cleave(c('function', 'harm'), newFields = 'Harmony')
humData |> cleave(c('kern', 'function', 'harm'))
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.