How to format the x-axis labels in ApexCharts - javascript

I have an API that returns data like this:
[
{
"attributes": {
"type": "AggregateResult"
},
"expr0": 25937961.52,
"expr1": 1,
"expr2": 2020
},
{
"attributes": {
"type": "AggregateResult"
},
"expr0": 4092447.85,
"expr1": 3,
"expr2": 2020
},
{
"attributes": {
"type": "AggregateResult"
},
"expr0": 18509414.84,
"expr1": 6,
"expr2": 2019
},
{
"attributes": {
"type": "AggregateResult"
},
"expr0": 13572118.12,
"expr1": 10,
"expr2": 2019
},
...
Where expr0 is an monetary value, expr1 is the month and expr2 is the year. I am using ApexCharts in React to display the results on my website, however I can't seem to format the data correctly. My component is shown below, however it currently only displays a single point. I'm not sure whether the data points need x/y keys to be displayed or if the dates need to be in the x-axis in options.
class SFAllTimeQuoteValue extends Component {
constructor(props) {
super(props);
this.state = {
series: [{
name: "Opportunities",
data: []
}],
options: {
chart: {
id: "line"
},
xaxis: {
type: "date"
}
}
}
}
async componentDidMount() {
var res = await axios.get(api);
const value = res.data;
var data = [];
for(var i = 0; i < value.length; i++) {
var date = new Date(value[i].expr2, value[i].expr1 - 1);
data.push([date, value[i].expr0]);
}
this.setState({
series: [{
data: data
}]
})
}
render() {
return (
<div>
<Chart series={this.state.series} type ='line' options ={this.state.options}/>
</div>
)
}
}
I would preferably like the data points to display just the month and year as the label too, however using my current method I am getting full date time strings as the label.

You should set the xaxis type as datetime and also set the labels.format property
xaxis: {
type: 'datetime',
labels: {
format: 'MM yyyy'
}
}

Related

CanvasJs Doughnut Chart loading issue on page reload. But works fine in page redirection

I'm implementing a doughnut chart with CanvasJs in a ReactJs App.
Collected following code from CanvasJs's github repo
var React = require("react");
var CanvasJS = require("./canvasjs.min");
CanvasJS = CanvasJS.Chart ? CanvasJS : window.CanvasJS;
class CanvasJSChart extends React.Component {
static _cjsContainerId = 0;
constructor(props) {
super(props);
this.options = props.options ? props.options : {};
this.containerProps = props.containerProps
? props.containerProps
: { width: "100%", position: "relative" };
this.containerProps.height =
props.containerProps && props.containerProps.height
? props.containerProps.height
: this.options.height
? this.options.height + "px"
: "400px";
this.chartContainerId =
"canvasjs-react-chart-container-" + CanvasJSChart._cjsContainerId++;
}
async componentDidMount() {
//Create Chart and Render
this.chart = await new CanvasJS.Chart(this.chartContainerId, this.options);
this.chart.render();
console.log("CHart", this.chart);
if (this.props.onRef) this.props.onRef(this.chart);
}
shouldComponentUpdate(prevProps) {
// //Check if Chart-options has changed and determine if component has to be updated
// return !(nextProps.options === this.options);
if (prevProps.options !== this.props.options) {
return false;
}
else {
return true;
}
}
componentWillUnmount() {
//Destroy chart and remove reference
this.chart.destroy();
if (this.props.onRef) this.props.onRef(undefined);
}
render() {
return <div id={this.chartContainerId} style={this.containerProps} />;
}
}
var CanvasJSReact = {
CanvasJSChart: CanvasJSChart,
CanvasJS: CanvasJS,
};
export default CanvasJSReact;
I'm passing options to the component in the following manner
const options = {
animationEnabled: true,
subtitles: [
{
text: "",
verticalAlign: "center",
fontSize: 24,
dockInsidePlotArea: true,
},
],
data: [
{
type: "doughnut",
indexLabel: "{name}: {percentage}",
yValueFormatString: "'$'#,###",
dataPoints: [{ name: "Unsatisfied", y: 5 },
{ name: "Very Unsatisfied", y: 31 },
{ name: "Very Satisfied", y: 40 },
{ name: "Satisfied", y: 17 },
{ name: "Neutral", y: 7 }],
},
],
};
USE THIS UPPER COMPONENT
<CanvasJSChart options={options} />
When I'm passing dataPoints (with static data) in my code, the chart loads fine.
But the issue occurs when I try to use dynamic data. My dynamic data has only one dataPoint this point of time
// Array of data points
[{
name: "FNBO Evergreen® Rewards Visa® Card",
percentage:"100%",
y: 20000
}]
On Page reload the chart is not rendering. But, it appears back if routed from another page or window size is changed.
The issue can be easily seen the following loom video
https://www.loom.com/share/754b51dae7b04cb29a87a969a961fefc
Note: In all the cases shown in video, we do receive data from backend. But this issue occurs in some of the cases

How to get data from API through vue chartjs?

this is my first time posting here, i'm working on an application where i need to get data from an API and show it through a chart (i'm using vue chart js). The code is almost done, i can see in the console the API's data.
Showing API's data in console
This is my chart/api conection:
<template>
<div>
<bar-chart
:data="barChartData"
:options="barChartOptions"
:height="150"
:width="150"
/>
</div>
</template>
<script>
import BarChart from "~/components/BarChart";
const chartColors = {
grey: "rgba(210, 210, 210, 0.2)",
white: "rgb(255,255,255)",
};
export default {
components: {
BarChart,
},
data() {
return {
barChartData: {
asistencia: [],
labels: [],
datasets: [
{
label: "Income",
backgroundColor: [chartColors.white, chartColors.grey],
data: [0,0],
},
],
},
barChartOptions: {
responsive: true,
legend: {
display: true,
},
},
};
},
async fetch() {
this.asistencia = await fetch(
'http://127.0.0.1:8000/apiasistenciausuarioAsistenciaUsuario/',
).then(res => res.json())
console.log(this.asistencia);
},
components: {
BarChart,
},
methods: {
refresh() {
this.datos();
this.$nuxt.refresh();
},
datos() {
this.barChartData.datasets[0].data = [
this.res.is_presente,
];
},
}
};
As you can see i send the data to the console but the "Asistencia" graphic is not showing and that's because it isn't getting the data sucessfully
datos() {
this.barChartData.datasets[0].data = [
this.res.is_presente,
];
barChartData should get the data from "is_presente" var from the API but that var is a boolean so i was thinking on doing a validation to check when it's true/false and make a counter to fill the graphic.
datos() {
this.barChartData.datasets[0].data = [
if(this.res.is_presente == true){
count++;
}else{
count--;
}
];
I don't know how to do this, i have the idea but i don't know how to execute this....
Thanks in advance!

t[this.activeSeriesIndex].data[0] is undefined in ApexCharts. How to correctly build the series array?

I'm a beginner in Vue and I'm using vue-apex chart to create a chart in my application. I want to display in chart, the values of the two component's properties "uncorrectAns" and "correctAns" that I compute thanks to a specific method (computeStat()).
<template>
<apexcharts width="500" type="bar" :options="chartOptions" :series="series"></apexcharts>
</template>
<script>
export default {
name: 'Results',
components: {
apexcharts: VueApexCharts
},
data() {
return {
results: '',
correctAns: 0,
uncorrectAns: 0,
chartOptions: {
chart: {
id: 'vuechart-example'
},
xaxis: {
categories: ['Correct Answers', 'Uncorrect Answers']
}
},
series: [
{
name: 'series-1',
data: [this.correctAns, this.uncorrectAns]
}
]
}
},
methods: {
computeStat() {
var i
for (i = 0; i < this.results.length; i = i + 1) {
if (this.results[i].answerCorrect == true) {
this.correctAns = this.correctAns + 1
} else {
this.uncorrectAns = this.uncorrectAns + 1
}
}
}
},
created() {
this.results = this.$route.params.output
this.computeStat()
var i
for (i = 0; i < this.results.length; i = i + 1) {
console.log('bestPractice ' + i + ':' + this.results[i].bestPract)
}
}
}
</script>
When I run the application, the chart isn't displayed and I get this error message on the browser console:
I would like to know the nature of this error and if there is a correct way to display "correctAns" and "uncorrectAns" values in the chart.
There's a couple of problems here around your series property...
When you define series, both this.correctAns and this.uncorrectAns are undefined (this is the source of your problem)
Because series is statically defined, it will never update as you make changes to this.correctAns and this.uncorrectAns
The solution is to convert series into a computed property. Remove it from data and add
computed: {
series () {
return [
{
name: 'series-1',
data: [this.correctAns, this.uncorrectAns]
}
]
}
}
Demo ~ https://jsfiddle.net/ynLfabdz/
Given you seem to be treating results as an array, you should initialise it as such instead of an empty string, ie
results: [], // not ''
I fixed the issue by simple check if the array is undefined then return empty if not return the chart with my values
const Amount = [
{
name: 'Salary Amount',
data: salary[0] === undefined ? [] : salary
},
{
name: 'Over Time Amount',
data: overTime[0] === undefined ? [] : overTime
},
true
]

How do I add time sourced from an external source as an X axis to a ChartJS graph?

https://plnkr.co/edit/O4BxVsdOZBc4R68p
fetch(target)
.then(response => response.json())
.then(data => {
var prices = data['Time Series (5min)'];
for (prop in prices) {
var stockPrices = prices[prop]['1. open'];
//change to 2. high, etc
console.log(`${prop} : ${stockPrices}`);
stocksData.datasets[0].data.push({x: prop, y: +stockPrices})
//time x axes are preventing render
window.lineChart.update();
}
})
I am getting information from the AlphaVantage API and am trying to graph the time as the X axis and the open price as the Y axis. However, the time from the API is in an odd format and doesn't appear to graph. I have looked into Moment.js but that appears to be making times, not formatting them. Can anyone give me any pointers on graphing the time correct?
Your problem comes from 2 things:
Your Chart config in options with xAxes that should be xAxis instead
Missing Labels and correct data in Chart data
Here is the codes that works:
var stocksData = {
datasets: [
{
label: 'open',
backgroundColor: 'rgba(104,0,255,0.1)',
data: [
],
},
],
};
window.onload = function() {
var ctx = document.getElementById('myChart').getContext('2d');
var lineChart = new Chart(ctx, {
type: 'line',
data: stocksData,
options: {
scales: {
xAxis: [
{
type: 'linear',
position: 'bottom',
},
],
},
},
});
window.lineChart = lineChart;
};
var sym = 'AAPL'; //get from form
var tseries = 'TIME_SERIES_INTRADAY'; //get from form
var target = `https://www.alphavantage.co/query?function=${tseries}&symbol=${sym}&interval=5min&apikey=VA3RZ8B9PPYWKQKN`;
function update () {
fetch(target)
.then(response => response.json())
.then(data => {
var prices = data['Time Series (5min)'];
for (prop in prices) {
var stockPrices = prices[prop]['1. open'];
//change to 2. high, etc
console.log(`${prop} : ${stockPrices}`);
//stocksData.datasets[0].data.push({x: prop, y: +stockPrices})
stocksData.datasets[0].data.push(stockPrices);
// Format date here. For example with Moment:
// var date = moment(prop).format('YYYY-MM-DD')
stocksData.labels.push(prop);
//time x axes are preventing render
window.lineChart.update();
}
})
.catch(error => console.error(error));
}
A complete format for Chart data would be like:
var stocksData = {
labels: ['date1', 'date2', 'date3', 'date4'],
datasets: [
{
label: 'open',
backgroundColor: 'rgba(104,0,255,0.1)',
data: [
'data1', 'data2', 'data3', 'data4'
],
},
],
};
Then each data and date label should be push separately:
stocksData.datasets[0].data.push(stockPrices);
stocksData.labels.push(prop);
To format with Moment you can use:
var dateStr = moment(prop).format('YYYY-MM-DD');
The "odd" time format is (almost) the standard international datetime format. In this case YYYY-MM-DD HH:MM:SS. I strongly suggest you familiarise yourself with it and use it in preference to DD/MM/YYYY or MM/DD/YYYY.
You can fix your code by changing the x-axis type to time and adding the appropriate configuration options:
options: {
scales: {
xAxes: [
{
type: 'time',
...
Note that you'll also need to change your call to Chart.js to the version with moment.js bundled (or include moment separately):
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>

Chart.js chart in vue.js component does not update

I´m developing a visualization module for some crypto portfolios with vue.js and chart.js but am currently stuck with this:
Empty chart is displayed but non of the values are rendered.
Since the values are dynamically loaded after the chart is initialized I believe that the chart is not updating itself properly (even though I call .update()), but no errors are displayed whatsoever.
I wrapped the chart.js rendering in a vue component:
Vue.component('portfolioValues', {
template: '<canvas width="400" height="200"></canvas>',
data: function() {
return {
portfolio_value: [],
portfolio_labels: [],
chart: null,
}
},
methods: {
load_portfolio_value_local: function() {
values = [];
labels = []
local_data.forEach(element => {
values.push(element.total_usd);
labels.push(moment(element.timestamp, 'X'));
});
this.portfolio_value = values;
this.portfolio_labels = labels;
this.chart.update();
},
render_chart: function() {
this.chart = new Chart(this.$el, {
type: 'line',
data: {
labels: this.portfolio_labels,
datasets: [{
label: "Portfolio Value",
data: this.portfolio_value,
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
distribution: 'linear',
}]
}
}
});
}
},
mounted: function() {
this.render_chart();
this.load_portfolio_value_local();
}
});
For demonstration purposes I just added some data locally, looks like this:
local_data = [{
"timestamp": 1515102737,
"total_btc": 0.102627448096786,
"total_usd": 1539.41274772627
}, {
"timestamp": 1515102871,
"total_btc": 0.102636926127186,
"total_usd": 1538.52649627725
}, {
"timestamp": 1515103588,
"total_btc": 0.102627448096786,
"total_usd": 1532.33042753311
}
]
Here is the full demo code: https://codepen.io/perelin/pen/mppbxV
Any ideas why no data gets rendered? thx!
The problem you have here is how vuejs handles its data.
If you use it like that:
local_data.forEach(element => {
this.portfolio_value.push(element.total_usd);
this.portfolio_labels.push(moment(element.timestamp, 'X'));
});
this.chart.update();
The chart will update. But by re-initializing the arrays you work against vuejs.
TL;DR
If you want to re-initialize an object, you could assign the array to the object:
Object.assign(this.portfolio_value, values);
Object.assign(this.portfolio_labels, labels);
That way, the linking stays working.

Categories