How to interpolate missing values in my chart? - javascript

I used this code (JSFiddle: http://jsfiddle.net/0zvq3gr7/):
var data = [
{ Date: "2015-09-14", DayOfMonth: 14, Type: "Views", Amount: 5, y1: 10, },
{ Date: "2015-09-14", DayOfMonth: 14, Type: "Likes", Amount: 2, y1: 15, },
{ Date: "2015-09-15", DayOfMonth: 15, Type: "Views", Amount: 10, y1: 35, },
// { Date: "2015-09-15", DayOfMonth: 15, Type: "Likes", Amount: 4, y1: 20, },
{ Date: "2015-09-16", DayOfMonth: 16, Type: "Views", Amount: 14, y1: 22, },
{ Date: "2015-09-16", DayOfMonth: 16, Type: "Likes", Amount: 10, y1: 22, },
{ Date: "2015-09-17", DayOfMonth: 27, Type: "Views", Amount: 20, y1: 22, },
{ Date: "2015-09-17", DayOfMonth: 27, Type: "Likes", Amount: 12, y1: 22, },
];
var svgWidth = $("#chart").width(),
svgHeight = $("#chart").height();
var svg = dimple.newSvg("#chart", svgWidth, svgHeight);
var chart = new dimple.chart(svg, data);
var xAxis = chart.addCategoryAxis("x", "DayOfMonth");
xAxis.title = null;
xAxis.addOrderRule("Date");
var yAxis = chart.addMeasureAxis("y", "Amount");
yAxis.title = null;
var series = chart.addSeries("Type", dimple.plot.area);
series.stacked = false;
//series.interpolation = "cardinal";
var legend = chart.addLegend(0, 20, 300, 20, "right");
chart.draw();
The result is this:
In the previous example I removed:
{ Date: "2015-09-15", DayOfMonth: 15, Type: "Likes", Amount: 4, y1: 20, }
from the data. Since for the "Likes" Type DayOfMonth 15 is missing there should be a straight line between DayOfMonth 14 and 16 for "Likes". I draw this in the following graphic:
How do I fix the wrong interpolation here?

You have two objects for DayOfMonth 15 . If you remove them both it will draw a linear line between 14 and 16. Look at this updated fiddle.
var data = [
{ Date: "2015-09-14", DayOfMonth: 14, Type: "Views", Amount: 5, y1: 10, },
{ Date: "2015-09-14", DayOfMonth: 14, Type: "Likes", Amount: 2, y1: 15, },
// { Date: "2015-09-15", DayOfMonth: 15, Type: "Views", Amount: 10, y1: 35, },
// { Date: "2015-09-15", DayOfMonth: 15, Type: "Likes", Amount: 4, y1: 20, },
{ Date: "2015-09-16", DayOfMonth: 16, Type: "Views", Amount: 14, y1: 22, },
{ Date: "2015-09-16", DayOfMonth: 16, Type: "Likes", Amount: 10, y1: 22, },
{ Date: "2015-09-17", DayOfMonth: 27, Type: "Views", Amount: 20, y1: 22, },
{ Date: "2015-09-17", DayOfMonth: 27, Type: "Likes", Amount: 12, y1: 22, },
];

Related

Highcharts drilldown doesn't work for 3+ levels

I want to have highchart drilldown with more than 3 levels.
Also, I have tried referring below articles, but I was not able to figure out.
Drilldown multiple levels Highchart
Highcharts - drill down to multiple series
I could do only till 3 levels. After that, bar is not clickable.
Not sure where the mistake is, but this is what I have done so far.
2 Level Drill down - Works fine
Multilevel - Works only till Month level, cannot filter Day level
https://jsfiddle.net/foodiepanda/2ec7d6fz/9/
Below is code (only jquery)
/*Start*/
$('#chart1').highcharts({
chart: {type: 'column'},
title: {text: 'Multi Drilldown'},
xAxis: {type: 'category'},
legend: {enabled: false},
plotOptions:
{
series:
{
dataLabels:
{
enabled: true, //Shown at top of column
}
}
},
series:
[
{
name: 'Year',
//colorByPoint: false,
data:
[
{name: '2019',y: 200,drilldown: '2019'}, //200 clicks in 2018
{name: '2020',y: 450,drilldown: '2020'}, //450 clicks in 2019
]
}
],
drilldown:
{
series:
[
{
id: '2019', //For 2019
name: 'Quarter', //Splitting 200 as 50,100,20,30
data:
[
{
name: 'Q1',
y: 50,
drilldown: 'Q1'
},
{
name: 'Q2',
y: 100,
drilldown: 'Q2'
},
{
name: 'Q3',
y: 20,
drilldown: 'Q3'
},
{
name: 'Q4',
y: 30,
drilldown: 'Q4'
}
]
},
{
id: 'Q1',
name: 'Month', //Splitting 50 as 10,30,20
data:
[
{
name: 'Jan',
y: 10,
drilldown: 'Jan'
},
{
name: 'Feb',
y: 30,
drilldown: 'Feb'
},
{
name: 'Mar',
y: 20,
drilldown: 'Mar'
}
]
},
{
id: 'Jan',
name: 'Day', //Splitting 10 as ...[days]
data:
[
{name:'1', y: 0},
{name:'2', y: 0},
{name:'3', y: 2},
{name:'4', y: 0},
{name:'5', y: 0},
{name:'6', y: 0},
{name:'7', y: 0},
{name:'8', y: 0},
{name:'9', y: 0},
{name:'10', y: 0},
{name:'11', y: 1},
{name:'12', y: 2},
{name:'13', y: 0},
{name:'14', y: 1},
{name:'15', y: 0},
{name:'16', y: 0},
{name:'17', y: 0},
{name:'18', y: 0},
{name:'19', y: 0},
{name:'20', y: 0},
{name:'21', y: 0},
{name:'22', y: 0},
{name:'23', y: 0},
{name:'24', y: 0},
{name:'25', y: 2},
{name:'26', y: 0},
{name:'27', y: 0},
{name:'28', y: 0},
{name:'29', y: 0},
{name:'30', y: 1},
{name:'31', y: 1}
]
},
{
id: 'Q2',
name: 'Month', //Splitting 100 as 80,10,10
data:
[
['Apr', 80],
['May', 10],
['Jun', 10]
]
},
{
id: 'Q3',
name: 'Month', //Splitting 20 as 5,10,5
data:
[
['Jul', 5],
['Aug', 10],
['Sep', 5]
]
},
{
id: 'Q4',
name: 'Month', //Splitting 30 as 5,15,10
data:
[
['Oct', 5],
['Nov', 15],
['Dec', 10]
]
},
//For 2020
{
id: '2020',
name: 'Quarter', //Splitting 450 as 50,100,50,250
data:
[
{
name: 'Q1',
y: 50,
drilldown: 'Q1'
},
{
name: 'Q2',
y: 100,
drilldown: 'Q2'
},
{
name: 'Q3',
y: 50,
drilldown: 'Q3'
},
{
name: 'Q4',
y: 250,
drilldown: 'Q4'
}
]
},
{
id: 'Q1',
name: 'Month', //Splitting 50 as 10,35,5
data:
[
['Jan', 10],
['Feb', 35],
['Mar', 5]
]
},
{
id: 'Q2',
name: 'Month', //Splitting 100 as 40,35,25
data:
[
['Apr', 40],
['May', 35],
['Jun', 25]
]
},
{
id: 'Q3',
name: 'Month', //Splitting 50 as 5,25,20
data:
[
['Jul', 5],
['Aug', 25],
['Sep', 20]
]
},
{
id: 'Q4',
name: 'Month', //Splitting 250 as 75,125,50
data:
[
['Oct', 75],
['Nov', 125],
['Dec', 50]
]
},
] //End Series
} //End Year Drilldown
}); //End Highchart function
//Explicitly change Y axis
var curChart = $('#chart1').highcharts();
curChart.yAxis[0].update({
title:{
text:"Number of Hits"
}
});
/*End*/
I was able to figure out what the issue was.
The name parameter and drilldown parameter were having same values.
I just renamed name parameter from 'Q1' to '_Q1' and it worked like a charm.
{
name: 'Q1',
y: 50,
drilldown: '_Q1'
}
Updated JSFiddle :
https://jsfiddle.net/foodiepanda/2ec7d6fz/11/

How to subtract or minus from two array of objects particular values?

To be silly I am here to ask a simple question which make me too much time
Here is sample data
const demo1 = [
{ count: 156, monthCount: 1, year: 2018 },
{ count: 165, monthCount: 2, year: 2018 },
{ count: 103, monthCount: 3, year: 2018 },
{ count: 60, monthCount: 4, year: 2018 }
]
const data2 = [
{ count: 100, monthCount: 1, year: 2019 },
{ count: 55, monthCount: 2, year: 2019 },
{ count: 99, monthCount: 3, year: 2019 },
{ count: 130, monthCount: 4, year: 2019 }
]
I want to get data3 which is data2 - data1 with its key
Expected Out put look like that
[
{count: 56, monthCount: 1 },
{count: 100, monthCount: 2 },
{count: 60, monthCount: 3 },
{count: 70, monthCount: 4 }
]
If you want to subtract data2 - data1, then you can do it through vanilla JavaScript. Let me show an example.
Your data:
const data1 = [
{ count: 156, monthCount: 1, year: 2018 },
{ count: 165, monthCount: 2, year: 2018 },
{ count: 103, monthCount: 3, year: 2018 },
{ count: 60, monthCount: 4, year: 2018 }
];
const data2 = [
{ count: 100, monthCount: 1, year: 2019 },
{ count: 55, monthCount: 2, year: 2019 },
{ count: 99, monthCount: 3, year: 2019 },
{ count: 130, monthCount: 4, year: 2019 }
];
An example:
const combined = data1.concat(data2);
console.log(`combined, not calculated`, combined);
const desired = [...combined.reduce((r, {monthCount, count}) => {
const key = monthCount;
const item = r.get(key) || Object.assign({}, {
count: 0,
monthCount: monthCount
});
if (item.count === 0)
item.count = -count;
else
item.count += +count;
return r.set(key, item);
}, new Map).values()];
console.log(`desired: `, desired)
OUTPUT:
[
{count: -56, monthCount: 1},
{count: -110, monthCount: 2},
{count: -4, monthCount: 3},
{count: 70, monthCount: 4},
]
const data1 = [
{ count: 156, monthCount: 1, year: 2018 },
{ count: 165, monthCount: 2, year: 2018 },
{ count: 103, monthCount: 3, year: 2018 },
{ count: 60, monthCount: 4, year: 2018 }
]
const data2 = [
{ count: 100, monthCount: 1, year: 2019 },
{ count: 55, monthCount: 2, year: 2019 },
{ count: 99, monthCount: 3, year: 2019 },
{ count: 130, monthCount: 4, year: 2019 }
];
const subtractData = (arrOne, arrTwo) => {
const newArr = []
arrOne.forEach((elOne) => {
arrTwo.forEach((elTwo) => {
if(elOne.monthCount === elTwo.monthCount){
const count = Math.abs(Number(elOne.count) - Number(elTwo.count));
const newObj = {
...elOne,
count
}
delete newObj.year;
newArr.push(newObj)
}
})
})
return newArr;
}
console.log(subtractData(data1, data2))

Highcharts: Stacked area drilldown to multiple series

I am trying to present a graph that shows the current progress with an ongoing project. So basically once you open the plot, it will show you a plot of Passed, Failed and not run test runs in a stacked area.
I want to drilldown on the main data (Passed, Failed, Not Run). I want to basically show the teams(s) that may have passed, failed, or not run. Let's say that you want to drill down on "Passed", once you click on "Passed", it should bring multiple series, each serie containing the team name and the amount of Passed tests.
JSfiddle: https://jsfiddle.net/9aqbLzar/3/
Demo:
Highcharts.Tick.prototype.drillable = function() {};
Highcharts.setOptions({
lang: {
drillUpText: '◁ Go back'
}
});
Highcharts.chart('container', {
chart: {
type: 'area'
},
xAxis: {
type: 'datetime',
tickmarkPlacement: 'on',
title: {
enabled: false
}
},
yAxis: {
allowDecimals: false,
title: {
text: "Test runs"
}
},
tooltip: {
shared: false
},
plotOptions: {
area: {
stacking: 'normal',
lineColor: null,
lineWidth: 1,
marker: {
enabled: false,
lineWidth: 1,
lineColor: null,
symbol: 'circle',
radius: 3
}
},
cursor: 'pointer',
trackByArea: true
},
series: [{
name: 'Passed',
data: [{
x: Date.UTC(2017, 09, 06),
y: 20,
drilldown: 'Passed'
}, {
x: Date.UTC(2017, 09, 07),
y: 21,
drilldown: 'Passed'
}, {
x: Date.UTC(2017, 09, 08),
y: 22,
drilldown: 'Passed'
}, {
x: Date.UTC(2017, 09, 09),
y: 23,
drilldown: 'Passed'
}]
},
{
name: 'Failed',
data: [{
x: Date.UTC(2017, 09, 06),
y: 6,
drilldown: 'Failed'
}, {
x: Date.UTC(2017, 09, 07),
y: 5,
drilldown: 'Failed'
}, {
x: Date.UTC(2017, 09, 08),
y: 4,
drilldown: 'Failed'
}, {
x: Date.UTC(2017, 09, 09),
y: 3,
drilldown: 'Failed'
}]
},
{
name: 'Not run',
data: [{
x: Date.UTC(2017, 09, 06),
y: 8,
drilldown: 'Not run'
}, {
x: Date.UTC(2017, 09, 07),
y: 7,
drilldown: 'Not run'
}, {
x: Date.UTC(2017, 09, 08),
y: 6,
drilldown: 'Not run'
}, {
x: Date.UTC(2017, 09, 09),
y: 5,
drilldown: 'Not run'
}]
}
],
drilldown: {
series: [{
id: 'Passed',
data: [{
x: Date.UTC(2017, 09, 11),
y: 1
}, {
x: Date.UTC(2017, 09, 12),
y: 2
}, {
x: Date.UTC(2017, 09, 13),
y: 3
}, {
x: Date.UTC(2017, 10, 14),
y: 5
}]
}, {
id: 'Failed',
data: [{
x: Date.UTC(2017, 09, 09),
y: 5
}, {
x: Date.UTC(2017, 09, 10),
y: 6
}, {
x: Date.UTC(2017, 09, 11),
y: 7
}, {
x: Date.UTC(2017, 10, 12),
y: 8
}, {
x: Date.UTC(2017, 10, 13),
y: 9
}]
}, {
id: 'Not run',
data: [{
x: Date.UTC(2017, 09, 09),
y: 5
}, {
x: Date.UTC(2017, 09, 10),
y: 6
}, {
x: Date.UTC(2017, 09, 11),
y: 7
}, {
x: Date.UTC(2017, 10, 12),
y: 8
}, {
x: Date.UTC(2017, 10, 13),
y: 9
}]
}]
}
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/drilldown.js"></script>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
First of all, you need to have multiple drilldown series for each series (e.g. three for the 'Passed', three for the 'Failed', three for the 'Not run'). Secondly, the only way to drilldown to more than one series is to add them on drilldown event with a function called addSingleSeriesAsDrilldown. When desired series are added all you need to do is to apply them with applyDrilldown function. Take a look at the example below and in case of any question, feel free to ask.
API Reference:
https://api.highcharts.com/highcharts/chart.events.drilldown
Example:
https://jsfiddle.net/7a6gh7vz/

Highchart - Area chart: customize tooltip

I am trying to customize the tooltip of area chart. I am using Highchart for this.
I am plotting 3 series in area chart. My requirement is to show tooltip at fixed location in chart which is top center. Now, when i put cursor at any point then tooltip should show all series name and their current value where the cursor is. Refer below image:
Currently i am able to show tooltip on top - center and putting mouse at any point is showing current series name and data but it is showing current series name in all 3 places.
Highchart option:
Highcharts.chart('container', {
chart: {
type: 'area'
},
title: {
text: 'ACCUMULATED WEALTH'
},
xAxis: {
categories: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
tickmarkPlacement: 'on',
crosshair: {
width: 1,
color: "#ccc"
},
title: {
enabled: false
}
},
yAxis: {
title: {
text: false
},
opposite: true,
labels: {
formatter: function() {
return '$' + this.value + 'k';
}
},
},
tooltip: {
backgroundColor: 'none',
borderWidth: 0,
shadow: false,
useHTML: true,
shared: true,
padding: 0,
split: false,
headerFormat: "",
pointFormat: '<table><tr><td>{point.y}</td><td>{point.y}</td><td>{point.y}</td></tr>' +
'<tr><td>{series.name}</td><td>{series.name}</td><td>{series.name}</td></tr></table>',
footerFormat: "",
positioner: function () {
return { x: 250, y: 25 };
}
},
plotOptions: {
area: {
stacking: 'normal',
lineColor: '#666666',
lineWidth: 1,
marker: {
lineWidth: 1,
lineColor: '#666666'
}
}
},
series: [{
name: 'Cash Flow',
data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
}, {
name: 'Appreciation',
data: [ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
}, {
name: 'Principal',
data: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33]
}]
});
Here is what i have tries so far:
https://jsfiddle.net/2pdossk7/13/
Please help. Thanks in advance!
It might be difficult to achieve the desired result without tooltip.formatter.
This is how you can build tooltip text in a formatter:
formatter: function(tooltip) {
const points = this.points;
let str = '<table><tr>';
points.forEach(point => {
str += '<td style="text-align:center">' + point.y + '</td>';
});
str += '</tr><tr>';
points.forEach(point => {
str += '<td><span style="font-size:20px;color:' + point.color + '">●</span> ' + point.series.name + '</td>';
});
str += '</tr></table>';
return str;
},
And position it in the center of the chart:
positioner: function () {
const chart = this.chart;
return { x: (chart.plotWidth + chart.marginRight - this.label.getBBox().width) / 2, y: chart.plotTop + 10 };
}
Example and output
https://jsfiddle.net/eb3ou25v/
You can achieve desired result using pointFormat method
This is how you can use this
pointFormat: '<table style="text-align:center; display: inline-block; background: white;"><tr><td>{point.y}</td></tr>' +
'<tr><td><span style="font-size:20px;color:{series.color}">●</span> {series.name}</td></tr></table>',
positioner: function () {
const chart = this.chart;
return { x: (chart.plotWidth + chart.marginRight - this.label.getBBox().width) / 2, y: chart.plotTop - 20 };
}
for jsfiddle example click here

javascript populate nested object from other nested object

I am rather new to JavaScript and I am following different tutorials at the moment. For visualisation of a d3js graph I like to restructure a small dataset so that the d3.layout.stack() function can deal with the data.
The original dataset looks as follows. Its an array of objects:
var dats = [{ apples: 5, oranges: 10, grapes: 22 },
{ apples: 4, oranges: 12, grapes: 28 },
{ apples: 2, oranges: 19, grapes: 32 },
{ apples: 7, oranges: 23, grapes: 35 },
{ apples: 23, oranges: 17, grapes: 43 }
];
The target object should look as follows. its an Array of Array of objects:
var finaldats = [
[{ x: 0, y: 5 },
{ x: 1, y: 4 },
{ x: 2, y: 2 },
{ x: 3, y: 7 },
{ x: 4, y: 23 }
],
[{ x: 0, y: 10 },
{ x: 1, y: 12 },
...
My approach so far:
var inner = {}
inner["x"] ;
inner["y"] ;
dats.forEach(function(d,i) {
inner["x"] = i
inner["y"] = dats[i].apples;
});
This produces: Object {x: 4, y: 23}
Its always the last element of the input array, which is fine, since the object is constantly overwritten in each iteration.
At the moment I fail to push these objects, being created in each iteration into an array.
I thought of something like this, but it does not work:
var inner = {}
inner["x"] ;
inner["y"] ;
var outer = [];
dats.forEach(function(d,i) {
inner["x"] = i
inner["y"] = dats[i].apples;
outer.push(inner);
});
Use map:
The map() method creates a new array with the results of calling a
provided function on every element in this array.
var dats = [{ apples: 5, oranges: 10, grapes: 22},
{ apples: 4, oranges: 12, grapes: 28},
{ apples: 2, oranges: 19, grapes: 32},
{ apples: 7, oranges: 23, grapes: 35},
{ apples: 23, oranges: 17, grapes: 43}
];
var inner = dats.map(function(d, i) {
return {
x: i,
y: d.apples
}
});
document.write('<pre>' + JSON.stringify(inner, 0, 4) + '</pre>');
Edit:
To get the result for all the Keys you can use below snippet:
var dats = [{ apples: 5, oranges: 10, grapes: 22},
{ apples: 4, oranges: 12, grapes: 28},
{ apples: 2, oranges: 19, grapes: 32},
{ apples: 7, oranges: 23, grapes: 35},
{ apples: 23, oranges: 17, grapes: 43}
];
var inner = dats.map((o) => {
return Object.keys(o)
}).reduce((prev, curr) => {
return prev.concat(curr)
}).filter((col, i, array) => {
return array.indexOf(col) === i
}).map(function(k) {
return dats.map(function(a, i) {
return {
x: i,
y: a[k]
};
});
});
document.write('<pre>' + JSON.stringify(inner, 0, 4) + '</pre>');
Read more about map
While the other solution features only a part of the solution, here the complete solution with an array for the keys and two nested Array#map(), one for the keys ['apples', 'oranges', 'grapes'] and one for the values in the dats.
var dats = [{ apples: 5, oranges: 10, grapes: 22 }, { apples: 4, oranges: 12, grapes: 28 }, { apples: 2, oranges: 19, grapes: 32 }, { apples: 7, oranges: 23, grapes: 35 }, { apples: 23, oranges: 17, grapes: 43 }],
finaldats = ['apples', 'oranges', 'grapes'].map(function (k) {
return dats.map(function (a, i) {
return { x: i, y: a[k] };
});
});
document.write('<pre>' + JSON.stringify(finaldats, 0, 4) + '</pre>');

Categories