Get array of data based on hierarchical edges sequence in cytoscape.js - cytoscape.js

I use cytoscape.js to organize an flow of nodes that represent an tasks execution. Sometimes an task is not created hierarchicly.
At least in a visual way, edges gives the correct sequence.
I would like to get the hierarchical sequence based on the edges and list their data as an array. Each index will be dispposed as edges says so.
The image above represent a sequence based on the edges arrows. I would like to transform this edges/arrows sequence into a perfect sequence of data (array).
The cytoscape.elements().toArray() method transform visual to array, but it is delivered the same sequence of the original data.
How can it be done? Is there some method in cytoscape core?

The easiest way would be to give the nodes id's with the corresponding numbers in your sequence:
-> The first task to execute has the id 1, the second has the id 2...
After initialization you can then do a loop with n iterations (n = number of nodes in cy) and get the nodes one by one. That way you can access their information and enter this data into an array:
for (i = 0; i < cy.nodes().length; i++) {
var curr = cy.nodes("[id = '" + i + "']"); // This way you get the node with the id == i
//do stuff
array[i] = theDataYouNeed;
}
If you want the nodes to be in a hierarchy, you would have to rethink your layout. An hierarchy in cytoscape can be achieved by "directed acyclic graph" (= dagre in cytoscape).

Related

Convert stream or sequence to a stream or sequence of summaries

Using Kotlin, how would I transform a Sequence of detail objects into a Sequence of summary objects, where each summary object represents a fixed number of detailed objects? It's kind of like map, except it's not one-to-one and it's kind of like reduce except it's not to a single accumulator?
For example:
var hourlyInfo: Sequence<HourlyData> = ...
var dailyInfo: Sequence<DailySummary> = hourlyInfo.somethingMagical()
What about the same problem with a stream instead of a sequence?
If there's a known fixed number of items, you use chunked and then map. When the sequence is iterated, actual lists of each chunk of items will be allocated.
var dailyInfo: Sequence<DailySummary> = hourlyInfo
.chunked(12)
.map(::DailySummary) // for example if it has a constructor taking a List of 12 HourlyData
If the List of HourlyData isn't ordered, or there isn't some fixed size, then I suppose you have to group by some property in HourlyData and then map it. This does not preserve Sequence status.
var dailyInfo: Sequence<DailySummary> = hourlyInfo
.groupBy(HourlyData::hourOfDay)
.map { (hour, listOfHourlyData) -> DailySummary(hour, listOfHourlyData) }

Iterate connected nodes in cytoscape.js

I need to get the nodes connected to a given node, and highlight them. The "components" function looks good for this, however my traversal fails. The component collection shows a size of one and only the original node gets highlighted.
cynode = cy.getElementById(idstr);
comps = cynode.components();
for (i = 0; i < comps.length; i++) /* really there's only one component */
{
comp = comps[i];
alert(comp.size()); /* this always returns 1!! */
comp.nodes().addClass('nodehlt'); /* only the original node gets highlighted */
}
From the docs:
eles.components() : Get the connected components, considering only the elements in the calling collection. An array of collections is returned, with each collection representing a component.
If the set of elements you consider is only a single node, there can only ever be one component.
You need to get the components of the whole graph (cy.elements.components()) -- or of the subgraph you're interested in. Of those components, you then need to find the one that contains the node of interest.

Get bone ID from its name or from the index on skin list in MaxScript

I have an bone name (e.g. Bone002) and I want to get the bone ID for it (not the index in skin list, but the ID that is required e.g. in skinOps.SetVertexWeights).
I know that reverse operation looks like this:
skinMod = $.modifiers[#skin]
boneListIndex = (skinOps.GetVertexWeightBoneID skinMod v w)
local boneName = skinOps.GetBoneNameByListID skinMod boneListIndex 0
But how to get boneID? I already have boneListIndex and boneName.
I assume that all bones have unique names.
What version of 3dsMax are you using? I remember the documentation being rather confusing here. Bone_ID and vertex_bone_integer are interchangeable in this case - I just tested on a simple mesh and SkinOps.GetVertexWeightBoneID and SkinOps.SetVertexWeights work with the same bone indices.
If you want to locate by name, then you need to match the indices by name. Create an array with your bone names:
boneNames = for i=1 to (skinOps.GetNumberBones skinMod) collect (skinOps.GetBoneName skinMod i 0)
Then you can use your favorite search method and retrieve the index, a simple findItem works well here:
boneIndex = findItem boneNames "Bone002"
Keep in mind that the skinOps.GetBoneName function is slightly borked; the last parameter is meant to determine whether to return the actual node or its name - regardless the setting, only the name string is ever returned. This means that if you have two bones in the skin with the same name, you'll have to find a clever way on how to get the appropriate node.
If what you want is the boneID corresponding to the bone owning the skin weights, then you need one more step, because skinOps.GetBoneName returns the parent of the bone owning the weights:
fn GenerateBoneList sk =
(
boneNames = #()
for i=1 to (skinOps.GetNumberBones skinMod) do
(
local aName = skinOps.GetBoneName skinMod i 0
local inSkinUI = (execute ("$" + aName)).children[1].name
append boneNames inSkinUI
)
return boneNames
)
Now, when you use finditem, you can use the name of the bone that owns the skin weights
finditem boneNames $Bone002.name

Generating tree nodes on the fly

I have an ANTLRv3 grammar to transform an AST (generated and consumed by other grammars).
One part of it is to rewrite ranges defined like M:N (i.e. 1:5) into their actual list representation — M, M+1, ..., N (i.e. 1, 2, 3, 4, 5).
So, a node ^(RANGE s=INT e=INT) is transformed into a list of INT tokens.
What I currently do now is the following:
range
: ^(RANGE s=INT e=INT) -> { ToSequence(int.Parse($s.text),int.Parse($e.text)) }
;
and the ToSequence method looks like
private ITree ToSequence(int start, int end)
{
var tree = new CommonTree();
for (int i = start; i <= end; i++)
{
tree.AddChild(new CommonTree(new CommonToken(INT, i.ToString())));
}
return tree;
}
It actually works fine, transforming tree node (TIME 1 2 (RANGE 5 10) 3 4) to (TIME 1 2 5 6 7 8 9 10 3 4), but I somewhat unsure whether it is the correct and idiomatic way to do such a transformation.
So, is there any more civilized way to perform this task?
I don’t think that performing such transformations inside the parser is a good idea at all. Your code lacks any kind of validity check. What if the first number is bigger than the second one? And what if errors are detected at the next stage of processing? At that point you have already lost the knowledge about the true structure of your input so you can’t give useful error messages.
I strongly recommend building a tree reflecting the true structure of your input first and transforming the tree afterwards. The transformed node might keep references to their source nodes then.

Optimal Solution: Get a random sample of items from a data set

So I recently had this as an interview question and I was wondering what the optimal solution would be. Code is in Objective-c.
Say we have a very large data set, and we want to get a random sample
of items from it for testing a new tool. Rather than worry about the
specifics of accessing things, let's assume the system provides these
things:
// Return a random number from the set 0, 1, 2, ..., n-2, n-1.
int Rand(int n);
// Interface to implementations other people write.
#interface Dataset : NSObject
// YES when there is no more data.
- (BOOL)endOfData;
// Get the next element and move forward.
- (NSString*)getNext;
#end
// This function reads elements from |input| until the end, and
// returns an array of |k| randomly-selected elements.
- (NSArray*)getSamples:(unsigned)k from:(Dataset*)input
{
// Describe how this works.
}
Edit: So you are supposed to randomly select items from a given array. So if k = 5, then I would want to randomly select 5 elements from the dataset and return an array of those items. Each element in the dataset has to have an equal chance of getting selected.
This seems like a good time to use Reservoir Sampling. The following is an Objective-C adaptation for this use case:
NSMutableArray* result = [[NSMutableArray alloc] initWithCapacity:k];
int i,j;
for (i = 0; i < k; i++) {
[result setObject:[input getNext] atIndexedSubscript:i];
}
for (i = k; ![input endOfData]; i++) {
j = Rand(i);
NSString* next = [input getNext];
if (j < k) {
[result setObject:next atIndexedSubscript:j];
}
}
return result;
The code above is not the most efficient reservoir sampling algorithm because it generates a random number for every entry of the reservoir past the entry at index k. Slightly more complex algorithms exist under the general category "reservoir sampling". This is an interesting read on an algorithm named "Algorithm Z". I would be curious if people find newer literature on reservoir sampling, too, because this article was published in 1985.
Interessting question, but as there is no count or similar method in DataSet and you are not allowed to iterate more than once, i can only come up with this solution to get good random samples (no k > Datasize handling):
- (NSArray *)getSamples:(unsigned)k from:(Dataset*)input {
NSMutableArray *source = [[NSMutableArray alloc] init];
while(![input endOfData]) {
[source addObject:[input getNext]];
}
NSMutableArray *ret = [[NSMutableArray alloc] initWithCapacity:k];
int count = [source count];
while ([ret count] < k) {
int index = Rand(count);
[ret addObject:[source objectAtIndex:index]];
[source removeObjectAtIndex:index];
count--;
}
return ret;
}
This is not the answer I did in the interview but here is what I wish I had done:
Store pointer to first element in dataset
Loop over dataset to get count
Reset dataset to point at first element
Create NSMutableDictionary for storing random indexes
Do for loop from i=0 to i=k. Each iteration, generate a random value, check if value exists in dictionary. If it does, keep generating a random value until you get a fresh value.
Loop over dataset. If the current index is within the dictionary, add it to a the array of random subset values.
Return array of random subsets.
There are multiple ways to do this, the first way:
1. use input parameter k to dynamically allocate an array of numbers
unsigned * numsArray = (unsigned *)malloc(sizeof(unsigned) * k);
2. run a loop that gets k random numbers and stores them into the numsArray (must be careful here to check each new random to see if we have gotten it before, and if we have, get another random, etc...)
3. sort numsArray
4. run a loop beginning at the beginning of DataSet with your own incrementing counter dataCount and another counter numsCount both beginning at 0. whenever dataCount is equal to numsArray[numsCount], grab the current data object and add it to your newly created random list then increment numsCount.
5. The loop in step 4 can end when either numsCount > k or when dataCount reaches the end of the dataset.
6. The only other step that may need to be added here is before any of this to use the next command of the object type to count how large the dataset is to be able to bound your random numbers and check to make sure k is less than or equal to that.
The 2nd way to do this would be to run through the actual list MULTIPLE times.
// one must assume that once we get to the end, we can start over within the set again
1. run a while loop that checks for endOfData
a. count up a count variable that is initialized to 0
2. run a loop from 0 through k-1
a. generate a random number that you constrain to the list size
b. run a loop that moves through the dataset until it hits the rand element
c. compare that element with all other elements in your new list to make sure it isnt already in your new list
d. store the element into your new list
there may be ways to speed up the 2nd method by storing a current list location, that way if you generate a random that is past the current pointer you dont have to move through the whole list again to get back to element 0, then to the element you wish to retreive.
A potential 3rd way to do this might be to:
1. run a loop from 0 through k-1
a. generate a random
b. use the generated random as a skip count, move skip count objects through the list
c. store the current item from the list into your new list
Problem with this 3rd method is without knowing how big the list is, you dont know how to constrain the random skip count. Further, even if you did, chances are that it wouldnt truly look like a randomly grabbed subset that could easily reach the last element in the list as it would become statistically unlikely that you would ever reach the end element (i.e. not every element is given an equal shot of being select.)
Arguably the FASTEST way to do this is method 1, where you generate the random numerics first, then traverse the list only once (yes its actually twice, once to get the size of the dataset list then again to grab the random elements)
We need a little probability theory. As others, I will ignore the case n < k. The probability that the n'th item will be selected into the set of size k is just C(n-1, k-1) / C(n, k) where C is the binomial coefficient. A bit of math says shows that this is just k/n. For the rest, note that the selection of the n'th item is independent of all other selections. In other words, "the past doesn't matter."
So an algorithm is:
S = set of up to k elements
n = 0
while not end of input
v = next value
n = n + 1
if |S| < k add v to S
else if random(0,1) >= k/n replace a randomly chosen element of S with v
I will let the coders code this one! It's pretty trivial. All you need is an array of size k and one pass over the data.
If you care about efficiency (as your tags suggest) and the number of items in the population is known, don't use reservior sampling. That would require you to loop through the entire data set and generate a random number for each.
Instead, pick five values ranges from 0 to n-1. In the unlikely case, there is a duplicate among the five indexes, replace the duplicate with another random value. Then use the five indexes to do a random-access lookup to the i-th element in the population.
This is simple. It uses a minimum number of calls the random number generator. And it accesses memory only for the relevant selections.
If you don't know the number of data elements in advance, you can loop-over the data once to get the population size and proceed as above.
If you aren't allow to iterate over the data more than once, use a chunked form of reservior sampling: 1) Choose the first five elements as the initial sample, each having a probability of 1/5th. 2) Read in a large chunk of data and choose five new samples from the new set (using only five calls to Rand). 3) Pairwise, decide whether to keep the new sample item or old sample element (with odds proportional the the probablities for each of the two sample groups). 4) Repeat until all the data has been read.
For example, assume there are 1000 data elements (but we don't know this in advance).
Choose the first five as the initial sample: current_sample = read(5); population=5.
Read a chunk of n datapoints (perhaps n=200 in this example):
subpop = read(200);
m = len(subpop);
new_sample = choose(5, subpop);
loop-over the two samples pairwise:
for (a, b) in (current_sample and new_sample): if random(0 to population + m) < population, then keep a, otherwise keep *b)
population += m
repeat