Stacked D3 bar chart with multiple level - javascript

I want to create a responsive D3 bar chart using my JSON.
I tried pushing my values into an array and create a bar chart using the same array. But it didn't come out well. I don't know what I am missing.
Can anyone please help me with this?
JSON = {
"Resource 1": {
"metrics": [
{
"2021-04-07": {
"percent": {
"avg": 15,
"max": 30,
"min": 10
}
}
},
{
"2021-04-08": {
"percent": {
"avg": 30,
"max": 50,
"min": 12
}
}
},
{
"2021-04-09": {
"percent": {
"avg": 35,
"max": 60,
"min": 5
}
}
}
]
},
"Resource 2": {
"metrics": [
{
"2021-04-07": {
"percent": {
"avg": 30,
"max": 50,
"min": 10
}
}
},
{
"2021-04-08": {
"percent": {
"avg": 15,
"max": 30,
"min": 10
}
}
},
{
"2021-04-09": {
"percent": {
"avg": 27,
"max": 39,
"min": 15
}
}
}
]
}
}
My y-axis will be numeric with a maximum value = 100 and the x-axis will be a date.
1 whole bar = 1 Resource, each resource contains three segments (Minimum, Average, and Maximum) stacked one above the other.
Each date will have multiple resources. When the cursor moved to the minimum value of resource1 in one date, it should highlight all the minimum value of the same resource1 on others dates too.
While moving the cursor to the bar the tooltip should show the resource name with resource value like
Resource1
min: 10
I have attached my fiddle.
https://jsfiddle.net/oLqdrymh/
Thanks in advance.

Related

Javascript: Merge Array of Objects, summing values with same key

I already searched for my issue, however, i did not find something, that matches my needs. I want to merge (sum) multiple series of data into a single array. Any dataset that matches the key, shall be summed in the resulting array.
Please see sample data and expected result:
var power1 = [
{
"time": 10,
"power": 100
},
{
"time": 20,
"type": 200
},
{
"time": 30,
"type": 300
}
]
var power2 = [
{
"time": 20,
"type": 200
},
{
"time": 30,
"type": 300
},
{
"time": 40,
"type": 400
}
]
var result = [
{
"time": 10,
"type": 100
},
{
"time": 20,
"type": 400
},
{
"time": 30,
"type": 600
},
{
"time": 40,
"type": 400
}
]
Since this should happen with thousands of items, it should be reasonable fast. Could a Map as intermediate help here?
Thanks in advance
You can concat the two arrays and then perform a reduce operation over it with an object to store the values for each key.
var power1=[{time:10,type:100},{time:20,type:200},{time:30,type:300}],power2=[{time:20,type:200},{time:30,type:300},{time:40,type:400}];
const res = Object.values(
power1.concat(power2).reduce((acc, {type, time})=>{
(acc[time] ??= {time, type: 0}).type += type;
return acc;
}, {})
);
console.log(res);

Appending last JSON object to the previous in array

I have a function that is outputting an array of json objects, where the last one is unique in structure:
// multi
[
{ "min": 10, "max": 200, "sum": 580, "avg": 72.5 },
{ "min": 10, "max": 470, "sum": 8300, "avg": 103.75 },
{ "largest": 470 }
]
// single
[
{ "min": 20, "max": 190, "sum": 270, "avg": 90 },
{ "largest": 190 }
]
Is it possible to have it append the last part { "largest": n } to the other objects in the array?
So the output would be:
// multi
[ { "min": 10, "max": 200, "sum": 580, "avg": 72.5, "largest": 470 },
{ "min": 10, "max": 470, "sum": 8300, "avg": 103.75, "largest": 470 }
]
// single
[
{ "min": 20, "max": 190, "sum": 270, "avg": 90, "largest": 190 }
]
Here is a link to the snippet of code that outputs the above.
Slice the array to omit the last entry, then map each entry to merge in the last entry
function mergeLastEntry(arr) {
const last = arr[arr.length - 1] // get the last entry
// map each object (except the last) to merge in the `last` object
return arr.slice(0, -1).map(o => ({ ...o, ...last }))
}
const multi =[{"min":10,"max":200,"sum":580,"avg":72.5},{"min":10,"max":470,"sum":8300,"avg":103.75},{"largest":470}]
const single = [{"min":20,"max":190,"sum":270,"avg":90},{"largest":190}]
console.log("multi", mergeLastEntry(multi))
console.log("single", mergeLastEntry(single))
.as-console-wrapper { max-height: 100% !important; }

Group by id and get order by total count in mongoose express node js

I have a collection like that:
{
"_id": {
"$oid": "5f54b3333367b91bd09f4485"
},
"products": [
{
"_id": 20,
"name": "Türk Kahvesi",
"price": 8,
"count": 2
},
{
"_id": 22,
"name": "Dibek",
"price": 10,
"count": 2
},
{
"_id": 21,
"name": "Damla Sakızlı T.K.",
"price": 10,
"count": 1
}
],
"deskId": "5f53473611f7490d3c860ccd",
"waiterId": "1",
"deskName": "Ü2",
},
{
"_id": {
"$oid": "5f54af663367b91bd09f4483"
},
"products": [
{
"_id": 20,
"name": "Türk Kahvesi",
"price": 8,
"count": 1
},
{
"_id": 21,
"name": "Damla Sakızlı T.K.",
"price": 10,
"count": 1
},
{
"_id": 22,
"name": "Dibek",
"price": 10,
"count": 1
},
{
"_id": 23,
"name": "Menengiç",
"price": 10,
"count": 1
},
{
"_id": 25,
"name": "Double Espresso",
"price": 15,
"count": 6
}
],
"deskId": "5f53473611f7490d3c860ccd",
"waiterId": "1",
"deskName": "Ü2",
}
And my goal is, getting all data order and group by product._id and show totalPrice(price*count),products.name, _id and totalCount. This is actually to show us a report product by product. If you need any more information, Just ask. Sample result:
{
{
"_id": 20,
"name": "Türk Kahvesi",
"totalCount": 3,
"totalPrice": 24
},
{
"_id": 22,
"name": "Dibek",
"totalCount": 3,
"totalPrice": 30
},
{
"_id": 21,
"name": "Damla Sakızlı T.K.",
"totalCount": 2,
"totalPrice": 20
},
{
"_id": 23,
"name": "Menengiç",
"totalCount": 1,
"totalPrice": 10
},
{
"_id": 25,
"name": "Double Espresso",
"totalCount": 6,
"totalPrice": 90
}
}
We can use aggregate on something. Please help me.
I'm still new to MongoDB, but I think this aggregate pipeline is what you're looking for. That said this is the kind of thing you should research yourself using the documentation, but as long as you understand the thought process you'll learn something so it's all good!
[
{
$unwind: {
path: '$products',
// Here we are seperating each item in the products array of
// the user(I presumed your objects were users, or carts maybe)
// It will now be available to the next stage of the pipeline as
// a singular object for each item in the array,
// see the picture below for how this works practically.
}
},
{
$group: {
// Now we're going to restructure the object to
// center around the id field of the products, and
// at the same time we can add up the total price
// and count of each item.
_id: '$products.id', // This is the selector for the grouping process (in our case it's the id)
item: { $first: '$$ROOT.products' }, // this is me thinking you'll want access to the item in question for each total.
totalCount: { $sum: "$products.count" }, // adds to totalCount EACH $products.count that we have
totalPrice: { $sum: { $multiply: ["$products.price", '$products.count'] } }, // self explanatory
}
}
]
this is what unwind does to your array and object
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
NB I modified/removed some variable names(_id, oid) for practical reasons, you'll have to parse through which ones and this code will most likely not work right away if copy-pasted.

Custom label values for X axis in amcharts

Can I set Custom label values for X axis in amcharts js?
Type is xy.
On X axis I had labels 0, 10, 20, 30, 40, 50... Need to set 0, 1, 10, 100
You could just add the values into your data provider components, such as...
"dataProvider": [
{
"category": "0",
"column-1": 32
},
{
"category": "1"
},
{
"category": "10",
"column-1": 32
},
{
"category": "100"
},
{
"category": "1000",
"column-1": 14
}
];
To make the data on the chart start on the axis then ensure the "startOnAxis": true is within your categoryAxis section.
"categoryAxis":
{
"startOnAxis": true
}

How to select object in muti level array

I am attempting to get just the smiling array under tags then attributes. I have tried both to search and simply select. Every attempt results in an undefined variable. If you could explain how to select the smiling array that would be excellent!
{
"status": "success",
"photos": [{
"url": "http://tinyurl.com/673cksr",
"pid": "F#019cbdb135cff0880096136c4a0b9bad_3547b9aba738e",
"width": 375,
"height": 406,
"tags": [{
"uids": [],
"label": null,
"confirmed": false,
"manual": false,
"width": 30.67,
"height": 28.33,
"yaw": -16,
"roll": -1,
"pitch": 0,
"attributes": {
"face": {
"value": "true",
"confidence": 84
},
"smiling": {
"value": "false",
"confidence": 46
}
},
"points": null,
"similarities": null,
"tid": "TEMP_F#019cbdb135cff0880096136c00d500a7_3547b9aba738e_56.80_41.13_0_1",
"recognizable": true,
"center": {
"x": 56.8,
"y": 41.13
},
"eye_left": {
"x": 66.67,
"y": 35.71,
"confidence": 51,
"id": 449
},
"eye_right": {
"x": 50.67,
"y": 35.47,
"confidence": 57,
"id": 450
},
"mouth_center": {
"x": 60.8,
"y": 51.23,
"confidence": 53,
"id": 615
},
"nose": {
"x": 62.4,
"y": 42.61,
"confidence": 54,
"id": 403
}
}]
}],
"usage": {
"used": 21,
"remaining": 79,
"limit": 100,
"reset_time": 1390111833,
"reset_time_text": "Sun, 19 January 2014 06:10:33 +0000"
},
"operation_id": "edc2f994cd8c4f45b3bc5632fdb27824"
}
This particular code, will aggregate all the smiling attribute from the given object and return that as an Array.
map function will get smiling attribute from each and every tag
concat function will flatten all the attributes and returns a single array per photo.
reduce function will gather all the attributes all the photos and accumulate the result in result and that will be returned at the end.
var result = data.photos.reduce(function(result, currentPhoto) {
return result.concat(currentPhoto.tags.map(function(currentTag) {
return currentTag.attributes.smiling;
}));
}, []);
console.log(result);
Output
[ { value: 'false', confidence: 46 } ]
JSON.parse(json).photos[0].tags[0].attributes.smiling
obj.photos[0].tags[0].attributes.smiling
The best way would be to loop through the tags, instead of hardcoding 0 in there
obj.photos.forEach(function(photo){
photo.tags.forEach(function(tag){
tag.attributes.smiling; // here it is
});
});
It's a bit tricky since your JSON object is a mixture of objects and arrays, but here's how you would get to the "smiling" object (it's an object since there's no associative arrays in JavaScript):
var smiling_object = obj["photos"][0]["tags"][0]["attributes"]["smiling"];
Then you if you want to do something with it:
var some_var = smiling_object["value"];
var some_other_var = smiling_object["confidence"];
alert("The combined string is " + some_var + " and " + some_other_var);

Categories