Fine tuning hash to dynamically create ZingCharts treemap array - javascript

First: Thanks for reading, but there is a lot in this, it may be easier to see it in the CodePen examples that are linked at the bottom.
I recently asked a question about how to dynamically create an array for a treemap, and was pointed in the right direction. I have been able to do some simple manipulation to the hash table, but can't figure out how to do the final step.
Currently the treemap has 2 "levels", that was done like this:
var data=[{color:"blue",party:"Democratic",text:"California",value:55},{color:"blue",party:"Democratic",text:"Oregon",value:7},{color:"red",party:"Republican",text:"Texas",value:38},{color:"red",party:"Republican",text:"Georgia",value:16},{color:"grey",party:"Democratic",text:"Arizona",value:11}];
var result = data.reduce(function(hash) {
return function(prev, curr) {
if (hash[curr.color]) {
hash[curr.color].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
} else {
hash[curr.color] = {};
hash[curr.color].children = hash[curr.color].children || [];
prev.push({
text: curr.party,
style: {
backgroundColor: curr.color
},
children: hash[curr.color].children
});
hash[curr.color].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
}
return prev;
};
}(Object.create(null)), []);
Now, what I'm trying to do is bring an additional criteria and add another level. For example, under "Republican" and "Democratic" you'd have subcategories for "Likely", "Leaning", and "Tipping" but for "Toss Up" you wouldn't have any of those.
Here is the end result that I'm trying to make:
series: [{
text: "Democratic",
style: { "backgroundColor": "blue" },
children: [{
text: "Likely",
style: { "backgroundColor": "darkblue" },
children: [{
text: "Alabama",
value: 8,
style: { "backgroundColor": "darkblue" },
}, {
text: "New Mexico",
value: 14,
style: { "backgroundColor": "darkblue" },
}]
}, {
text: "Leaning",
style: { "backgroundColor": "blue" },
children: [{
text: "Florida",
value: 9,
style: { "backgroundColor": "blue" },
}, {
text: "North Carolina",
value: 6,
style: { "backgroundColor": "blue" },
}]
}, {
text: "Tipping",
style: { "backgroundColor": "lightblue" },
children: [{
text: "Utah",
value: 4,
style: { "backgroundColor": "lightblue" },
}, {
text: "Idaho",
value: 5,
style: { "backgroundColor": "lightblue" },
}]
}]
},
{ text: "Republican",
style: { "backgroundColor": "red" },
children: [{
text: "Likely",
style: { "backgroundColor": "darkred" },
children: [{
text: "alabama",
value: 13,
style: { "backgroundColor": "darkred" },
}, {
text: "New Mexico",
value: 14,
style: { "backgroundColor": "darkred" },
}]
}, {
text: "Leaning",
style: { "backgroundColor": "red" },
children: [{
text: "Florida",
value: 9,
style: { "backgroundColor": "red" },
}, {
text: "North Carolina",
value: 6,
style: { "backgroundColor": "red" },
}]
}, {
text: "Tipping",
style: { "backgroundColor": "lightred" },
children: [{
text: "Utah",
value: 27,
style: { "backgroundColor": "lightred" },
}, {
text: "Idaho",
value: 12,
style: { "backgroundColor": "lightred" },
}]
}]
}, {
text: "Toss Up",
style: { "backgroundColor": "grey" },
children: [{
text: "alabama",
value: 10,
style: { "backgroundColor": "grey" },
}, {
text: "New Mexico",
value: 14,
style: { "backgroundColor": "grey" },
}]
},
]
};
I have been trying to figure out how to modify the example I was given to do that, but have been failing for hours. I'm not sure what I should be looking up. I think in the Else statement inside the "prev.push" (line 2040 here) is where the adjustment should be happening, but I don't know how to implement it, I also suspect I need to change the whole approach.
var result = data.reduce(function(hash) {
return function(prev, curr) {
if (hash[curr.party]) {
console.log("if: " + curr.party + " " + curr.category);
hash[curr.party].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
}
else {
console.log("else: " + curr.party + " " + curr.category);
hash[curr.party] = {};
hash[curr.party].children = hash[curr.party].children || [];
hash[curr.party].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
prev.push({
text: curr.party,
style: {
backgroundColor: curr.color
},
children: hash[curr.party].children // children: [{ text: curr.category, children: [{ }] }]
});
hash[curr.category] = {};
hash[curr.category].children = hash[curr.category].children || [];
console.log("category");
prev.push({
text: curr.category,
style: {
backgroundColor: curr.color
},
children: hash[curr.category].children
});
}
return prev;
};
}(Object.create(null)), []);
To wrap up:
Here is a CodePen of the basic structure of the goal
Here is my current code

Earlier the classification was being done based on color, seeing your data I guess we can do it based on party now. As there is another level added to the tree, we can classify that based on category.
So there are many changes - see demo below:
var data = [{"text":"California","value":55,"color":"#000066","party":"Democratic","compare":1,"category":"Likely"},{"text":"Connecticut","value":7,"color":"#000066","party":"Democratic","compare":1,"category":"Likely"},{"text":"Colorado","value":9,"color":"#3333CC","party":"Democratic","compare":2,"category":"Leaning"},{"text":"Florida","value":29,"color":"#9999FF","party":"Democratic","compare":3,"category":"Tipping"},{"text":"Iowa","value":6,"color":"red","party":"Republican","compare":4,"category":"Likely"},{"text":"Alabama","value":9,"color":"#CC3333","party":"Republican","compare":5,"category":"Leaning"},{"text":"Alaska","value":3,"color":"#FF9999","party":"Republican","compare":6,"category":"Tipping"},{"text":"Arizona","value":11,"color":"#666666","party":"Toss-Up","compare":7,"category":"Toss Up"},{"text":"Texas","value":11,"color":"#666666","party":"Toss-Up","compare":7,"category":"Toss Up"}];
var result = data.reduce(function(hash) {
return function(prev, curr) {
if (!hash[curr.party]) {
hash[curr.party] = {};
hash[curr.party].children = hash[curr.party].children || [];
prev.push({
text: curr.party,
style: {
backgroundColor: curr.color
},
children: hash[curr.party].children
});
} else if (hash[curr.party] && hash[curr.party][curr.category]) {
hash[curr.party][curr.category].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
}
if (hash[curr.party] && !hash[curr.party][curr.category]) {
if (curr.category == "Toss Up") {
hash[curr.party].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
} else {
hash[curr.party][curr.category] = {};
hash[curr.party][curr.category].children = hash[curr.party][curr.category].children || [];
hash[curr.party].children.push({
text: curr.category,
style: {
backgroundColor: curr.color
},
children: hash[curr.party][curr.category].children
});
hash[curr.party][curr.category].children.push({
text: curr.text,
value: curr.value,
style: {
backgroundColor: curr.color
}
});
}
}
return prev;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper {top: 0;max-height: 100%!important;}

Related

Get trees closer together

I am using tree layout and I have multiple trees (multiple roots).
How can I get the trees to be packed together and fill the empty space using layout.
Here is an example of my trees:
unpacked trees image
I want them to be more like this:
packed trees image
here is my current layout:
let myDiagram = new go.Diagram("myDiagramDiv",
{
layout: new go.TreeLayout({
treeStyle: go.TreeLayout.StyleLastParents,
arrangement: go.TreeLayout.ArrangementHorizontal,
compaction: go.TreeLayout.CompactionBlock,
// properties for most of the tree:
angle: 90,
layerSpacing: 35,
// properties for the "last parents":
alternateAngle: 90,
alternateLayerSpacing: 35,
alternateAlignment: go.TreeLayout.AlignmentBus,
alternateNodeSpacing: 20,
})
});
#HumanTarget has the right idea. Here's an example:
<script type="module">
import * as go from "../release/go-module.js";
import { ArrangingLayout } from "../extensionsJSM/ArrangingLayout.js";
import { PackedLayout } from "../extensionsJSM/PackedLayout.js";
const $ = go.GraphObject.make;
const myDiagram =
$(go.Diagram, "myDiagramDiv",
{
layout: $(ArrangingLayout,
{
primaryLayout: $(go.TreeLayout, { angle: 90 }),
arrangingLayout: $(PackedLayout, { spacing: 10 }),
})
});
myDiagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape, { fill: "white" },
new go.Binding("fill", "color")),
$(go.TextBlock, { margin: 8 },
new go.Binding("text"))
);
myDiagram.model = new go.GraphLinksModel(
[
{ key: 1, text: "Alpha", color: "lightblue" },
{ key: 2, text: "Beta", color: "orange" },
{ key: 3, text: "Gamma", color: "lightgreen" },
{ key: 4, text: "Delta", color: "pink" },
{ key: 5, text: "Epsilon", color: "lightblue" },
{ key: 6, text: "Zeta", color: "orange" },
{ key: 7, text: "Eta", color: "lightgreen" },
{ key: 8, text: "Theta", color: "pink" },
{ key: 9, text: "Iota", color: "lightblue" },
{ key: 10, text: "Kappa", color: "orange" },
{ key: 11, text: "Lambda", color: "lightgreen" },
{ key: 12, text: "Mu", color: "pink" },
{ key: 13, text: "Nu", color: "lightblue" },
{ key: 14, text: "Xi", color: "orange" },
{ key: 15, text: "Omicron", color: "lightgreen" },
{ key: 16, text: "Pi", color: "pink" },
],
[
{ from: 1, to: 2 },
{ from: 1, to: 3 },
{ from: 4, to: 5 },
{ from: 4, to: 6 },
{ from: 6, to: 7 },
{ from: 8, to: 9 },
{ from: 9, to: 10 },
{ from: 11, to: 12 },
{ from: 13, to: 14 },
{ from: 13, to: 15 },
{ from: 13, to: 16 },
]);
</script>
Result:
But note that PackedLayout will treat each subtree as occupying a rectangular area, so it won't try to fit subtrees together where one or both of the subtrees has some empty space.

Echart Custom label in sunburst chart

option = {
tooltip: {},
series: {
label: { rotate: 'tangential', },
nodeClick: false,
radius: ['15%', '80%'],
type: 'sunburst',
sort: null,
data: [
{
name: "sun",
value: 3456,
itemStyle: { color: '#814175' },
label: { formatter: '{b}\n\n{c}' },
children: [{ name: '', value: 2221, itemStyle: { color: '#a4829d' }, }]
},
{
name: "mon",
value: 6555,
itemStyle: { color: '#498ce7' },
label: { formatter: '{b}\n\n{c}' },
children: [{ name: '', value: 5001, itemStyle: { color: '#79aefa' }, }]
},],
}
};
https://i.stack.imgur.com/lcA0o.jpg
This is my chart in the first picture.When i hover the chart the label was hide(second picture).
i need to show all label on hover.
The way to do this would be to assign the formatter for emphasis and downplay. You can have different formats for the default label, the label that is hovered and the non-hovered labels
series: [
{
type: 'sunburst',
data: [],
label: {
formatter: 'E.g. A \n{b}\n\n{c}'
},
emphasis: {
label: {
formatter: 'E.g. B \n{b}\n\n{c}'
}
},
downplay: {
label: {
formatter: 'E.g. C \n{b}\n\n{c}'
}
}
}
]

Add Title To Each Bubble in Packed Bubble Highcharts

I have a packed bubble chart that works great. I would like to add a title to each of the larger, separated bubbles. The title should always show and I would like it to be the name of the series. I'm using a split series.
The 'name' attribute shows up in the tooltip, but I would like it to always be displayed.
Here is the code to create the bubbles:
Highcharts.chart('bubble-split-chart', {
chart: {
type: 'packedbubble',
animation: false,
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 },
stops: [
[0, '#15191b'],
[1, '#15191b']
]
},
},
// remove hamburger button
exporting: {
enabled: false
},
// remove chart watermark (highcharts.com)
credits: {
enabled: false
},
title: {
text: '',
enabled: false
},
tooltip: {
useHTML: true,
pointFormat: '<b>{point.name}</b>'
},
plotOptions: {
packedbubble: {
minSize: '1%',
maxSize: '100%',
zMin: 1,
zMax: 400,
layoutAlgorithm: {
enableSimulation: false,
gravitationalConstant: 0.05,
splitSeries: true,
seriesInteraction: false,
dragBetweenSeries: false,
parentNodeLimit: true
}
},
legend: {
enabled: false
}
},
series: [{
name: 'Test',
data: [{
name: "Lorem",
value: 29.4,
color: 'red'
},
{
name: "Ipsum",
value: 34.1,
color: 'blue'
},
{
name: "Dolor",
value: 7.1,
color: 'green'
}],
}, {
name: 'Test 2',
data: [{
name: 'Lorem',
value: 300.1,
color: 'red'
},
{
name: 'Ipsum',
value: 20.7,
color: 'blue'
},
{
name: "Dolor",
value: 97.2,
color: 'green'
}],
}, {
name: 'Test 3',
data: [{
name: "Lorem",
value: 8.2,
color: 'red'
},
{
name: "Ipsum",
value: 9.2,
color: 'blue'
},
{
name: "Dolor",
value: 13.1,
color: 'green'
}],
}]
});
Is this possible? Also, if this is possible, how can I remove the name from the tooltip?
You can add the labels by using annotations or Highcharts.SVGRenderer class.
To remove the series name from tooltip set:
tooltip: {
headerFormat: '',
...
}
Live demo: http://jsfiddle.net/BlackLabel/6m4e8x0y/4771/
API Reference:
https://api.highcharts.com/class-reference/Highcharts.SVGRenderer
https://api.highcharts.com/highcharts/annotations
https://api.highcharts.com/highcharts/tooltip.headerFormat

Custom Dynamic color for echarts

I am using echarts for my data visualization.... I got the solution for static data from here.. But in my case I have dynamic data and don't know how to make it work. The data items changes from time to time. It is not always 3 items like below. It could be any number.
var option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed']
},
yAxis: {
type: 'value'
},
series: [{
data: [
{
value: 120,
itemStyle: {color: 'blue'},
},
{
value: 200,
itemStyle: {color: 'red'},
},
{
value: 150,
itemStyle: {color: 'green'},
}
],
type: 'bar'
}],
graph: {
color: colorPalette
}
};
Someone have any idea about this.
Any help is appreciated. Thanks
You can have an array of colors predefined and randomly pop a color from that array, for each bar you have to draw:
var colors = [
"blue",
"red",
"yellow",
"green",
"purple"
];
function popRandomColor(){
var rand = Math.random();
var color = colors[Math.floor(rand*colors.length)];
colors.splice(Math.floor(rand*colors.length), 1);
return color;
}
Then call popRandomColor() everytime you need a color from the color bank.
var option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed']
},
yAxis: {
type: 'value'
},
series: [{
data: [
{
value: 120,
itemStyle: {color: popRandomColor()},
},
{
value: 200,
itemStyle: {color: popRandomColor()},
},
{
value: 150,
itemStyle: {color: popRandomColor()},
}
],
type: 'bar'
}],
graph: {
color: colorPalette
}
};
Is dynamic data with different color you want? check below
// put any color you want in Array colors
var colors = [
"blue",
"red",
"green"
];
// can be any length
var data = [{
category: 'cate1',
value: 120
}, {
category: 'cate2',
value: 200
}, {
category: 'cate3',
value: 150
}, {
category: 'cate4',
value: 135
}, {
category: 'cate5',
value: 54
}]
let category = [];
let seriesData = data.map((item, index) => {
category.push(item.category);
return {
value: item.value,
itemStyle: {
color: colors[index % colors.length]
}
}
});
var option = {
xAxis: {
type: 'category',
data: category
},
yAxis: {
type: 'value'
},
series: [{
data: seriesData,
type: 'bar'
}]
};
You can use this function to generate any number of colors and use it to assign these dynamic colors to your pie chart:
export const getColorArray = (num) => {
const result = [];
for (let i = 0; i < num; i += 1) {
const letters = '0123456789ABCDEF'.split('');
let color = '#';
for (let j = 0; j < 6; j += 1) {
color += letters[Math.floor(Math.random() * 16)];
}
result.push(color);
}
return result;
};
You can call this function like:
...
series: [
{
name: "Nightingale Chart",
type: "pie",
radius: [50, 150],
center: ["50%", "50%"],
roseType: "area",
itemStyle: {
borderRadius: 8,
},
data: [
{ value: 40, name: "rose 1" },
{ value: 38, name: "rose 2" },
{ value: 32, name: "rose 3" },
{ value: 30, name: "rose 4" },
{ value: 28, name: "rose 5" },
{ value: 26, name: "rose 6" },
{ value: 22, name: "rose 7" },
{ value: 18, name: "rose 8" },
],
color: [...getColorArray(6)]
},
],
...

Add CSS or style to each node in swimlane (GOjs library)

I am currently using GOjs library's new graph which is the swimlane.
My problem is I want to add DIFFERENT styles to each node (like, one node has a bg-color of red, the other is blue, others are green and etc). Anyone knows how to do this?
Any help is greatly appreciated. Or anyone can suggest another library that does my thing.
As you haven't posted your code Ill be working off the swinlane examples (http://www.gojs.net/latest/samples/swimlanes.html).
If you have a look at the documentation for nodes (http://gojs.net/beta/intro/nodes.html) you can see how they are changing the color there.
diagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape, "Rectangle",
new go.Binding("fill", "color")),
$(go.TextBlock,
{ margin: 5 },
new go.Binding("text", "key"))
);
diagram.model.nodeDataArray = [
{ key: "Alpha", color: "lightblue" }
];
In the swimlane example they have the following relevant code:
myDiagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape, "Rectangle",
{ fill: "white", portId: "", cursor: "pointer", fromLinkable: true, toLinkable: true }),
$(go.TextBlock, { margin: 5 },
new go.Binding("text", "key")),
// limit dragging of Nodes to stay within the containing Group, defined above
{
dragComputation: stayInGroup,
mouseDrop: function (e, node) { // dropping a copy of some Nodes and Links onto this Node adds them to this Node's Group
if (!e.shift && !e.control) return; // cannot change groups with an unmodified drag-and-drop
var grp = node.containingGroup;
if (grp !== null) {
var ok = grp.addMembers(node.diagram.selection, true);
if (!ok) grp.diagram.currentTool.doCancel();
}
},
layoutConditions: go.Part.LayoutAdded | go.Part.LayoutNodeSized
}
);
myDiagram.model = new go.GraphLinksModel(
[ // node data
{ key: "Lane1", isGroup: true, color: "lightblue" },
{ key: "Lane2", isGroup: true, color: "lightgreen" },
{ key: "Lane3", isGroup: true, color: "lightyellow" },
{ key: "Lane4", isGroup: true, color: "orange" },
{ key: "oneA", group: "Lane1" },
{ key: "oneB", group: "Lane1" },
{ key: "oneC", group: "Lane1" },
{ key: "oneD", group: "Lane1" },
{ key: "twoA", group: "Lane2" },
{ key: "twoB", group: "Lane2" },
{ key: "twoC", group: "Lane2" },
{ key: "twoD", group: "Lane2" },
{ key: "twoE", group: "Lane2" },
{ key: "twoF", group: "Lane2" },
{ key: "twoG", group: "Lane2" },
{ key: "fourA", group: "Lane4" },
{ key: "fourB", group: "Lane4" },
{ key: "fourC", group: "Lane4" },
{ key: "fourD", group: "Lane4" },
],
[ // link data
{ from: "oneA", to: "oneB" },
{ from: "oneA", to: "oneC" },
{ from: "oneB", to: "oneD" },
{ from: "oneC", to: "oneD" },
{ from: "twoA", to: "twoB" },
{ from: "twoA", to: "twoC" },
{ from: "twoA", to: "twoF" },
{ from: "twoB", to: "twoD" },
{ from: "twoC", to: "twoD" },
{ from: "twoD", to: "twoG" },
{ from: "twoE", to: "twoG" },
{ from: "twoF", to: "twoG" },
{ from: "fourA", to: "fourB" },
{ from: "fourB", to: "fourC" },
{ from: "fourC", to: "fourD" }
]);
To allow each node their own fill color you change the line
{ fill: "white", portId: "", cursor: "pointer", fromLinkable: true, toLinkable: true }),
to
{ fill: "lightblue", portId: "", cursor: "pointer", fromLinkable: true, toLinkable: true },
new go.Binding("fill", "color")),
After making those changes you can then specify what fill colors you want in the node data. Note that I changed the original fill value above to lighblue. Now lightblue will be the default color if you do not specify a color for a node (fourD will be lightblue):
myDiagram.model = new go.GraphLinksModel(
[ // node data
{ key: "Lane1", isGroup: true, color: "lightblue" },
{ key: "Lane2", isGroup: true, color: "lightgreen" },
{ key: "Lane3", isGroup: true, color: "lightyellow" },
{ key: "Lane4", isGroup: true, color: "orange" },
{ key: "oneA", group: "Lane1", color: "green" },
{ key: "oneB", group: "Lane1", color: "red" },
{ key: "oneC", group: "Lane1", color: "yellow" },
{ key: "oneD", group: "Lane1", color: "purple" },
{ key: "twoA", group: "Lane2", color: "orange" },
{ key: "twoB", group: "Lane2", color: "green" },
{ key: "twoC", group: "Lane2", color: "red" },
{ key: "twoD", group: "Lane2", color: "yellow" },
{ key: "twoE", group: "Lane2", color: "purple" },
{ key: "twoF", group: "Lane2", color: "orange" },
{ key: "twoG", group: "Lane2", color: "green" },
{ key: "fourA", group: "Lane4", color: "red" },
{ key: "fourB", group: "Lane4", color: "yellow" },
{ key: "fourC", group: "Lane4", color: "purple" },
{ key: "fourD", group: "Lane4" },
],
[ // link data
{ from: "oneA", to: "oneB" },
{ from: "oneA", to: "oneC" },
{ from: "oneB", to: "oneD" },
{ from: "oneC", to: "oneD" },
{ from: "twoA", to: "twoB" },
{ from: "twoA", to: "twoC" },
{ from: "twoA", to: "twoF" },
{ from: "twoB", to: "twoD" },
{ from: "twoC", to: "twoD" },
{ from: "twoD", to: "twoG" },
{ from: "twoE", to: "twoG" },
{ from: "twoF", to: "twoG" },
{ from: "fourA", to: "fourB" },
{ from: "fourB", to: "fourC" },
{ from: "fourC", to: "fourD" }
]);

Categories