Issue While Passing Dynamic Datas in React Chart Js 2 - javascript

I have successfully passed dynamic datas to React Chart JS 2 but i am having problem displaying it.
Please find the attached screenshot of the chart.
I am trying to make a line chart for all the expenses vs month. As you can see there are two arrays that is visible in the console of the screenshot. One is of Amount spent and corresponding month it was spent can be seen in the array below it. Eg: 529 was spent on May and 100 was spent on April.
Here is my Chart.js
import React from 'react';
import {connect} from 'react-redux';
import {Line} from 'react-chartjs-2';
import moment from 'moment';
const Chart = (props) => {
console.log(props.expenses);
const amount = props.expenses.map((expense) => {
// console.log(expense.amount);
// console.log(moment(expense.createdAt).format('MMMM'));
return expense.amount;
});
console.log(amount);
const createdAt = props.expenses.map((expense) => {
const arr_createdAt = expense.createdAt;
return moment(arr_createdAt).format('MMMM');
});
console.log(createdAt);
const data = {
labels: **createdAt**,
datasets: [
{
label: 'My First dataset',
fill: false,
lineTension: 0.1,
backgroundColor: 'rgba(75,192,192,0.4)',
borderColor: 'rgba(75,192,192,1)',
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: 'rgba(75,192,192,1)',
pointBackgroundColor: '#fff',
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: 'rgba(75,192,192,1)',
pointHoverBorderColor: 'rgba(220,220,220,1)',
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: **amount**
}
]
};
return (
<div>
<div className = "page-header">
<div className = "content-container">
<h1 className = "page-header__title">CHART</h1>
</div>
</div>
<div className = "content-container">
<h2>Line Example</h2>
<Line data={data} />
</div>
</div>
)};
const mapStateToProps = (state) => {
return {
expenses : state.expenses
};
}
export default connect(mapStateToProps)(Chart);
What i want to do is bucket all the expenses that was spent on May and dispaly total expense sum in May Line and do same for other months as well.
Any help is much appreciated.
Thank You

Try this:
`let reducedValue = props.expenses.reduce((acc, item) => {
let index = acc.findIndex(accItem => moment(accItem.createdAt).format('MMM') === moment(item.createdAt).format('MMM'));
if(index < 0){
acc.push({...item});
} else {
acc[index].amount += item.amount;
}
return acc;
}, []);
let amount = reducedValue.map(item => item.amount);
let createdAt = reducedValue.map(item => moment(item.createdAt).format('MMM'));
`

Related

Is there a way to change the react-chart-js tooltip only on a graph?

I have the following:
const labels = historicosData.map(historico => {
const localDate = new Date(historico.fechaIngreso);
return localDate.toLocaleString('es-ES', { month: 'long' })
});
//const labels = historicosData.map(({ anio }) => anio);
// const labels = [123, 321, 456, 123, 4568]
const data = {
labels,
datasets: [
{
label: 'Valores históricos',
fill: false,
backgroundColor: 'rgba(75,192,192,0.4)',
borderColor: 'rgba(75,192,192,1)',
pointBorderColor: 'rgba(75,192,192,1)',
pointBackgroundColor: '#fff',
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: 'rgba(75,192,192,1)',
pointHoverBorderColor: 'rgba(220,220,220,1)',
pointHoverBorderWidth: 10,
pointRadius: 10,
pointHitRadius: 10,
data: historicosData.map(({ valor }) => valor),
},
],
};
And it displays the following graph:
Is there a way where I can change the default message of the tooltip (the one saying 'mayo') for a personalized message?
My main purpose is to make the X bottom axis to display only the months' name and display the whole date when the user's hover over one specific point
You can use the options prop as follows to customize the tooltip title:
const options = {
responsive: true,
plugins:
{
tooltip:
{
callbacks:
{
title: (context) =>
{
return context[0].label
},
}
},
},
}
Then pass options as a prop to your Line component:
<Line options = {options} data = {data} />
In the example above, I'm returning context[0].label which is the label you already see on the x-axis. You can change the return value to anything you want, and you can put other necessary logic within the callback as well.
For example, you may choose to return context[0].parsed.x rather than the label. Or you may choose to use this value to put together the final title to return.
Read more about tooltip configuration in the docs.

React-Chart-JS-2 ^3.0.5 | TypeError: Cannot read properties of undefined (reading 'visible') at Chart._getSortedDatasetMetas

I am making an Area chart with two datasets, and this mysterious error has popped up and stumped me. The chart will render and look fine, but will randomly error out and I'm not sure what is going wrong.
Chart Looks like this:
What the chart looks like
Screenshot of error:
Error Screenshot
Code to generate chart
const ChartWrapper = styled.div`
width: 100%;
height: 250px;
`;
const HomeSubmissionsChart = ({
submissions,
}) => {
const daySubmissions = getSubmissionsByDayStats(submissions)
const dataOne = Object.values(daySubmissions).map(obj => obj.subs);
const dataTwo = Object.values(daySubmissions).map(obj => obj.pass)
const chartData = (canvas) => {
const ctx = canvas.getContext('2d');
const gradient = ctx.createLinearGradient(0, 0, 0, 160);
gradient.addColorStop(0, 'rgba(158,158,158,0.5)');
gradient.addColorStop(1, 'rgba(158,158,158,0.16)');
const passedGradient = ctx.createLinearGradient(0, 0, 0, 160);
passedGradient.addColorStop(0, 'rgba(100,181,246,1)');
passedGradient.addColorStop(1, 'rgba(100,181,246,0.1)');
return {
labels: Object.keys(daySubmissions).map(val => format(new Date(val), 'MMM-dd')),
datasets: [
{
fill: {
target: 'origin',
above: gradient,
},
borderColor: 'rgba(158,158,158,.05)',
pointBorderColor: 'slategrey',
pointBorderWidth: 1,
tension: 0.4,
pointBackgroundColor: 'slategrey',
data: dataOne,
},
{
fill: {
target: 'origin',
above: passedGradient,
},
borderColor: 'rgba(100,181,246,.05)',
pointBorderColor: '#64b5f6',
pointBorderWidth: 1,
tension: 0.4,
pointBackgroundColor: '#64b5f6',
data: dataTwo,
},
],
};
};
return (
<Wrapper>
<Typography variant="subtitle2" mb={2}>
Engagement Last 14 Days
</Typography>
<LengendWrapper>
<LegendItem>
<LegendSubmission />
<span>
All Submissions
</span>
</LegendItem>
<LegendItem>
<LegendPassed />
<span>
Modules Passed
</span>
</LegendItem>
</LengendWrapper>
<ChartWrapper>
<Line data={chartData} options={options} />
</ChartWrapper>
</Wrapper>
)
};
Any help would be greatly appreciated!
Downgrading to version 3.0.4 fixed it for me.
There is an open issue for tracking: https://github.com/reactchartjs/react-chartjs-2/issues/735

Can anyone help me move data from an Axios JSON response to a plot points on a Chart js line chart?

I am working on building a React app that contains a line chart representing the timeline of data recordings from a certain point in time to present day. I am using the JS library Chart js. Specifically the 'react-chartjs-2' plugin. I am using the '/historical/all' path of the following API:
[https://corona.lmao.ninja/docs/?urls.primaryName=version%202.0.0#/][1]
I am successfully retrieving a response from the Axios GET request. But the structuring of the JSON being sent back to me is confusing me when it comes to the implementation I have been following to build the application. I have a lot of the scaffolding in place, but I am struggling to get the data from GET request function to the line chart.
The data is being sent in the following structure:
{
"cases": {
"3/21/20": 304507,
"3/22/20": 336953,
"3/23/20": 378231,
"3/24/20": 418041,
"3/25/20": 467653,
"3/26/20": 529591,
"3/27/20": 593291,
"3/28/20": 660693,
"3/29/20": 720140,
"3/30/20": 782389,
"3/31/20": 857487,
"4/1/20": 932605,
"4/2/20": 1013466,
"4/3/20": 1095917,
"4/4/20": 1176060,
"4/5/20": 1249754,
"4/6/20": 1321481,
"4/7/20": 1396476,
"4/8/20": 1480202,
"4/9/20": 1565278,
"4/10/20": 1657526,
"4/11/20": 1735650,
"4/12/20": 1834721,
"4/13/20": 1904838,
"4/14/20": 1976191,
"4/15/20": 2056054,
"4/16/20": 2152437,
"4/17/20": 2240190,
"4/18/20": 2317758,
"4/19/20": 2401378
},
"deaths": {
"3/21/20": 12973,
"3/22/20": 14651,
"3/23/20": 16505,
"3/24/20": 18625,
"3/25/20": 21181,
"3/26/20": 23970,
"3/27/20": 27198,
"3/28/20": 30652,
"3/29/20": 33925,
"3/30/20": 37582,
"3/31/20": 42107,
"4/1/20": 47180,
"4/2/20": 52983,
"4/3/20": 58787,
"4/4/20": 64606,
"4/5/20": 69374,
"4/6/20": 74565,
"4/7/20": 81937,
"4/8/20": 88338,
"4/9/20": 95521,
"4/10/20": 102525,
"4/11/20": 108502,
"4/12/20": 114090,
"4/13/20": 119481,
"4/14/20": 125983,
"4/15/20": 134176,
"4/16/20": 143800,
"4/17/20": 153821,
"4/18/20": 159509,
"4/19/20": 165043
},
"recovered": {
"3/21/20": 91682,
"3/22/20": 97889,
"3/23/20": 98341,
"3/24/20": 107890,
"3/25/20": 113604,
"3/26/20": 121966,
"3/27/20": 130659,
"3/28/20": 138949,
"3/29/20": 148616,
"3/30/20": 164100,
"3/31/20": 176442,
"4/1/20": 191853,
"4/2/20": 208528,
"4/3/20": 223621,
"4/4/20": 243575,
"4/5/20": 257000,
"4/6/20": 273259,
"4/7/20": 296263,
"4/8/20": 324507,
"4/9/20": 348813,
"4/10/20": 370241,
"4/11/20": 395521,
"4/12/20": 414599,
"4/13/20": 440897,
"4/14/20": 466051,
"4/15/20": 502053,
"4/16/20": 532409,
"4/17/20": 557798,
"4/18/20": 581355,
"4/19/20": 612056
}
}
I would like for each category (cases, deaths, recovered) to represent a line on the chart showing the progression over time, but I'm unsure how to handle it. With the intention being that the dates would be the X-axis and the points would be plotted in a different colored line for each.
Would anyone be able to help with this at all? I would greatly appreciate some guidance. Below are the two primary files corresponding to the Chart and API handling:
index.js
export const fetchDailyData = async () => {
try {
const { data } = await axios.get(`${url}/historical/all`);
const labels = Object.keys(data.cases);
const cases = labels.map((name) => data.cases[name]);
const deaths = labels.map((name) => data.deaths[name]);
const recovered = labels.map((name) => data.recovered[name]);
return {labels, cases, deaths, recovered};
} catch (error) {
return error;
}
}
Chart.jsx
import React, { useState, useEffect } from 'react';
import { Line, Bar } from 'react-chartjs-2';
import { fetchDailyData } from '../../api';
import styles from './Chart.module.css';
const Chart = ({data: { labels, cases, deaths, recovered }}) => {
const [dailyData, setDailyData] = useState([]);
useEffect(() => {
const fetchAPI = async () => {
setDailyData(await fetchDailyData());
}
fetchAPI();
}, []);
const lineChart = (
<Line data = {
{
labels,
datasets: [{
data:cases,
label: 'Infected',
borderColor: '#3333ff',
fill: true,
}, {
data: deaths,
label: 'Deaths',
borderColor: 'red',
backgroundColor: 'rgba(255, 0, 0, 0.5)',
fill: true,
},
{
data: recovered,
label: 'Recovered',
borderColor: 'green',
backgroundColor: 'rgba(0, 255, 0, 0.5)',
fill: true,
}],
}
}
/>
);
return (
<div className = { styles.container }>
{lineChart}
</div>
);
};
export default Chart;
Here is a complete solution:
// Create the chartData state
const [chartData, setChartData] = useState();
// in your fetch function, convert the data to chartData
const labels = Object.keys(data.cases);
const cases = labels.map((name) => data.cases[name]);
const deaths = labels.map((name) => data.deaths[name]);
const recovered = labels.map((name) => data.recovered[name]);
setChartData({
labels,
datasets: [{
data: cases,
label: 'Infected',
borderColor: '#3333ff',
fill: true
}, {
data: deaths,
label: 'Deaths',
borderColor: 'red',
backgroundColor: 'rgba(255, 0, 0, 0.5)',
fill: true
}, {
data: recovered,
label: 'Recovered',
borderColor: 'green',
backgroundColor: 'rgba(0, 255, 0, 0.5)',
fill: true
}]
})
// Now render your chart (but make sure chartData exists)
return (
<div className = { styles.container }>
{chartData &&
<Line data={chartData} />
}
</div>
);
First extract the x labels:
const labels = Object.keys(dailyData.cases);
Then extract the y values for each serie:
const cases = Object.keys(dailyData.cases).map((name) => dailyData.cases[name]);
const deaths = Object.keys(dailyData.deaths).map((name) => dailyData.deaths[name]);
const recovered = Object.keys(dailyData.recovered).map((name) => dailyData.recovered[name]);
Then assemble everything into a chart js object:
<Line data = {
labels,
datasets: [{
data: cases,
label: 'Infected',
borderColor: '#3333ff',
fill: true
}, {
data: deaths,
label: 'Deaths',
borderColor: 'red',
backgroundColor: 'rgba(255, 0, 0, 0.5)',
fill: true
}, {
data: recovered,
label: 'Recovered',
borderColor: 'green',
backgroundColor: 'rgba(0, 255, 0, 0.5)',
fill: true
}]
}
/>

Can't reuse a template in Vue.js

Trying to reuse a custom template from my Graph.vue file, but this attempt fails(without any errors in the console). I only get one chart rendered(the red one). Any ideas how to fix this code?
My current code looks like this:
main.js
import Vue from 'vue';
import Graph from './components/Graph.vue';
new Vue({
el: 'graph',
components: { Graph }
});
Graph.vue
<template>
<canvas height="400" width="600"></canvas>
</template>
<script>
import Chart from 'chart.js';
export default {
props: ['labels', 'values', 'color'],
props: {
labels: {},
values: {},
color: {
default: 'rgba(220,220,220,0.2)'
}
},
mounted(){
var data = {
labels: this.labels,
datasets: [
{
label: "My First dataset",
fill: true,
lineTension: 0.1,
backgroundColor: this.color,
borderColor: "rgba(75,192,192,1)",
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: "rgba(75,192,192,1)",
pointBackgroundColor: "#fff",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: this.values,
spanGaps: false
},
]
};
new Chart(this.$el, {type: 'line', data: data});
}
}
</script>
example.html
<div style="width:600px" class="container">
<graph :labels="['January', 'February', 'March']"
:values="[10, 42, 4]"
color="red"
></graph>
</div>
<div style="width:600px" class="container">
<graph :labels="['May', 'June', 'July']"
:values="[100, 420, 99]"
color="blue"
></graph>
</div>
<script src="{{asset('/js/main.js')}}"></script>
The intended result should be two bars - red and blue one.
I think your mountpoint is wrong. el: 'graph' behavior is probably not predictable in this context (will it target the first graph element?).
Use something like that instead:
JS:
new Vue({
el: '#graphContainer',
components: { Graph }
});
HTML:
<div id="graphContainer">
<div style="width:600px" class="container>
<graph :labels="['January', 'February', 'March']"
:values="[10, 42, 4]"
color="red"></graph>
</div>
<div style="width:600px" class="container">
<graph :labels="['May', 'June', 'July']"
:values="[100, 420, 99]"
color="blue"></graph>
</div>
</div>
I like #Cobaltway answer better, but this also solves the problem.
JS:
import Vue from 'vue';
import Graph from './components/Graph.vue';
const graphs = document.querySelectorAll('graph');
for (let i = 0; i < graphs.length; ++i) {
new Vue({
el: graphs[i],
components: { Graph }
});
}

react-chartjs chart renders without colors

I've tried making a radar chart using react-chartjs (https://github.com/reactjs/react-chartjs). It renders, but there are no colors.
What am I missing? I pretty much copied a large chunk of the example at https://reactcommunity.org/react-chartjs/index.html. (I simplified the data to one dataset.)
import React, {PropTypes} from 'react';
import {Grid} from 'react-bootstrap';
const {Radar} = require("react-chartjs");
const ReactDOM = require('react-dom');
function rand(min, max, num) {
var rtn = [];
while (rtn.length < num) {
rtn.push((Math.random() * (max - min)) + min);
}
return rtn;
}
var chartData = {
labels: ["Eating", "Drinking", "Sleeping", "Designing", "Coding", "Cycling", "Running"],
datasets: [
{
label: "My First dataset",
backgroundColor: "rgba(179,181,198,0.2)",
borderColor: "red",
pointBackgroundColor: "rgba(179,181,198,1)",
pointBorderColor: "#fff",
pointHoverBackgroundColor: "#fff",
pointHoverBorderColor: "rgba(179,181,198,1)",
data: [65, 59, 90, 81, 56, 55, 40]
}
]
};
var chartOptions = {
scale: {
reverse: true,
ticks: {
beginAtZero: true
}
}
};
function TasteGraph({rating}) {
//loop through and output one slider and one value per component
return (
<div>
<Radar data={chartData} options={chartOptions}/>
</div>
);
}
TasteGraph.propTypes = {
rating: PropTypes.array
};
TasteGraph.defaultProps = {
rating: []
};
export default TasteGraph;
There doesn't seem to be any imports missing or clear error. I tried surrounding the chartOptions and ChartData with "[" and "]" based on another related SO question.
Replace backgroundColor with fillColor. Propably your borderColor should be also replaced with strokeColor.
See in this jsfiddle. (It uses chart.js without react wrapper - but your properties gave same output as in your screenshot)

Categories