React Native how to create a VictoryPie from nested data - javascript

In my React Native application, I am accessing data from my store in the following form:
Array [
Checkout {
"date": 2020-12-27T13:24:08.734Z,
"id": "Sun Dec 27 2020 08:24:08 GMT-0500 (EST)",
"items": Array [
Object {
"productBrand": "Microsoft",
"productCategory": "Gaming",
"productId": "p1",
"productTitle": "Xbox",
"quantity": 2,
"x": 1.815,
},
Object {
"productBrand": "Apple",
"productCategory": "Computers",
"productId": "p2",
"productTitle": "MacBook Pro",
"quantity": 1,
"x": 1.905,
},
],
"total": 3.720,
},
Checkout {
"date": 2020-12-27T13:24:47.790Z,
"id": "Sun Dec 27 2020 08:24:47 GMT-0500 (EST)",
"items": Array [
Object {
"productBrand": "Apple",
"productCategory": "Computers",
"productId": "p2",
"productTitle": "MacBook Pro",
"quantity": 1,
"x": 1.905,
},
],
"total": 1.905,
},
]
I am trying to use VictoryPie to create a pie chart that shows productBrand weighted by the sum of x over all the objects. In this example, I would need a pie chart showing Microsoft and Apple, weighted by 1.815 and 2*1.905 = 3.81, respectively. Is there any way to do this without writing a separate function to calculate these sums? I would like the pie chart to update automatically every time new data is added to the store.
I tried this, where history is a variable containing the above array but no pie chart is produced.
<VictoryPie data={history} x={(data) => data.items.productBrand} y={(data) => data.items.x} />

See my working sample: https://codesandbox.io/s/react-victory-pie-chart-forked-kpe39?file=/src/index.js
Like this:
x="productBrand"
y={(data) => data.x * data.quantity}

For anyone trying to do something similar, I ended up extracting the data I needed by using a nested for loop within the useSelector hook:
const allBrands = useSelector(state => {
let allData = {};
for (const key1 in state.history.history) {
for (const key2 in state.history.history[key1].items) {
if (allData.hasOwnProperty(state.history.history[key1].items[key2].productBrand)) {
allData[state.history.history[key1].items[key2].productBrand] += state.history.history[key1].items[key2].x;
} else {
allData[state.history.history[key1].items[key2].productBrand] = state.history.history[key1].items[key2].x;
}
}
};
let dataArray = [];
for (const prop in allData) {
dataArray.push({ brand: prop, total: allData[prop] })
}
return dataArray
});
Passing allBrands to the VictoryPie data prop produced the correct pie chart.

Related

how to show multiple data labels on react highchart line chart?

i want to show below data (sample data from my api) on react highchart line chart. but i am confuse how to prepare this data. the chart should be look alike, at Aaxis all assignments name and at y axis if 4 assignment name then look at data each object have values array. so 4 assignment names means 4 charts with multiple data labels. look at below screen shot. first image is what my chart should look alike. the second screenshot is how my chart giving error data is not loading.i am also attaching codesandbox link. the data is too much i have total 30+ assignments names with array of datalabels but right now i am attaching only 4.
codesandbox link : https://codesandbox.io/s/customizable-react-dashboard-with-chart-fork-forked-15rfpq?file=/src/LineHighchart.js
my sample Data:
const data ={"data":[{"assignment_name":"assignment for oliver","0":26,"1":1,"2":70,"3":80,"4":100,"5":10,"6":0,"7":0},{"assignment_name":"assignment","0":25,"1":0,"2":19,"3":35,"4":310,"5":0,"6":0,"7":0},{"assignment_name":"assignment2","0":27,"1":20,"2":10,"3":30,"4":50,"5":90,"6":0,"7":0},
{"assignment_name":"assignment2","0":29,"1":0,"2":10,"3":0,"4":30,"5":0,"6":60,"7":10},
]}
I am not familiar with the react wrapper for Highcharts, but here is a plain vanilla Highcharts object to show a line graph with two series and five data points, which might help you dig further:
{
"chart": {
"height": 436
},
"xAxis": {
"categories": [
"2019-12-30",
"2020-01-06",
"2020-01-13",
"2020-01-20",
"2020-01-27",
],
"title": {
"text": "Week",
}
},
"series": [{
"name": "Count",
"type": "line",
"data": [ 6, 9, 7, 6, 5 ]
}, {
"name": "Slope",
"type": "spline",
"data": [ 5.9, 6.23, 6.57, 6.9, 7.23 ]
}
]
}
UPDATE:
Here is the answer for your comment question: "can u make array of object from my given data and then give that variable to series":
const data ={
"data": [
{"assignment_name":"assignment for oliver",
"0":26,"1":1,"2":70,"3":80,"4":100,"5":10,"6":0,"7":0},
{"assignment_name":"assignment",
"0":25,"1":0,"2":19,"3":35,"4":310,"5":0,"6":0,"7":0},
{"assignment_name":"assignment2",
"0":27,"1":20,"2":10,"3":30,"4":50,"5":90,"6":0,"7":0},
{"assignment_name":"assignment2",
"0":29,"1":0,"2":10,"3":0,"4":30,"5":0,"6":60,"7":10},
]
};
let categories = Object.keys(data.data[0]).filter(key => key.match(/^\d+$/));
let series = data.data.map(obj => {
return {
name: obj.assignment_name,
tyle: 'line',
data: categories.map(key => obj[key])
}
});
let chartObj = {
"chart": {
"height": 436
},
"xAxis": {
"categories": categories,
"title": {
"text": "Assignments",
}
},
"series": series
};
console.log(chartObj);

How to use Highcharts React to create chart with multiple lines for same XAxis?

I have a dataset containing a date value, and 3 other values. For example:
{
"minimum": "71",
"maximum": "74",
"meanAverage": "72",
"dateTime": "2018-03-28T13:46:00"
},
{
"minimum": "57",
"maximum": "87",
"meanAverage": "71",
"dateTime": "2018-03-28T18:00:01"
},
I'd like to create a chart using react highcharts with the dates in the x axis, and then 3 lines on the y axis showing the corresponding 3 values for all the dates.
So far I thought using 3 different arrays to pass to series.data. Each array would have the x value (date) and then the y value. For the minimuns, it would be:
['2018-03-28T13:46:00', '71']
['2018-03-28T18:00:01', '57']
...
And in the options object, I would have something like:
series: [
{
data: minimuns
},
{
data: maximuns
},
{
data: meanAverages
},
]
But this isn't working and I'm having some trouble finding the info to correctly do this. Any help?
You need to parse the json object into a suitable data format.
See the docs for accepted data formats:
https://api.highcharts.com/highcharts/series.line.data
Notice, that y value should be a number.
The example config:
const json = '[{"minimum": 71, "maximum": 74, "meanAverage": 72, "dateTime": "2018-03-28T13:46:00"}, {"minimum": 57,"maximum": 87, "meanAverage": 71, "dateTime": "2018-03-28T18:00:01"}]',
parsed = JSON.parse(json);
const minimum = [];
parsed.forEach(data => {
minimum.push([new Date(data.dateTime).getTime(), data.minimum])
})
const maximum = [];
parsed.forEach(data => {
maximum.push([new Date(data.dateTime).getTime(), data.maximum])
})
const meanAverage = [];
parsed.forEach(data => {
meanAverage.push([new Date(data.dateTime).getTime(), data.meanAverage])
})
Then you can use your data arrays as you expected:
series: [{
data: minimum
},
{
data: maximum
},
{
data: meanAverage
}
]
Demo:
https://jsfiddle.net/BlackLabel/2ncb83eh/

How do I create an unique dataset of json object literal in Javascript?

I want to get an output as an unique set of Categories array with the following output [Men,Woman].
Is there any way to do it in Javascript?
For example this my data
{
"products:"[
{
"id": 1,
"categories": {
"1": "Men",
},
},
{
"id": 2,
"categories": {
"1": "Men",
},
}, {
"id": 3,
"categories": {
"1": "Woman",
},
}
];
}
A simple 1 line answer would be
new Set(input.products.map(p => p.categories["1"]))
This is if you're expecting only key "1" in the categories object.
If it can have multiple categories then you can always do
const uniqueCategories = new Set();
input.products.forEach(p => uniqueCategories.add(...Object.values(p.categories)))
Now you can convert a Set into an array
PS: This is not a ReactJs problem but a pure JS question. You might want to remove the ReactJs tag from this question altogether.

Why does this delete information from both jsons

I try to delete information from a JSON but when i put the og JSON to a new variable and then delete some of the information from both
example:
fs = require('fs');
var name = 'Assets/signup.json';
var m = JSON.parse(fs.readFileSync(name).toString());
const originalJSON = m;
let newJSONFile = originalJSON;
console.log(originalJSON)
newJSONFile.members.splice(0, newJSONFile.members.length)
console.log(originalJSON)
so this code should from what i know that it will asign a new JSON and then delete the members from newJSONFile and keep the members in the originalJSON but when i console.log(originalJSON) it output the members to be empty and i dont understand why
What looks like is your newJSONFile and originalJSON are both the same.
The objects in JS, they refer to same location. Unlike primitives we cant make a copy simply by using =. You can read more about it here
We can create deep copies using spread and other ways const newJSONFile = {...originalJSON} but this will still not deep copy the nested objects.
I am not aware of the structure your JSON is so can't suggest best way to create a deep copy.
You can use clone functions from libraries like lodash
UPDATED:
Create a deep clone of your original JSON, instead of just creating a reference. Then you can delete from the clone, and retain the original:
/* YOUR JSON FILE */
const newJSON = {
"howToUse": ",,photos {name} {instagram}",
"date": "April 8, 2021",
"available": "true",
"members": [
{
"name": "TinyruthlessPC",
"instagram": "Xclusiv3_Tester",
"signupDate": "April 10, 2021"
},
{
"name": "Tinyruthless",
"instagram": "Xclusiv3_Photography",
"signupDate": "April 10, 2021"
},
{
"name": "Kade",
"instagram": "Kade_Sucks",
"signupDate":"April 11, 2021"
}
]
}
/* LOG OG JSON FILE */
console.log(newJSON);
/* DEEP CLONE JSON FILE - MAKES A COPY */
let deepCloneJSON = JSON.parse(JSON.stringify(newJSON));
/* DELETE FROM THE COPY, NOT THE ORIGINAL */
delete deepCloneJSON.members[1];
console.log(deepCloneJSON);
/* CHECK THE ORIGNAL IS STILL INTACT */
console.log(newJSON);
https://jsfiddle.net/pixelmedia/7j18y5sp/12/
Old responses due to vague question:
Your question seems rather confusing, but if you are trying to delete from your JSON, then use the following.
Example: This will delete the second, and leave the first (0).
delete originalJSON[1];
Another example:
Initial is: 1, 2, 3
const originalJSON = [1, 2, 3];
delete originalJSON[1];
console.log(originalJSON);
Expected output: 1, 3
Now updated to demonstrate with the additional information provided by the OP:
const newJSON = {
"howToUse": ",,photos {name} {instagram}",
"date": "April 8, 2021",
"available": "true",
"members": [
{
"name": "TinyruthlessPC",
"instagram": "Xclusiv3_Tester",
"signupDate": "April 10, 2021"
},
{
"name": "Tinyruthless",
"instagram": "Xclusiv3_Photography",
"signupDate": "April 10, 2021"
},
{
"name": "Kade",
"instagram": "Kade_Sucks",
"signupDate":"April 11, 2021"
}
]
}
delete newJSON.members[1];
console.log(newJSON);
Expected output: removed 'Tinyruthless'
JSFiddle: https://jsfiddle.net/pixelmedia/7j18y5sp/1/
so my json will look like this:
{
"howToUse": ",,photos {name} {instagram}",
"date": "April 8, 2021",
"available": "true",
"members": [
{
"name": "TinyruthlessPC",
"instagram": "Xclusiv3_Tester",
"signupDate": "April 10, 2021"
},
{
"name": "Tinyruthless",
"instagram": "Xclusiv3_Photography",
"signupDate": "April 10, 2021"
},
{
"name": "Kade",
"instagram": "Kade_Sucks",
"signupDate":"April 11, 2021"
}
]
}
and i want to make it so that i can go through it and then delete one of the members and keep the rest in the same order
so i thought that i could just do
console.log(`deleteing person`)
fs = require('fs');
var name = 'Assets/signup.json';
var m = JSON.parse(fs.readFileSync(name).toString());
const originalJSON = m;
let newJSONFile = originalJSON;
console.log(originalJSON)
newJSONFile.members.splice(0, newJSONFile.members.length)
console.log(originalJSON)
for(m in originalJSON.members) {
console.log(`for loop runs`)
if(originalJSON.members[m]['name'] !== args[0]) {
let addMember = {
"name": originalJSON.members[m]['name'],
"instagram": originalJSON.members[m]['instagram'],
"signupDate": originalJSON.members[m]['signupDate']
}
newJSONFile.members.push(addMember)
console.log(newJSONFile)
}else {
}
}
and it just deletes it from both
Hi I used below script for this scenario.
const orgObj = { foo: "foo", bar: [1, 2, 3] }
var clonedObj = Object.assign({}, orgObj);
clonedObj.bar = Array.from(clonedObj.bar);
clonedObj.bar.push(4);
console.log(orgObj)
console.log(clonedObj)
It will make complete saperate copy of you object and OrgObj will remain unchanged.

Javascript looping through elements and adding to table

I'm having trouble finding a solution that will help me loop through a bunch of elements and putting the chosen values into a table. I've been able to withdraw some values but the method isn't dynamic.
Here is an example:
var Table = {
"credit": {
"link": "site link",
"logoUrl": "logo url",
"message": "message"
},
"groups": [
{
"labels": [
{
"name": "Western Conference",
"type": "conference"
},
{
"name": "Central Division",
"type": "division"
}
],
"standings": [
{
"stats": [
{
"name": "gp",
"value": 20
},
{
"name": "w",
"value": 17
},
{
"name": "l",
"value": 0
},
{
"name": "gf",
"value": 64
},
{
"name": "ga",
"value": 37
},
{
"name": "gd",
"value": 27
},
{
"name": "pts",
"value": 37
}
],
"team": {
"id": 12345,
"link": "team link",
"name": "team name",
"shortName": "team"
}
},
This is the structure of the elements. So far I've used this:
document.getElementById("sGamesPlayed").innerHTML=Table.groups[0].standings[0].stats[0].value;
to withdraw values. However there are more teams, stats and divisions so I would need some kind of loop to go through the elements and put the into a dynamic table.
I would consider you to look at http://underscorejs.org/.
it provides a bunch of utility functions that could help you,
for example, _.each() helps you loop through JSON properties.
for the sample objects you've given (after completing the missing brackets at the end),
_.each(Table.groups[0].standings[0].stats, function(stats){
console.log(stats['name']+","+stats['value'])
})
gives me:
gp,20
w,17
l,0
gf,64
ga,37
gd,27
pts,37
how it works is that you provide the object you want as the first argument and the function that you give as the second argument will be called with each element of the first argument (Assuming it is a list).
I would also urge you to look at underscore templating that you can use to render your table where i put the console.log :
http://net.tutsplus.com/tutorials/javascript-ajax/getting-cozy-with-underscore-js/
http://scriptble.com/2011/01/28/underscore-js-templates/
I guess your question is about filtering the values of the array standings. In order to do that you can use the jQuery grep function (if you want to use jQuery).
For example you can write:
var arr = $.grep(Table.groups[0].standings[0].stats, function(d){return d.value>25})
Which will give
arr = [{"name": "gf","value": 64}, {"name": "ga", "value": 37},{"name": "gd", "value": 27},{"name": "pts", "value": 37}]
If this is not what you meant, can you please create a jsFiddle with a sample of what you want?
Depending on what you want to do with the results, you can go over the object using a scheme like:
var groups, standings, stats, value;
groups = Table.groups;
// Do stuff with groups
for (var i=0, iLen=groups.length; i<iLen; i++) {
standings = groups[i].standings;
// Do stuff with standings
for (var j=0, jLen=standings.length; j<jLen; j++) {
stats = standings[j];
// Do stuff with stats
for (var k=0, kLen=stats.length; k<kLen; k++) {
value = stats[k].value;
// Do stuff with value
}
}
}
Of course I have no idea what the data is for, what the overall structure is or how you want to present it. But if you have deeply nested data, all you can do is dig into it. You might be able to write a recursive function, but it might also become very difficult to maintain if the data structure is complex.

Categories

Resources