Convert hard-coded data into automated data in Javascript Chart.js - javascript

I have a data variable that needs to be represented on a line chart in Chart.js in React app. I am showing train and test data on the same line chart.
The values for the train dataset and test dataset are as follows:
train(y-axis): [369, 438, 329, 435, 359, 345, 406, 469, 457, 499, 352, 336, 480, 499, 354]
test(y-axis): [354, 354, 354, 354, 354]
The values for the train dataset indices and test dataset indices are as follows:
train_idx(x-axis): [0, 1, 2, 3, 4, 5,6,7 ,8 9, 10, 11, 12, 13, 14]
test_idx(x-axis): [14, 15, 16, 17, 18] /
I have hard-coded the values for now and the code looks as follows:
const [data, setData] = useState({
labels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
datasets: [{
label: 'Train Dataset',
data: [{x: 0, y: 369},
{x: 1, y: 438},
{x: 2, y: 329},
{x: 3, y: 435},
{x: 4, y: 359},
{x: 5, y: 345},
{x: 6, y: 406},
{x: 7, y: 469},
{x: 8, y: 457},
{x: 9, y: 499},
{x: 10, y: 352},
{x: 11, y: 336},
{x: 12, y: 480},
{x: 13, y: 499},
{x: 14, y: 354}],
//data: [369, 438, 329, 435, 359, 345, 406, 469, 457, 499, 352, 336, 480, 499, 354],
borderColor: 'blue',
}, {
label: 'Test Dataset',
data: [{x: 14, y: 354},
{x: 15, y: 354},
{x: 16, y: 354},
{x: 17, y: 354},
{x: 18, y: 354}],
//data: [354, 354, 354, 354, 354],
type: 'line',
borderColor: 'purple',
}],
})
From the above data, I get a graph that looks like this:
Now, I need the same graph but without hard-coding the values like above.
Please help me. The resulting graph without hard-coding the values needs to look like the picture.

Related

Add multi color gradient for different points in d3.js

I have to add gradient inside a foot shape according to the value of a point inside the foot. I have X and Y coordinates of a point and a value is attached to it. According to the value I have to assign color gradient like in the picture below. Higher the value of a point, darker the area is
So far, I have created the foot and added 2 color gradient to the whole foot, but I am unable to add gradient like this in the picture. Below is what I have achieved. Please if anyone could help me to find any solution to this
Here is the Stackblitz Link
Sample data :
[
{sensor: 0, value: 7.4, x: 108, y: 406}
{sensor: 1, value: 8.1, x: 68, y: 412}
{sensor: 2, value: 3.6, x: 108, y: 346}
{sensor: 3, value: 4.5, x: 61, y: 350}
{sensor: 4, value: 0.5, x: 108, y: 280}
{sensor: 5, value: 1, x: 49, y: 288}
{sensor: 6, value: 1, x: 122, y: 200}
{sensor: 7, value: 0.5, x: 30, y: 218}
{sensor: 8, value: 3.3, x: 140, y: 109}
{sensor: 9, value: 3.4, x: 105, y: 114}
{sensor: 10, value: 2.7, x: 78, y: 119}
{sensor: 11, value: 2.3, x: 51, y: 124}
{sensor: 12, value: 1.6, x: 22, y: 136}
{sensor: 13, value: 3.5, x: 121, y: 41}
{sensor: 14, value: 1.2, x: 85, y: 45}
{sensor: 15, value: 1, x: 50, y: 59}
]
Here is a hit map with 'populated' data (based on average value of closest points):
Just add the mask of the foot contour...
const data = [
{sensor: 0, value: 7.4, x: 108, y: 406},
{sensor: 1, value: 8.1, x: 68, y: 412},
{sensor: 2, value: 3.6, x: 108, y: 346},
{sensor: 3, value: 4.5, x: 61, y: 350},
{sensor: 4, value: 0.5, x: 108, y: 280},
{sensor: 5, value: 1, x: 49, y: 288},
{sensor: 6, value: 1, x: 122, y: 200},
{sensor: 7, value: 0.5, x: 30, y: 218},
{sensor: 8, value: 3.3, x: 140, y: 109},
{sensor: 9, value: 3.4, x: 105, y: 114},
{sensor: 10, value: 2.7, x: 78, y: 119},
{sensor: 11, value: 2.3, x: 51, y: 124},
{sensor: 12, value: 1.6, x: 22, y: 136},
{sensor: 13, value: 3.5, x: 121, y: 41},
{sensor: 14, value: 1.2, x: 85, y: 45},
{sensor: 15, value: 1, x: 50, y: 59},
];
const populateData = (points, width, height, step) => {
const populated = [];
for (let x = 0; x < width; x += step)
for (let y = 0; y < height; y += step) {
const distances = points.map(p =>
({...p, distance: Math.hypot(p.x - x, p.y - y)})).filter(d => d.distance < 100);
const sum = distances.reduce((s, d) => s + 1 / d.distance, 0);
const value = distances.reduce((a, d) => a + 1 / sum / d.distance * d.value, 0);
populated.push({x, y, value});
}
return populated;
};
const pd = populateData(data, 300, 500, 10);
const RECT_SIZE = 20;
const getColor = v => `rgb(255,${255 - v * 25},0)`
const svg = d3.select('svg');
pd.forEach(d => {
svg.append('rect')
.attr('x', d.x - RECT_SIZE / 2)
.attr('y', d.y - RECT_SIZE / 2)
.attr('width', RECT_SIZE / 2)
.attr('height', RECT_SIZE / 2)
.style('fill', getColor(d.value));
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="300" height="500" />
Here is a simple plot with the data you provided:
If you have more points, it can be a more precise picture
const data = [
{sensor: 0, value: 7.4, x: 108, y: 406},
{sensor: 1, value: 8.1, x: 68, y: 412},
{sensor: 2, value: 3.6, x: 108, y: 346},
{sensor: 3, value: 4.5, x: 61, y: 350},
{sensor: 4, value: 0.5, x: 108, y: 280},
{sensor: 5, value: 1, x: 49, y: 288},
{sensor: 6, value: 1, x: 122, y: 200},
{sensor: 7, value: 0.5, x: 30, y: 218},
{sensor: 8, value: 3.3, x: 140, y: 109},
{sensor: 9, value: 3.4, x: 105, y: 114},
{sensor: 10, value: 2.7, x: 78, y: 119},
{sensor: 11, value: 2.3, x: 51, y: 124},
{sensor: 12, value: 1.6, x: 22, y: 136},
{sensor: 13, value: 3.5, x: 121, y: 41},
{sensor: 14, value: 1.2, x: 85, y: 45},
{sensor: 15, value: 1, x: 50, y: 59},
];
const RECT_SIZE = 20;
const getColor = v => `rgb(255,${255 - v * 25},0)`
const svg = d3.select('svg');
data.forEach(d => {
svg.append('rect')
.attr('x', d.x - RECT_SIZE / 2)
.attr('y', d.y - RECT_SIZE / 2)
.attr('width', RECT_SIZE / 2)
.attr('height', RECT_SIZE / 2)
.style('fill', getColor(d.value));
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="300" height="500" />

How to normalize a histogram with Danfo.js?

I need to get normalized histogram.
So in Danfo notebooks I tried syntax like this:
s = new dfd.Series([1, 3, 2, 2, 2, 6, 10, 10, 34, 40, 51, 90, 90, 90, 90, 1, 3, 2, 2, 2, 6, 10, 10, 34, 40, 51, 90, 90, 90, 90, 1, 3, 2, 2, 2, 6, 10, 10, 34, 40, 51, 90, 90, 90, 90, 1, 3, 2, 2, 2, 6, 10, 10, 34, 40, 51, 90, 90, 90, 90, 1, 3, 2, 2, 2, 6, 10, 10, 34, 40, 51, 90, 90, 90, 90, 75])
s.plot(this_div()).hist({histnorm: 'probability', layout: {title: 'Normalized Histogram'}})
But it looks like danfo.js ignores Plotly histnorm trace attribute.
So the question is: Is it possible to use Plotly trace attributes with danfojs's plots, and if it's possible then what is correct syntax for that?

find lowest and highest in array of object

I need to find 4 values in this order in a array of object:
lowest x & y
highest x and lowest y
highest x & y
highest y & lowest x
my object is like this :
object: [
{id: 1, x: 160, y: 160},
{id: 2, x: 192, y: 160},
{id: 3, x: 224, y: 160},
{id: 4, x: 224, y: 192},
{id: 5, x: 192, y: 192},
{id: 6, x: 160, y: 192},
{id: 7, x: 160, y: 224},
{id: 8, x: 192, y: 224},
{id: 9, x: 224, y: 224}
],
the result must be an array with those 4 object .
Thanks
This is not the complete answer; highest x and lowest y and vice versa remained but it might give other contributors some insights how to solve the problem:
const object = [
{id: 9, x: 224, y: 224},
{id: 2, x: 192, y: 160},
{id: 3, x: 224, y: 160},
{id: 4, x: 224, y: 192},
{id: 5, x: 192, y: 192},
{id: 6, x: 160, y: 192},
{id: 7, x: 160, y: 224},
{id: 8, x: 192, y: 224},
{id: 1, x: 160, y: 160},
{id: 9, x: 224, y: 224}
];
object.sort((objA, objB) => (objA.x * objA.y) - (objB.x * objB.y));
const HighestXAndHighestY = object[object.length-1];
const lowestXAndlowestY = object[0];
console.log(HighestXAndHighestY)
console.log(lowestXAndlowestY)

Highcharts Column Series: Centering categorized x-axis labels

I'm working on a histogram like column chart with React-JSX-Highcharts. I have 6 categories, 10 data points for 5 categories, and 30 data points for the 6 and final category. I'm trying to achieve having the tick marks start at each category, but have the category label, be centered inbetween the tick marks. I was able to achieve this by setting x-axis labels x: 150, however, I learned that is not responsive.
Here is what i'm looking to achieve:
Curious to hear if I'm (A) taking the wrong approach, (B) Using the wrong series type (I tried histogram, but my bins are by category so the results were stacked columns), or (C) if i'm close and if anyone can find a solution to responsively center the labels.
Highcharts.chart('container', {
chart: {
type: 'column'
},
xAxis: {
categories: [
"VERY LOW",
"LOW",
"MEDIUM",
"HIGH",
"VERY HIGH",
"EXTREMELY HIGH"
],
tickInterval: 10,
startOnTick: true,
tickMarkPlacement: 'between',
type: 'category',
endOnTick: false,
showTempty: true,
},
series: [{
data: [
{x: 0, name: 'VERY LOW', y: 0.2},
{x: 1, name: 'VERY LOW', y: 0.2},
{x: 2, name: 'VERY LOW', y: 0.8},
{x: 3, name: 'VERY LOW', y: 1},
{x: 4, name: 'VERY LOW', y: 1.1},
{x: 5, name: 'VERY LOW', y: 1.1},
{x: 6, name: 'VERY LOW', y: 1.3},
{x: 7, name: 'VERY LOW', y: 1.5},
{x: 8, name: 'VERY LOW', y: 2},
{x: 9, name: 'VERY LOW', y: 1.5},
{y: 2.1, x: 10, name: 'LOW'},
{y: 2.1, x: 11, name: 'LOW'},
{y: 2.4, x: 12, name: 'LOW'},
{y: 2.5, x: 13, name: 'LOW'},
{y: 2.1, x: 14, name: 'LOW'},
{y: 2.6, x: 15, name: 'LOW'},
{y: 2.0, x: 16, name: 'LOW'},
{y: 2.7, x: 17, name: 'LOW'},
{y: 2.9, x: 18, name: 'LOW'},
{y: 2.5, x: 19, name: 'LOW'},
{y: 2.5, x: 20, name: 'MEDIUM'},
{y: 3.3, x: 21, name: 'MEDIUM'},
{y: 3.0, x: 22, name: 'MEDIUM'},
{y: 2.9, x: 23, name: 'MEDIUM'},
{y: 2.8, x: 24, name: 'MEDIUM'},
{y: 2.6, x: 25, name: 'MEDIUM'},
{y: 2.5, x: 26, name: 'MEDIUM'},
{y: 2.1, x: 27, name: 'MEDIUM'},
{y: 2.2, x: 28, name: 'MEDIUM'},
{y: 2.2, x: 29, name: 'MEDIUM'},
{y: 2.2, x: 29, name: 'MEDIUM'},
{y: 2.0, x: 30, name: 'HIGH' },
{y: 2.0, x: 31, name: 'HIGH' },
{y: 1.5, x: 32, name: 'HIGH' },
{y: 1.3, x: 33, name: 'HIGH' },
{y: 1.2, x: 34, name: 'HIGH' },
{y: 1.1, x: 35, name: 'HIGH' },
{y: 1.1, x: 36, name: 'HIGH' },
{y: 1.0, x: 37, name: 'HIGH' },
{y: 0.9, x: 38, name: 'HIGH' },
{y: 0.7, x: 39, name: 'HIGH' },
{y: 3.1, x: 40, name: 'VERY HIGH'},
{y: 0.3, x: 41, name: "VERY HIGH"},
{y: 0.3, x: 42, name: "VERY HIGH"},
{y: 0.1, x: 43, name: "VERY HIGH"},
{y: 0.1, x: 44, name: "VERY HIGH"},
{y: 0.1, x: 45, name: "VERY HIGH"},
{y: 0, x: 46, name: "VERY HIGH"},
{y: 0, x: 47, name: "VERY HIGH"},
{y: 0, x: 48, name: "VERY HIGH"},
{y: 0, x: 49, name: "VERY HIGH"},
{y: 0.3, x: 50, name: "EXTREMELY HIGH"},
{y: 0.3, x: 51, name: "EXTREMELY HIGH"},
{y: 0.3, x: 52, name: "EXTREMELY HIGH"},
{y: 0.1, x: 53, name: "EXTREMELY HIGH"},
{y: 0.1, x: 54, name: "EXTREMELY HIGH"},
{y: 0.1, x: 55, name: "EXTREMELY HIGH"},
{y: 0, x: 56, name: "EXTREMELY HIGH"},
{y: 0, x: 57, name: "EXTREMELY HIGH"},
{y: 0, x: 58, name: "EXTREMELY HIGH"},
{y: 0, x: 59, name: "EXTREMELY HIGH"},
{y: 0, x: 60, name: "EXTREMELY HIGH"},
{y: 0, x: 61, name: "EXTREMELY HIGH"},
{y: 0, x: 62, name: "EXTREMELY HIGH"},
{y: 0, x: 63, name: "EXTREMELY HIGH"},
{y: 0, x: 64, name: "EXTREMELY HIGH"},
{y: 0, x: 65, name: "EXTREMELY HIGH"},
{y: 0, x: 66, name: "EXTREMELY HIGH"},
{y: 0, x: 67, name: "EXTREMELY HIGH"},
{y: 0, x: 68, name: "EXTREMELY HIGH"},
{y: 0, x: 69, name: "EXTREMELY HIGH"},
]
}]
});
JSFiddle
One way to do this in a responsive manner by using jQuery resize events to detect when the size of the chart has changed, and update dynamically after that (don't forget to include jQuery if you use this solution). Like this:
$(window).resize(function() {
setTimeout(function() {
chart.update({
xAxis: {
labels: {
x: chart.xAxis[0].len / (chart.xAxis[0].tickPositions.length * 2)
}
}
}, true)
}, 100)
});
I am using the same xAxis.labels.x value as you did, but I am calculating it dynamically.
chart.xAxis[0].len - is the length of the xAxis in pixels.
(chart.xAxis[0].tickPositions.length * 2) is the number of ticks on the xAxis, times 2 because we want to be in the center between two ticks, not at the tick marker.
setTimeout is used because if we update the page right as the user is resizing, the position will not be correct. So we wait 0.1 seconds and then update instead.
In addition to that, on the first render of the page, there is no resize event. So to take care of the resizing then, I used the highchart load event like this:
chart: {
type: 'column',
events: {
load: function() {
this.update({
xAxis: {
labels: {
x: this.xAxis[0].len / (this.xAxis[0].tickPositions.length * 2)
}
}
}, true)
}
}
},
The same update function, using this instead of chart because chart is not fully initialized yet.
var chart = Highcharts.chart('container', {
chart: {
type: 'column',
events: {
load: function() {
//Position the labels for the initial rendering
this.update({
xAxis: {
labels: {
x: this.xAxis[0].len / (this.xAxis[0].tickPositions.length * 2)
}
}
}, true)
}
}
},
xAxis: {
categories: [
"VERY LOW",
"LOW",
"MEDIUM",
"HIGH",
"VERY HIGH",
"EXTREMELY HIGH"
],
labels: {
rotation: 0,
},
tickInterval: 10,
startOnTick: true,
tickMarkPlacement: 'between',
type: 'category',
endOnTick: false,
showTempty: true,
},
series: [{
data: [
{x: 0, name: 'VERY LOW', y: 0.2},
{x: 1, name: 'VERY LOW', y: 0.2},
{x: 2, name: 'VERY LOW', y: 0.8},
{x: 3, name: 'VERY LOW', y: 1},
{x: 4, name: 'VERY LOW', y: 1.1},
{x: 5, name: 'VERY LOW', y: 1.1},
{x: 6, name: 'VERY LOW', y: 1.3},
{x: 7, name: 'VERY LOW', y: 1.5},
{x: 8, name: 'VERY LOW', y: 2},
{x: 9, name: 'VERY LOW', y: 1.5},
{y: 2.1, x: 10, name: 'LOW'},
{y: 2.1, x: 11, name: 'LOW'},
{y: 2.4, x: 12, name: 'LOW'},
{y: 2.5, x: 13, name: 'LOW'},
{y: 2.1, x: 14, name: 'LOW'},
{y: 2.6, x: 15, name: 'LOW'},
{y: 2.0, x: 16, name: 'LOW'},
{y: 2.7, x: 17, name: 'LOW'},
{y: 2.9, x: 18, name: 'LOW'},
{y: 2.5, x: 19, name: 'LOW'},
{y: 2.5, x: 20, name: 'MEDIUM'},
{y: 3.3, x: 21, name: 'MEDIUM'},
{y: 3.0, x: 22, name: 'MEDIUM'},
{y: 2.9, x: 23, name: 'MEDIUM'},
{y: 2.8, x: 24, name: 'MEDIUM'},
{y: 2.6, x: 25, name: 'MEDIUM'},
{y: 2.5, x: 26, name: 'MEDIUM'},
{y: 2.1, x: 27, name: 'MEDIUM'},
{y: 2.2, x: 28, name: 'MEDIUM'},
{y: 2.2, x: 29, name: 'MEDIUM'},
{y: 2.2, x: 29, name: 'MEDIUM'},
{y: 2.0, x: 30, name: 'HIGH' },
{y: 2.0, x: 31, name: 'HIGH' },
{y: 1.5, x: 32, name: 'HIGH' },
{y: 1.3, x: 33, name: 'HIGH' },
{y: 1.2, x: 34, name: 'HIGH' },
{y: 1.1, x: 35, name: 'HIGH' },
{y: 1.1, x: 36, name: 'HIGH' },
{y: 1.0, x: 37, name: 'HIGH' },
{y: 0.9, x: 38, name: 'HIGH' },
{y: 0.7, x: 39, name: 'HIGH' },
{y: 3.1, x: 40, name: 'VERY HIGH'},
{y: 0.3, x: 41, name: "VERY HIGH"},
{y: 0.3, x: 42, name: "VERY HIGH"},
{y: 0.1, x: 43, name: "VERY HIGH"},
{y: 0.1, x: 44, name: "VERY HIGH"},
{y: 0.1, x: 45, name: "VERY HIGH"},
{y: 0, x: 46, name: "VERY HIGH"},
{y: 0, x: 47, name: "VERY HIGH"},
{y: 0, x: 48, name: "VERY HIGH"},
{y: 0, x: 49, name: "VERY HIGH"},
{y: 0.3, x: 50, name: "EXTREMELY HIGH"},
{y: 0.3, x: 51, name: "EXTREMELY HIGH"},
{y: 0.3, x: 52, name: "EXTREMELY HIGH"},
{y: 0.1, x: 53, name: "EXTREMELY HIGH"},
{y: 0.1, x: 54, name: "EXTREMELY HIGH"},
{y: 0.1, x: 55, name: "EXTREMELY HIGH"},
{y: 0, x: 56, name: "EXTREMELY HIGH"},
{y: 0, x: 57, name: "EXTREMELY HIGH"},
{y: 0, x: 58, name: "EXTREMELY HIGH"},
{y: 0, x: 59, name: "EXTREMELY HIGH"},
{y: 0, x: 60, name: "EXTREMELY HIGH"},
{y: 0, x: 61, name: "EXTREMELY HIGH"},
{y: 0, x: 62, name: "EXTREMELY HIGH"},
{y: 0, x: 63, name: "EXTREMELY HIGH"},
{y: 0, x: 64, name: "EXTREMELY HIGH"},
{y: 0, x: 65, name: "EXTREMELY HIGH"},
{y: 0, x: 66, name: "EXTREMELY HIGH"},
{y: 0, x: 67, name: "EXTREMELY HIGH"},
{y: 0, x: 68, name: "EXTREMELY HIGH"},
{y: 0, x: 69, name: "EXTREMELY HIGH"},
]
}]
});
$(window).resize(function() {
setTimeout(function() {
chart.update({
xAxis: {
labels: {
x: chart.xAxis[0].len / (chart.xAxis[0].tickPositions.length * 2)
}
}
}, true)
}, 100)
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<div id="container" style="height: 400px"></div>
Working JSFiddle example: https://jsfiddle.net/ewolden/nLcveqp9/29/

boolean rectangles to polygon(s)

I am building something where I need to draw multiple rectangles, either adding them or subtracting them, and from that produce one or more polygons that represent the overall area enclosed. This would work like the thing you see in paint programs, etc, where you can create a selection by drawing rectangles and clicking the + or - button to determine whether to add or subtract from the current selected area.
I can do all the drawing code, but need to know how to convert an ordered series of rectangles, each with a mode of "add" or "subtract", into one or more polygons. Here is how I envision it being used:
var rectList = [
{x: 50, y: 40, w: 20, h: 30, mode: "+"},
{x: 24, y: 12, w: 14, h: 62, mode: "+"},
{x: 12, y: 30, w: 34, h: 14, mode: "-"},
{x: 22, y: 21, w: 45, h: 19, mode: "+"},
{x: 17, y: 20, w: 10, h: 21, mode: "+"}
];
var polygonList = getPolygonsFromRectangleList (rectList);
The polygonList might look like this (an array of arrays of points). (The numbers below are just made up and have nothing to do with the input above)
[
[
{x: 23, y: 12},
{x: 14, y: 12},
{x: 14, y: 36},
{x: 24, y: 36},
....
],
[
{x: 32, y: 45},
{x: 32, y: 22},
{x: 14, y: 22},
...
]
I imagine this must be a pretty standard graphics gem sort of thing.

Categories