Determining whether a node in a collapsible tree is hidden - user-interface

I'm working on a GUI that displays a list of elements.
All the elements are in a one dimensional iterable array, so displaying them would normally look something like this:
foreach (Element e: elements) {
display.Display(e);
}
I now need a way to organize the elements in a tree structure like in this example:
In my system, there is no distinction between "folder" elements and "file" elements, but I can access an element's 'depth' and 'isExpanded' values.
How can I determine whether an element should be displayed based on data taken from iterating through previous elements?

I think I've figured it out, but there may be some cases that mess it up:
bool prevIsCollapsed = false;
int collapsedPropertyDepth = 0;
// iterate through each property of this component
for (Property p : properties)
{
int depth = property.depth;
if (prevIsCollapsed && depth > collapsedPropertyDepth)
{
// dont display this property
continue;
}
if (!property.isExpanded)
{
prevIsCollapsed = true;
collapsedPropertyDepth = depth;
}
else
{
prevIsCollapsed = false;
}
}

Related

AMCharts - Dynamically add children to tree map

I am thoroughly enjoying AMChart's many features but I couldn't find any way to dynamically add some children to a treemap.
I am trying to load additional children on "hit" for each element
for (var i = 0; i < this.maxDepthLevel; i++) {
const series = this.chart.seriesTemplates.create(i);
series.columns.template.events.on("hit", async function(ev) {
const data = ev.target.dataItem.dataContext;
children = await api.getChildrenOf(data.id);
ev.target.dataItem.treeMapDataItem.children.values.push(...children);
});
}
^ this doesn't work and when doing this and then zooming out, I get
I even tried changing the underlying data and then calling
this.chart.invalidateRawData();
but to no avail.
Does anyone have any experience with adding such dynamic children to a tree map?
I cannot simply load everything upfront, there are far too many possible layers of depth unfortunately and the request will be too large!
Rather than directly pushing child items to children values you need to do it like this :
for(var index=0; index < children.length; index++){
var newChildDataItem = new am4charts.TreeMapDataItem();
newChildDataItem.value = children[index].value;
newChildDataItem.name = children[index].name;
newChildDataItem.color = ev.target.dataItem.dataContext.color;
ev.target.dataItem.dataContext.children.insert(newChildDataItem);
}

Drawing gaps for missing dates in dc.js time series line graph

Okay, so I've seen this ticket and this question and have tried several examples already. Maybe I'm just dense, but I really haven't been able to crack this one.
I have a time series of events that has gaps in it. By default, dc.js connects a straight line over the gap (making it look like things are represented there when they really shouldn't be). For example, in this graph we have data as follows:
{"time":"2014-06-09T18:45:00.000Z","input":17755156,"output":250613233.333333},
{"time":"2014-06-09T18:46:00.000Z","input":18780286.6666667,"output":134619822.666667},
{"time":"2014-06-09T18:47:00.000Z","input":20074614.6666667,"output":203239834.666667},
{"time":"2014-06-09T18:48:00.000Z","input":22955373.3333333,"output":348996205.333333},
{"time":"2014-06-09T18:49:00.000Z","input":19119089.3333333,"output":562631022.666667},
{"time":"2014-06-09T18:50:00.000Z","input":15404272,"output":389916332},
{"time":"2014-06-09T18:51:00.000Z","input":null,"output":null},
{"time":"2014-06-09T21:25:20.000Z","input":5266038.66666667,"output":62598396},
{"time":"2014-06-09T21:26:20.000Z","input":6367678.66666667,"output":84494096},
{"time":"2014-06-09T21:27:20.000Z","input":5051610.66666667,"output":88812540},
{"time":"2014-06-09T21:28:20.000Z","input":5761069.33333333,"output":79098036},
{"time":"2014-06-09T21:29:20.000Z", "input":5110277.33333333,"output":45816729.3333333}
Even though there's only two actual groups of data, there's a line on that graph connecting them. How do I make dc.js line graphs draw 0 where there is no data at all. I've tried using .defined(function(d) { return !isNaN(d.x);}) and .defined(function(d) { return d.y != null; }) and such, but this is just iterating through data which isn't there.
It's tricky trying to preserve nulls when using crossfilter, because crossfilter is all about aggregation.
Remember that reduceSum will add any values it finds, starting from zero, and 0 + null === 0.
In your case, it looks like you're not actually aggregating, since your timestamps are unique, so you could do something like this:
var input = time.group().reduce(
function(p, d) {
if(d.input !== null)
p += d.input;
else p = null;
return p;
},
function(p, d) {
if(d.input !== null)
p -= d.input;
else p = null;
return p;
},
function(){ return 0; }
);
Yeah, that's a lot more complicated than reduceSum, and it may get even more complicated if more than one datum falls into a bucket. (Not sure what you'd want to do there - is it possible for a data point to be partly defined?)
With the reduction defined this way, null reduces to null and dc.js is able to find the gaps:
Fork of your fiddle (thanks!): http://jsfiddle.net/gordonwoodhull/omLko77k/3/
Edit: counting nulls
If you're doing a "real" reduction where there is more than one value in a bin, I think you'll need to count the number of non-null values as well as keeping a running sum.
When there are no non-null values, the sum should be null.
Reusing our code a bit better this time:
function null_counter(field) {
return {
add: function(p, d) {
if(d[field] !== null) {
p.nvalues++;
p.sum += d[field];
}
return p;
},
remove: function(p, d) {
if(d[field] !== null) {
p.nvalues--;
p.sum -= d[field];
if(!p.nvalues)
p.sum = null;
}
return p;
},
init: function() {
return {nvalues: 0, sum: null};
}
}
}
Applied like this (and getting the fields right this time):
var input_reducer = null_counter('input');
var input = time.group().reduce(
input_reducer.add,
input_reducer.remove,
input_reducer.init
);
var output_reducer = null_counter('output');
var output = time.group().reduce(
output_reducer.add,
output_reducer.remove,
output_reducer.init
);
Since we're reducing to an object with two values {nvalues, sum}, we need to make all our accessors a little more complicated:
.valueAccessor(function(kv) { return kv.value.sum; })
.defined(function(d){
return (d.data.value.sum !== null);
})
chart.stack(output, "Output bits",
function(kv) { return kv.value.sum; });
Updated fork: http://jsfiddle.net/gordonwoodhull/omLko77k/9/

Tree Traversal without recursion and without stack and without changing the Tree

This question is from the book Introduction to Algorithms 3rd:
**Each node in the binary tree has 4 properties: key,left,right,parent
EDIT: The binary tree is stored as linked nodes that each one of them has the 4 properties I mentioned.
Write an O(n) time nonrecursive procedure that, given an n-node binary tree,
prints out the key of each node. Use no more than constant extra space outside of the tree itself and do not modify the tree, even temporarily, during the procedure.
I tried to find a solution but got nothing...(Also I searched google for solutions for this book, but this question wasn't included there maybe because it was added in later versions).
Here's a solution:
Let current store the currently visited node (initialized to the root of the tree)
Let origin represent how we got to the current node. It's one of FROM_PARENT, FROM_LEFT_CHILD, FROM_RIGHT_CHILD. (Initialized to FROM_PARENT)
Algorithm:
If we came from the top, we print the key and go down left
If we came back from left, go down right
If we came back form right, go up.
origin = FROM_PARENT;
current = root;
while (current != null) {
switch (origin) {
case FROM_PARENT:
System.out.println(current.key);
if (current.left != null)
goLeft();
else
origin = FROM_LEFT_CHILD;
break;
case FROM_LEFT_CHILD:
if (current.right != null)
goRight();
else
origin = FROM_RIGHT_CHILD;
break;
case FROM_RIGHT_CHILD:
goToParent();
break;
}
}
Where
static void goToParent() {
if (current.parent == null) {
current = null;
return;
}
origin = current == current.parent.left ? FROM_LEFT_CHILD
: FROM_RIGHT_CHILD;
current = current.parent;
}
static void goLeft() {
origin = FROM_PARENT;
current = current.left;
}
static void goRight() {
origin = FROM_PARENT;
current = current.right;
}

Get a random item from a collection that does not already exist in another collection - LINQ?

I am trying to learn LINQ but it is quite confusing at first!
I have a collection of items that have a color property (MyColor). I have another collection of all colors (called AvailableColors - lets say 10 for example).
I want to get a random color from the AvailableColors that does not already exist in my collection.
My current C# code just gets a random color but I would like to rewrite this in LINQ to take in the current color collection and exclude those from the possible options:
public MyColor GetRandomColour()
{
return AvailableColors[new Random().Next(0, AvailableColors.Count)];
}
so it would take in the existing collection:
public MyColor GetRandomColour(ListOfSomethingWithColorProperty)
Thanks for any pointers!
Excluding already-used colors implies saving of state. You might be better off writing an iterator and using yield return to return the next random color in the sequence. This allows you to "remember" which colors have already been used.
Once you have that, you can call it using Take(1) from Linq, if you wish.
// assumes Random object is available, preferrably a re-used instance
Color color = AvailableColors
.Except(myItems.Select(item => item.Color).Distinct())
.OrderBy(c => random.Next())
.FirstOrDefault();
Probably not terribly efficient, but also probably not a concern given a small number of items.
Another approach is to randomly order the available colors once beforehand, therefore you can go in order. Use a List<Color> so you can remove elements as you use them, or save the current index with each pull. Once the list is depleted or the index exceeds the length of the array, notify your user that you're all out of colors.
var rnd = new Random(); // don't keep recreating a Random object.
public MyColor GetRandomColour(List<Something> coll)
{
var len = rnd.Next(0, AvailableColors.Count- coll.Count);
return AvailableColors.Except(coll.Select(s=>s.MyColor)).Skip(len).First();
}
I'm going to suggest that you be Linq-minded and create a good, general purpose IEnumerable<T> extension method that does the heavy lifting you require and then your GetRandomColor functions are simpler and you can use the extension method for other similar tasks.
So, first, define this extension method:
public static IEnumerable<T> SelectRandom<T>(this IEnumerable<T> #this, int take)
{
if (#this == null)
{
return null;
}
var count = #this.Count();
if (count == 0)
{
return Enumerable.Empty<T>();
}
var rnd = new Random();
return from _ in Enumerable.Range(0, take)
let index = rnd.Next(0, count)
select #this.ElementAt(index);
}
This function allows you to select zero or more randomly chosen elements from any IEnumerable<T>.
Now your GetRandomColor functions are as follows:
public static MyColor GetRandomColour()
{
return AvailableColors.SelectRandom(1).First();
}
public static MyColor GetRandomColour(IEnumerable<MyColor> except)
{
return AvailableColors.Except(except).SelectRandom(1).First();
}
The second function accepts an IEnumerable<MyColor> to exclude from your available colors so to call this function you need to select the MyColor property from your collection of items. Since you did not specify the type of this collection I felt it was better to use IEnumerable<MyColor> rather than to make up a type or to define an unnecessary interface.
So, the calling code looks like this now:
var myRandomColor = GetRandomColour(collectionOfItems.Select(o => o.MyColor));
Alternatively, you could just directly rely on Linq and the newly created extension method and do this:
var myRandomColor =
AvailableColors
.Except(collectionOfItems.Select(o => o.MyColor))
.SelectRandom(1)
.First();
This alternative is more readable and understandable and will aid maintainability of your code. Enjoy.
There's a nifty way to select a random element from a sequence. Here it's implemented as an extention method:
public static T Random<T>(this IEnumerable<T> enumerable)
{
var rng = new Random(Guid.NewGuid().GetHashCode());
int totalCount = 0;
T selected = default(T);
foreach (var data in enumerable)
{
int r = rng.Next(totalCount + 1);
if (r >= totalCount)
selected = data;
totalCount++;
}
return selected;
}
This method uses the fact that probability to choose n-th element over m-th when iterating is 1/n.
With this method, you can select your colour in one line:
var color = AvailableColors.Except(UsedColors).Random();

An array stack algorithm without copy

I have a flashlite3 application with navigation consisting of icons the user can browse left or right through infinitely.
The basic algorithm i'm using now works (and is adequate for this project) however, part of the solution depends on a duplicate of the array of icons. Depending on the number of items in the array, and/or the size of the element contents, this solution could become less efficient. I'm interested in a solution or algorithm(in any language) that could achieve the same thing while being scalable & efficient.
Heres a portion of relevant code in the setter function for mutating the '_selectedItem' property, which:
Evaluates the current '_selectedItem' and the new '_value'
Based on step 1 pop,unshifts right, or shift,pops left
Repeats step 2 until the icon matching the '_selectedItem' is in the center of the array
This code runs using 3 arrays:
[static] Array of positions. There are 5 icons, 3 are visible at a time, so position 0 is off stage, position 1 is 1/3, position 2 is 1/2 ..
When instantiating the icons 2 arrays are created: _viewArray & _icons. The order of _viewArray mimics the order to be displayed and _icons is left alone and used for the loop condition checking
///Actionscript2///
public function set selectedItem(value:Number)
{
var w=Stage.width;
if(value > _icons.length-1)
{
value=0;
}else if(value < 0)
{
value=_icons.length-1;
}
if(value > _selectedIndex)
{
while(_viewArray[Math.floor(_icons.length*.5)] != _icons[value])
{
var element;
element=_viewArray.pop();
_viewArray.unshift(element);
}
}else if(value < _selectedIndex)
{
while(_viewArray[Math.floor(_icons.length*.5)]!=_icons[value])
{
var element;
element=_viewArray.shift();
_viewArray.push(element);
}
}
for(var i:Number=0;i<_viewArray.length;i++)
{
if(i>=1 && i<= _icons.length-2)
{
_viewArray[i]._visible=true;
}else
{
_viewArray[i]._visible=false;
}
Tweener.addTween(_viewArray[i],{_x:positions[i],_alpha:80,time:.5,transition:'elasticIn'})
}
Tweener.addTween(_icons[(_viewArray.length*.5)-1],{_alpha:100,time:.0,transition:'elasticIn'});
Tweener.addTween(_selectedServiceIndicator,{_alpha:0,time:.3,transition:'elasticIn',onComplete:function() {Tweener.addTween(this,{_alpha:100,time:.2,transition:'elasticIn'});}});
var eventObject:Object = {target:this, type:'SelectedItemChange'};
eventObject.value=value;
for(var key in _serviceData[value])
eventObject[key]=_serviceData[value][key];
dispatchEvent(eventObject);
_selectedIndex=value;
}
Why does each element of the _viewArray has to actually store the icon, rather than only the index into the _icons array? This way you only have the icons stored once, and _viewArray just stores their presentation order.

Resources