How to Bind custom shapes on kendoUI Listview from JSON? - kendo-ui

var myShapes = [{ "Shapes": '{"path":"M74.5,37.5 C74.5,57.91 57.91,74.5 37.5,74.5 C17,74.5 0.5,57.91 0.5,37.5 C0.5,17 17,0.5 37.5,0.5 C57.91,0.5 74.5,17 74.5,37.5 z","connectors":[{"name":"bottom"}]}', "text": "Start" },
{ "Shapes": '{"path":"m 40,30 c 0,5.522847 -4.477153,10 -10,10 -5.522847,0 -10,-4.477153 -10,-10 0,-5.522847 4.477153,-10 10,-10 5.522847,0 10,4.477153 10,10 z M 30,0 C 13.431458,0 0,13.431458 0,30 0,46.568542 13.431458,60 30,60 46.568542,60 60,46.568542 60,30 60,13.431458 46.568542,0 30,0 z m 0,10 C 41.045695,10 50,18.954305 50,30 50,41.045695 41.045695,50 30,50 18.954305,50 10,41.045695 10,30 10,18.954305 18.954305,10 30,10 z","connectors":[{"name":"bottom"}]}', "text": "Start" },
{ "Shapes": '{"path":"M74.5,37.5 C74.5,57.91 57.91,74.5 37.5,74.5 C17,74.5 0.5,57.91 0.5,37.5 C0.5,17 17,0.5 37.5,0.5 C57.91,0.5 74.5,17 74.5,37.5 z","connectors":[{"name":"bottom"}]}', "text": "Start" }] ;
How to bind the above json to Listview?

Related

Plotly Dash Heatmap not updating with dropdown selection

I am new to plotly dash and i'm trying to make a heatmap that changes with a dropdown selection. The dropdown is to choose a month, but the heatmap doesn't change!
My data frame is called 'New'.
Here's my code:
Month_Default = New['Month'].unique()
Month_def = 2
#create the dash app
app = dash.Dash()
app.layout = html.Div([
html.H1('//Title'),
html.Div([
html.Div([
html.H4('Select Month...'),
dcc.Dropdown(
id='Month_dropdown',
options=[{'label': i, 'value': i} for i in Month_Default],
value = Month_Def
),
],
style={'width': '48%', 'display': 'inline-block'}),
dcc.Graph(id='heatmap',
figure = {
'data': [go.Heatmap(
x=New['Days'].where(New['Month']==2),
y=New['Hour'],
z=New['Usage'],
colorscale='Viridis')],
'layout': go.Layout(
xaxis = dict(title = 'Days'),
yaxis = dict( title = 'Hours'),
)})
]),])
#app.callback(
dash.dependencies.Output(component_id='heatmap',component_property='figure'),
[dash.dependencies.Input(component_id='Month_dropdown',component_property='value')]
)
def update_graph(Month_dropdown):
filtered_df = New[New['Month'] == Month_dropdown]
heat_fig = go.Heatmap(filtered_df,
x='Days', y='Hour', z='Usage',
colorscale='Viridis',
title='PM KWH Usage')
return heat_fig
have created New dataframe in the way you described it in comments
using dash 2.0.0 hence only need to import dash
two key steps missed
did not app.run_server() to start the dash app
no callback to respond to Dropdown
instead of repeating code in dash layout and callback moved figure creation to just the callback
import dash
from jupyter_dash import JupyterDash
import plotly.graph_objects as go
from dash.dependencies import Input, Output, State
import pandas as pd
import numpy as np
New = pd.DataFrame(
{"date": pd.date_range("1-jan-2021", "15-jun-2021", freq="H")}
).assign(
Usage=lambda d: np.random.uniform(0, 1, len(d)),
Month=lambda d: d["date"].dt.month,
Days=lambda d: d["date"].dt.day,
Hour=lambda d: d["date"].dt.hour,
)
Month_Default = New["Month"].unique()
Month_def = 2
# create the dash app
# app = dash.Dash()
app = JupyterDash(__name__)
app.layout = dash.html.Div(
[
dash.html.H1("//Title"),
dash.html.Div(
[
dash.html.Div(
[
dash.html.H4("Select Month..."),
dash.dcc.Dropdown(
id="Month_dropdown",
options=[{"label": i, "value": i} for i in Month_Default],
value=Month_def,
),
],
style={"width": "48%", "display": "inline-block"},
),
dash.dcc.Graph(id="heatmap"),
]
),
]
)
#app.callback(Output("heatmap", "figure"), Input("Month_dropdown", "value"))
def updateGraph(value):
if not value:
value = Month_def
return {
"data": [
go.Heatmap(
x=New["Days"].where(New["Month"] == value),
y=New["Hour"],
z=New["Usage"],
colorscale="Viridis",
)
],
"layout": go.Layout(
xaxis=dict(title="Days"),
yaxis=dict(title="Hours"),
margin={"l": 0, "r": 0, "t": 0, "b": 0},
),
}
app.run_server(mode="inline")

Spinning circle with transloadit. Is it possible with watermark or image rotation?

I'm trying to achieve a spinning circle with artwork as a mask.
From what I've seen there is no way to use a moving watermark or an automatic rotation of an image. Is it possible with transloadit?
The result should be a "vinyl" spinning.
This question is quite complex to answer, but it's very much do-able with Transloadit. I'll be using python to answer it primarily for OpenCV, but of course you can use a language that you prefer - I'll try and make it as language agnostic as possible.
I used 4 different templates to get the result we want, as well as some local python magic to tie everything together - here goes.
First we need to resize the image so it fits nicely onto the vinyl record.
{
"steps": {
":original": {
"robot": "/upload/handle"
},
"resize": {
"use": ":original",
"robot": "/image/resize",
"format": "png",
"resize_strategy": "fillcrop",
"width": 350,
"height": 350,
"imagemagick_stack": "v2.0.7"
}
}
}
Now, we want to mask this image using OpenCV and NumPy like so:
# Mask the image
# Reads the input image
img = cv2.imread(img_path)
# Creates a mask with the same size as the image
mask = np.zeros(img.shape, dtype=np.uint8)
# Creates a white circle in the centre
mask = cv2.circle(mask, (175, 175), 175, (255, 255, 255), -1)
# Makes a small whole in the centre of the mask
mask = cv2.circle(mask, (175, 175), 20, (0, 0, 0), -1)
result = cv2.bitwise_and(img, mask)
This will take an image, and create a mask for it that should look like a donut.
Then, using a bitwise and operation between the image and the mask you end up with a cookie cutter of the original image
Yet we still need to remove the black background - which is what we use this template for:
{
"steps": {
":original": {
"robot": "/upload/handle"
},
"trimmed": {
"use": ":original",
"robot": "/image/resize",
"alpha": "Activate",
"type": "TrueColor",
"transparent": "0,0,0",
"imagemagick_stack": "v2.0.7"
}
}
}
This will just make all black pixels transparent.
We can now use Transloadit's watermark feature to overlay this image onto our vinyl record
{
"steps": {
":original": {
"robot": "/upload/handle"
},
"watermark": {
"use": ":original",
"robot": "/image/resize",
"watermark_size": "33%",
"watermark_position": "center",
"imagemagick_stack": "v2.0.7"
}
}
}
Now, all that is left is to make it spin. What we can do is create say 60 frames, and have the image rotate, then using the /video/merge robot - to stitch it all together into a seamless GIF.
{
"steps": {
":original": {
"robot": "/upload/handle"
},
"rotate_image": {
"use": ":original",
"robot": "/image/resize",
"rotation": "${file.basename}",
"resize_strategy": "crop",
"imagemagick_stack": "v2.0.7"
},
"animated": {
"robot": "/video/merge",
"use": {
"steps": [
{
"name": "rotate_image",
"as": "image"
}
],
"bundle_steps": true
},
"result": true,
"ffmpeg_stack": "v4.3.1",
"ffmpeg": {
"f": "gif",
"pix_fmt": "rgb24"
}
}
}
}
Here I use the image's name to determine how many degrees to rotate it by - so when I'm uploading the files to the robot I will name the image based on its index in an array using this python code:
# Now we make a list of images that represent each frame
no_of_frames = 60
assembly = tl.new_assembly({'template_id': [SPINNING_VINYL_TEMPLATE_ID]})
directory = 'Assets/Frames/{image}'.format(image=img_name)
# Length of our animation in seconds
length = 2
for i in range(no_of_frames):
if not os.path.exists(directory):
os.mkdir(directory)
# Creates an image based on the index in the animation
# We pass this to the robot so it knows how many degrees to rotate the image by
location = '{directory}/{index}.png'.format(directory=directory, index=round(i*360/no_of_frames))
cv2.imwrite(location, finished_vinyl)
assembly.add_file(open(location, 'rb'))
This is my end result

node-graphviz does not generate the expected png file

I am new to node-graphviz, which is a Node.js interface to the GraphViz graphing tool.
I want to draw a directed graph and save it into memory using the code:
var graphviz = require('graphviz');
var debug = true;
function draw (hbGraph) {
/** Create the digraph */
var vGraph = graphviz.digraph('Happens-Before-Graph'),
eventNodes = {};
/** Create nodes for digraph */
for (var i = 0; i < hbGraph.eventNodes.length; i++) {
/** Note, eventNodes is a sparse array */
var event = hbGraph.eventNodes[i];
if (event != undefined) {
var node = vGraph.addNode(event.id, {
'color': common.COLOR.GREY,
'style': common.STYLE,
});
eventNodes[node.id] = node;
}
}
/** Create edges for digraph, just ignore for this question */
if (debug) {
// Create digraph G
var g = graphviz.digraph("G");
// Add node (ID: Hello)
var n1 = g.addNode( "Hello", {"color" : "blue"} );
n1.set( "style", "filled" );
// Add node (ID: World)
g.addNode( "World" );
// Add edge between the two nodes
var e = g.addEdge( n1, "World" );
e.set( "color", "red" );
// Print the dot script
console.log( g.to_dot() );
// Set GraphViz path (if not in your path)
g.setGraphVizPath( "/usr/local/bin" );
// Generate a PNG output
g.output( "png", "test01.png" );
}
console.log( vGraph.to_dot() );
vGraph.setGraphVizPath( "/usr/local/bin" );
vGraph.output('png', 'test02.png');
}
After running the code, file test01.png is generated while file test02.png is not without any exception. Both two results of to_dot() methods are successfully printed on the console.
The printout of to_dot() method for test02.png is:
digraph Happens-Before-Graph {
"1" [ color = "grey" ];
"7" [ color = "grey" ];
"8" [ color = "grey" ];
"9" [ color = "grey" ];
"10" [ color = "grey" ];
"11" [ color = "grey" ];
"12" [ color = "grey" ];
"13" [ color = "grey" ];
"14" [ color = "grey" ];
}
I want to why file test02.png is not generated and how it can be generated. Could anyone help me?
In addition, the documenation about this library cannot be generated, so I am unfamiliar with it.
Additional information: link to node-graphviz is node-graphviz
The answer is just to remove the minus sign - in the digraph.
Since the documentation of node-graphviz cannot be built, I just post the right answer here.

How to change settings input background color in vscode?

I want to change the background color of input in settings. I tried doing "input.background": "#1D1F22". But it's not working. Search bar in settings does reflect the new background. However, the any of the input in settings won't change the background color.
Here's my color customization settings (basically I just combined vscode default dark and one dark pro theme):
{
"workbench.colorCustomizations": {
"[Default Dark+]": {
"activityBar.background": "#282c34",
"activityBar.foreground": "#d7dae0",
"activityBarBadge.background": "#4d78cc",
"activityBarBadge.foreground": "#f8fafd",
"badge.background": "#282c34",
"button.background": "#404754",
"debugToolBar.background": "#21252b",
"diffEditor.insertedTextBackground": "#00809b33",
"dropdown.background": "#282c34",
"dropdown.border": "#21252b",
"editor.background": "#20252B",
"editor.foreground": "#D4D4D4",
"editorError.foreground": "#c24038",
"editorIndentGuide.activeBackground": "#c8c8c859",
"editorMarkerNavigation.background": "#21252b",
"editorRuler.foreground": "#abb2bf26",
"editorWarning.foreground": "#d19a66",
"editor.lineHighlightBackground": "#2c313c",
"editor.selectionBackground": "#67769660",
"editor.selectionHighlightBackground": "#ffffff10",
"editor.selectionHighlightBorder": "#ddd",
"editorCursor.background": "#ffffffc9",
"editorCursor.foreground": "#528bff",
"editorBracketMatch.border": "#515a6b",
"editorBracketMatch.background": "#515a6b",
"editor.findMatchBackground": "#42557b",
"editor.findMatchBorder": "#457dff",
"editor.findMatchHighlightBackground": "#6199ff2f",
"editor.wordHighlightBackground": "#d2e0ff2f",
"editor.wordHighlightBorder": "#7f848e",
"editor.wordHighlightStrongBackground": "#abb2bf26",
"editor.wordHighlightStrongBorder": "#7f848e",
"editorGroup.border": "#181a1f",
"editorGroupHeader.tabsBackground": "#21252b",
"editorIndentGuide.background": "#3b4048",
"editorLineNumber.foreground": "#495162",
// "editorActiveLineNumber.activeForeground": "#737984",
"editorWhitespace.foreground": "#3b4048",
"editorHoverWidget.background": "#21252b",
"editorHoverWidget.border": "#181a1f",
"editorSuggestWidget.background": "#21252b",
"editorSuggestWidget.border": "#181a1f",
"editorSuggestWidget.selectedBackground": "#2c313a",
"editorWidget.background": "#21252b",
"focusBorder": "#464646",
"input.background": "#1d1f23",
"list.activeSelectionBackground": "#2c313a",
"list.activeSelectionForeground": "#d7dae0",
"list.focusBackground": "#383e4a",
"list.hoverBackground": "#292d35",
"list.highlightForeground": "#c5c5c5",
"list.inactiveSelectionBackground": "#2c313a",
"list.inactiveSelectionForeground": "#d7dae0",
"list.warningForeground": "#d19a66",
"menu.foreground": "#c8c8c8",
"peekViewEditor.background": "#1b1d23",
"peekViewEditor.matchHighlightBackground": "#29244b",
"peekViewResult.background": "#22262b",
"scrollbarSlider.background": "#4e566660",
"scrollbarSlider.activeBackground": "#747d9180",
"scrollbarSlider.hoverBackground": "#5a637580",
"sideBar.background": "#20252B",
"sideBarSectionHeader.background": "#282c34",
"statusBar.background": "#282c34",
"statusBar.foreground": "#9da5b4",
"statusBarItem.hoverBackground": "#2c313a",
"statusBar.noFolderBackground": "#282c34",
"statusBar.debuggingBackground": "#7e0097",
"statusBar.debuggingBorder": "#66017a",
"statusBar.debuggingForeground": "#ffffff",
"statusBarItem.remoteForeground": "#f8fafd",
"statusBarItem.remoteBackground": "#4d78cc",
"tab.activeBackground": "#282c34",
"tab.activeForeground": "#dcdcdc",
"tab.border": "#181a1f",
"tab.inactiveBackground": "#21252b",
"tab.hoverBackground": "#323842",
"tab.unfocusedHoverBackground": "#323842",
"terminal.foreground": "#c8c8c8",
"terminal.ansiBlack": "#2d3139",
"terminal.ansiBlue": "#61afef",
"terminal.ansiGreen": "#98c379",
"terminal.ansiYellow": "#e5c07b",
"terminal.ansiCyan": "#56b6c2",
"terminal.ansiMagenta": "#c678dd",
"terminal.ansiRed": "#e06c75",
"terminal.ansiWhite": "#d7dae0",
"terminal.ansiBrightBlack": "#7f848e",
"terminal.ansiBrightBlue": "#528bff",
"terminal.ansiBrightGreen": "#98c379",
"terminal.ansiBrightYellow": "#e5c07b",
"terminal.ansiBrightCyan": "#56b6c2",
"terminal.ansiBrightMagenta": "#7e0097",
"terminal.ansiBrightRed": "#f44747",
"terminal.ansiBrightWhite": "#d7dae0",
"titleBar.activeBackground": "#282c34",
"titleBar.activeForeground": "#9da5b4",
"titleBar.inactiveBackground": "#21252b",
"titleBar.inactiveForeground": "#6b717d",
"textLink.foreground": "#61afef",
"sideBar.border": "#282c34",
"breadcrumb.background": "#282c34"
}
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.tokenColorCustomizations": {
"[Default Dark+]": {
"comments": "#7f848e",
"textMateRules": [
{
"name": "Comments",
"scope": "comment, punctuation.definition.comment",
"settings": {
"foreground": "#7f848e",
"fontStyle": "italic"
}
},
{
"name": "js/ts italic",
"scope": "entity.other.attribute-name.js,entity.other.attribute-name.ts,entity.other.attribute-name.jsx,entity.other.attribute-name.tsx,variable.parameter,variable.language.super",
"settings": {
"fontStyle": "italic"
}
}
]
}
}
}
In your specific case you want this colorCustomization:
"workbench.colorCustomizations": {
"settings.numberInputBackground": "#ff0000",
but also see these for similar option colors:
"settings.textInputBackground": "#00aeff",
"settings.checkboxBackground": "#ff0000",
"settings.dropdownBackground": "#ff0000",
Try typing settings in the colorCustomizations block and you will get the intellisense to show you more options, such as foreground colors, borders, modified indicators, etc.

Complex d3.nest() manipulation

I have an array of arrays that looks like this:
var arrays = [[1,2,3,4,5],
[1,2,6,4,5],
[1,3,6,4,5],
[1,2,3,6,5],
[1,7,5],
[1,7,3,5]]
I want to use d3.nest() or even just standard javascript to convert this data into a nested data structure that I can use with d3.partition.
Specifically, I want to create this flare.json data format.
The levels of the json object I want to create with d3.nest() correspond to the index positions in the array. Notice that 1 is in the first position in all the subarrays in the example data above; therefore, it is at root of the tree. At the next positions in the arrays there are three values, 2, 3, and 7, therefore, the root value 1 has 3 children. At this point the tree looks like this:
1
/ | \
2 3 7
At the third position in the subarrays there are four values, 3, 5, and 6. These children would be places into the tree as follows:
1
____|___
/ | \
2 3 7
/ \ / / \
3 6 6 3 5
How can I produce this data structure using d3.nest()? The full data structure with the example data I showed above should look like this:
{"label": 1,
"children": [
{"label": 2, "children": [
{"label": 3, "children": [
{"label": 4, "children": [
{"label": 5}
]},
{"label": 6, "children": [
{"label": 5}
]}
]},
{"label": 6, "children": [
{"label": 4, "children": [
{"label": 5}
]}
]},
{"label": 3, "children": [
{"label": 6, "children": [
{"label": 4, "children": [
{"label": 5}
]}
]}
]},
{"label": 7, "children": [
{"label": 3, "children": [
{"label": 5}
]},
{"label": 5}
]}
]}
]}
I'm trying to convert my array data structure above using something like this (very wrong):
var data = d3.nest()
.key(function(d, i) { return d.i; })
.rollup(function(d) { return d.length; })
I've been banging my head for a week to try and understand how I can produce this hierarchical data structure from an array of arrays. I'd be very grateful if someone could help me out.
#meetamit's answer in the comments is good, but in my case my tree is too deep to repeatedly apply .keys() to the data, so I cannot manually write a function like this.
Here's a more straightforward function that just uses nested for-loops to cycle through all the path instructions in each of your set of arrays.
To make it easier to find the child element with a given label, I have implemented children as a data object/associative array instead of a numbered array. If you want to be really robust, you could use a d3.map for the reasons described at that link, but if your labels are actually integers than that's not going to be a problem. Either way, it just means that when you need to access the children as an array (e.g., for the d3 layout functions), you have to specify a function to make an array out of the values of the object -- the d3.values(object) utility function does it for you.
The key code:
var root={},
path, node, next, i,j, N, M;
for (i = 0, N=arrays.length; i<N; i++){
//for each path in the data array
path = arrays[i];
node = root; //start the path from the root
for (j=0,M=path.length; j<M; j++){
//follow the path through the tree
//creating new nodes as necessary
if (!node.children){
//undefined, so create it:
node.children = {};
//children is defined as an object
//(not array) to allow named keys
}
next = node.children[path[j]];
//find the child node whose key matches
//the label of this step in the path
if (!next) {
//undefined, so create
next = node.children[path[j]] =
{label:path[j]};
}
node = next;
// step down the tree before analyzing the
// next step in the path.
}
}
Implemented with your sample data array and a basic cluster dendogram charting method:
http://fiddle.jshell.net/KWc73/
Edited to add:
As mentioned in the comments, to get the output looking exactly as requested:
Access the data's root object from the default root object's children array.
Use a recursive function to cycle through the tree, replacing the children objects with children arrays.
Like this:
root = d3.values(root.children)[0];
//this is the root from the original data,
//assuming all paths start from one root, like in the example data
//recurse through the tree, turning the child
//objects into arrays
function childrenToArray(n){
if (n.children) {
//this node has children
n.children = d3.values(n.children);
//convert to array
n.children.forEach(childrenToArray);
//recurse down tree
}
}
childrenToArray(root);
Updated fiddle:
http://fiddle.jshell.net/KWc73/1/
If you extend the specification of Array, it's not actually that complex. The basic idea is to build up the tree level by level, taking each array element at a time and comparing to the previous one. This is the code (minus extensions):
function process(prevs, i) {
var vals = arrays.filter(function(d) { return prevs === null || d.slice(0, i).compare(prevs); })
.map(function(d) { return d[i]; }).getUnique();
return vals.map(function(d) {
var ret = { label: d }
if(i < arrays.map(function(d) { return d.length; }).max() - 1) {
tmp = process(prevs === null ? [d] : prevs.concat([d]), i+1);
if(tmp.filter(function(d) { return d.label != undefined; }).length > 0)
ret.children = tmp;
}
return ret;
});
}
No guarantees that it won't break for edge cases, but it seems to work fine with your data.
Complete jsfiddle here.
Some more detailed explanations:
First, we get the arrays that are relevant for the current path. This is done by filtering out those that are not the same as prevs, which is our current (partial) path. At the start, prevs is null and nothing is filtered.
For these arrays, we get the values that corresponds to the current level in the tree (the ith element). Duplicates are filtered. This is done by the .map() and .getUnique().
For each of the values we got this way, there will be a return value. So we iterate over them (vals.map()). For each, we set the label attribute. The rest of the code determines whether there are children and gets them through a recursive call. To do this, we first check whether there are elements left in the arrays, i.e. if we are at the deepest level of the tree. If so, we make the recursive call, passing in the new prev that includes the element we are currently processing and the next level (i+1). Finally, we check the result of this recursive call for empty elements -- if there are only empty children, we don't save them. This is necessary because not all of the arrays (i.e. not all of the paths) have the same length.
Since d3-collection has been deprecated in favor of d3.array, we can use d3.groups to achieve what used to work with d3.nest:
var input = [
[1, 2, 3, 4, 5],
[1, 2, 6, 4, 5],
[1, 3, 6, 4, 5],
[1, 2, 3, 6, 5],
[1, 7, 5],
[1, 7, 3, 5]
];
function process(arrays, depth) {
return d3.groups(arrays, d => d[depth]).map(x => {
if (
x[1].length > 1 || // if there is more than 1 child
(x[1].length == 1 && x[1][0][depth+1]) // if there is 1 child and the future depth is inferior to the child's length
)
return ({
"label": x[0],
"children": process(x[1], depth+1)
});
return ({ "label": x[0] }); // if there is no child
});
};
console.log(process(input, 0));
<script src="https://d3js.org/d3-array.v2.min.js"></script>
This:
Works as a recursion on the arrays' depths.
Each recursion step groups (d3.groups) its arrays on the array element whose index is equal to the depth.
Depending on whether there are children or not, the recursion stops.
Here is the intermediate result produced by d3.groups within a recursion step (grouping arrays on there 3rd element):
var input = [
[1, 2, 3, 4, 5],
[1, 2, 6, 4, 5],
[1, 2, 3, 6, 5]
];
console.log(d3.groups(input, d => d[2]));
<script src="https://d3js.org/d3-array.v2.min.js"></script>
Edit - fixed
Here is my solution
Pro:It is all in one go (doesn't need objects converting to arrays like above)
Pro:It keeps the size/value count
Pro:the output is EXACTLY the same as a d3 flare with children
Con:it is uglier, and likely less efficient
Big Thanks to previous comments for helping me work it out.
var data = [[1,2,3,4,5],
[1,2,6,4,5],
[1,3,6,4,5],
[1,2,3,6,5],
[1,7,5],
[1,7,3,5]]
var root = {"name":"flare", "children":[]} // the output
var node // pointer thingy
var row
// loop through array
for(var i=0;i<data.length;i++){
row = data[i];
node = root;
// loop through each field
for(var j=0;j<row.length;j++){
// set undefined to "null"
if (typeof row[j] !== 'undefined' && row[j] !== null) {
attribute = row[j]
}else{
attribute = "null"
}
// using underscore.js, does this field exist
if(_.where(node.children, {name:attribute}) == false ){
if(j < row.length -1){
// this is not the deepest field, so create a child with children
var oobj = {"name":attribute, "children":[] }
node.children.push(oobj)
node = node.children[node.children.length-1]
}else{
// this is the deepest we go, so set a starting size/value of 1
node.children.push({"name":attribute, "size":1 })
}
}else{
// the fields exists, but we need to find where
found = false
pos = 0
for(var k=0;k< node.children.length ;k++){
if(node.children[k]['name'] == attribute){
pos = k
found = true
break
}
}
if(!node.children[pos]['children']){
// if no key called children then we are at the deepest layer, increment
node.children[pos]['size'] = parseInt(node.children[pos]['size']) + 1
}else{
// we are not at the deepest, so move the pointer "node" and allow code to continue
node = node.children[pos]
}
}
}
}
// object here
console.log(root)
// stringified version to page
document.getElementById('output').innerHTML = JSON.stringify(root, null, 1);
Working examples
https://jsfiddle.net/7qaz062u/
Output
{ "name": "flare", "children": [ { "name": 1, "children": [ { "name": 2, "children": [ { "name": 3, "children": [ { "name": 4, "children": [ { "name": 5, "size": 1 } ] } ] }, { "name": 6, "children": [ { "name": 4, "children": [ { "name": 5, "size": 1 } ] } ] } ] }, { "name": 3, "children": [ { "name": 6, "children": [ { "name": 4, "children": [ { "name": 5, "size": 1 } ] } ] }, { "name": 3, "children": [ { "name": 6, "children": [ { "name": 5, "size": 1 } ] } ] } ] }, { "name": 7, "children": [ { "name": 5, "size": 1 }, { "name": 3, "children": [ { "name": 5, "size": 1 } ] } ] } ] } ] }

Resources