You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

243 lines
7.8 KiB
Plaintext

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

TITLE:: FluidDataSet
summary:: Container that associates data points with identifiers
categories:: Libraries>FluidCorpusManipulation
related:: Classes/FluidLabelSet, Classes/FluidKDTree, Classes/FluidKMeans
DESCRIPTION::
FluidDataSet is a container that associates data points with identifiers
CLASSMETHODS::
PRIVATE:: asUGenInput
METHOD:: new
Create a new instance of the DataSet, with the given name. If a DataSet with this name already exists, an exception will be thrown (see link::Classes/FluidDataSet#at:: to access an existing DataSet).
ARGUMENT:: server
The link::Classes/Server:: on which to create the data set.
returns:: The new instance
INSTANCEMETHODS::
PRIVATE:: init,id,cache
METHOD:: addPoint
Add a new point to the FluidDataSet. The dimensionality of the FluidDataSet is governed by the size of the first point added. If the identifier already exists, or if the size of the data does not match the dimensionality of the FluidDataSet an error will be reported.
Will report an error if the identifier already exists, or if the size of the data does not match the dimensionality of the DataSet.
ARGUMENT:: identifier
The identifier for the point.
ARGUMENT:: buffer
A link::Classes/Buffer:: containing the data for the point.
ARGUMENT:: action
A function to run when the point has been added.
METHOD:: updatePoint
Update an existing identifier's data. If the identifier does not exist, or if the size of the data does not match the dimensionality of the FluidDataSet an error will be reported.
ARGUMENT:: identifier
The identifier for the point.
ARGUMENT:: buffer
A link::Classes/Buffer:: containing the data for the point.
ARGUMENT:: action
A function to run when the operation completes.
METHOD:: getPoint
Retrieve a point from the data set into a link::Classes/Buffer::. If the identifier does not exist an error will be reported.
ARGUMENT:: identifier
The identifier for the point.
ARGUMENT:: buffer
A link::Classes/Buffer:: where the retrieved data will be stored.
ARGUMENT:: action
A function to run when the operation completes.
METHOD:: deletePoint
Remove a point from the data set. If the identifier doesn't exist an error will be reported.
ARGUMENT:: identifier
The identifier to be deleted.
ARGUMENT:: action
A function to run when the operation completes.
METHOD:: setPoint
Set the point. If the identifier exists, this method behaves like updatePoint. If the identifier doesn't exist, it behaves like addPoint.
ARGUMENT:: identifier
The identifier for the point.
ARGUMENT:: buffer
A link::Classes/Buffer:: containing the data for the point.
ARGUMENT:: action
A function to run when the operation completes.
METHOD:: clear
Empty the data set.
METHOD:: toBuffer
Dump the content of the dataset to a link::Classes/Buffer::, with optional transposition, and a map of frames/channels to the original IDs as a link::Classes/FluidLabelSet::.
ARGUMENT:: buffer
The buffer to write to. It will be resized.
ARGUMENT:: transpose
If 0, each dataset point becomes a buffer frame, and each dataset dimension becomes a buffer channel. If 1, points become channels, and dimensions become frames.
ARGUMENT:: labelSet
The link::Classes/FluidLabelSet:: in which to dump the point's IDs associated with their reference frame number (or channel number if transposed).
ARGUMENT:: action
A function to run when the dump is done.
METHOD:: fromBuffer
Import to the dataset the content of a link::Classes/Buffer::, with optional transposition, and a map of frames/channels to the original IDs as a link::Classes/FluidLabelSet::.
ARGUMENT:: buffer
The buffer to read from. The dataset will be resized.
ARGUMENT:: transpose
If 0, each buffer frame becomes a dataset point, and each buffer channel becomes a dataset dimension. If 1, channels become points, and frames become dimensions.
ARGUMENT:: labelSet
The link::Classes/FluidLabelSet:: from which to retrieve the point's IDs associated with their reference frame number (or channel number if transposed).
ARGUMENT:: action
A function to run when the import is done.
METHOD:: getIds
Export to the dataset IDs to a link::Classes/FluidLabelSet::.
ARGUMENT:: labelSet
The link::Classes/FluidLabelSet:: to export to. Its content will be replaced.
ARGUMENT:: action
A function to run when the export is done.
METHOD:: merge
Merge sourceDataSet in the current DataSet. It will update the value of points with the same identifier if overwrite is set to 1. To add columns instead, see the 'transformJoin' method of link::Classes/FluidDataSetQuery::
METHOD:: free
Destroy the object on the server.
METHOD:: print
Post an abbreviated content of the DataSet in the window by default, but you can supply a custom action instead.
returns:: A link::Classes/Synth::
METHOD:: server
The server instance the object uses
returns:: A link::Classes/Server::
EXAMPLES::
CODE::
// Create a simple a one-dimensional data set, three ways
// Using routine
s.reboot;
(
fork{
~ds = FluidDataSet.new(s);
~point = Buffer.alloc(s,1,1);
s.sync;
10.do{|i|
~point.set(0,i);
~ds.addPoint(i.asString,~point,{("addPoint"+i).postln});
s.sync;
};
~ds.dump;
s.sync;
~ds.free;
};
)
//Using Dictionary
(
d = Dictionary.new;
d.add(\cols -> 1);
d.add(\data -> Dictionary.newFrom(10.collect{|i|[i.asString, [i.asFloat]]}.flatten));
fork{
~ds = FluidDataSet.new(s);
~ds.load(d); s.sync;
~ds.dump; s.sync; ~ds.free;
}
)
// Using a synth
(
~ds = FluidDataSet.new(s);
{
var trig = Impulse.kr(20);
var count = PulseCount.kr(trig) - 1;
var buf = LocalBuf(1);
BufWr.kr(count, buf);
FluidDataSetWr.kr(~ds.asUGenInput, idNumber: count, buf: buf, trig: trig);
FreeSelf.kr(count - 8);
}.play.onFree{~ds.dump{|o| o.postln;~ds.free}}
)
::
STRONG:: Buffer Interface::
As the content of the dataset has a similar structure to buffers, namely arrays of floats in parallel, it is possible to transfer the content between the two. Careful consideration of the rotation of the buffer, as well as the relation of points to channel numbers, are needed.
code::
(
//Make a dummy data set
d = FluidDataSet(s);
~data = Dictionary.with(*Array.iota(20).reshape(4,5).collect{|a,i| ("row"++i)->a});
~dsdata = Dictionary.newFrom([\cols,5,\data,~data]);
d.load(~dsdata);
d.print;
)
//convert to separate buffer and labelset
b = Buffer(s);
l = FluidLabelSet(s);
d.toBuffer(b,0,l);
//check the result: by default, dataset points become frames, with their associated data columns as channels
b.query
b.getn(0,20,{|x|x.postln})
l.print
//you can also transpose your query, where dataset points are each a buffer channel, and each data column becomes a buffer frame
d.toBuffer(b,1,l);
b.query
b.getn(0,20,{|x|x.postln})
//note that the IDs are still one per item, as columns are unamed in datasets
l.print
//Convert back to DS again
e = FluidDataSet(s);
//Let's use the transposed data we just got
e.print;
e.fromBuffer(b,1,l);
e.print;
//if we didn't transpose, we would get an error as the labelset is mismatched with the number of items
e.clear
e.print
e.fromBuffer(b,0,l)
::
STRONG:: Merging Datasets::
code::
//this is how to add items between 2 datasets.
//create 2 datasets
(
~dsA = FluidDataSet.new(s);
~dsB = FluidDataSet.new(s);
)
//feed them items with same dimensions but different identifiers
~dsA.load(Dictionary.newFrom([\cols, 1, \data, Dictionary.newFrom([\one,1,\two,2])]));
~dsB.load(Dictionary.newFrom([\cols, 1, \data, Dictionary.newFrom([\three,3,\four,4])]));
~dsA.print;
~dsB.print;
// merge and check. it works.
~dsB.merge(~dsA)
~dsB.print;
//change the content of the dataset to shared identifiers
~dsA.load(Dictionary.newFrom([\cols, 1, \data, Dictionary.newFrom([\three,333,\four,444])]));
~dsB.load(Dictionary.newFrom([\cols, 1, \data, Dictionary.newFrom([\three,3,\four,4])]));
~dsA.print;
~dsB.print;
//try to merge, it does not update
~dsB.merge(~dsA)
~dsB.print;
// add the overwrite flag, and it works
~dsB.merge(~dsA,1)
~dsB.print;
::