So I am new to using data visualization in an application and I am trying to set my data coming from my api as the data the doughnut chart uses to display however I cannot figure out how to properly access the data
I have installed vue-chartjs as a way to simplify it for component use
Here is the Chart component
<script>
import { Doughnut } from 'vue-chartjs'
import {mapGetters} from 'vuex'
export default {
name: 'FirmChart',
extends: Doughnut,
computed: {
...mapGetters(['chartEngagements']),
},
mounted () {
this.renderChart({
labels: ['Scanned', 'Recieved', 'Preparation', 'Review', '2nd Review', 'Complete'],
datasets: [
{
label: 'Data One',
borderColor: 'black',
pointBackgroundColor: 'white',
borderWidth: 1,
pointBorderColor: 'white',
backgroundColor: [
'#0077ff',
'#0022ff',
'#1133bb',
'#0088aa',
'#11ffdd',
'#aabbcc',
'#22aabb',
],
data: [
10,
10,
10,
10,
10,
10,
]
},
]
}, {responsive: true, maintainAspectRatio: false});
},
created() {
this.$store.dispatch('retrieveEngagementsChartData')
}
}
</script>
now my data is coming from the chartEngagements getter and this is the display of that data in the console
{Complete: Array(1), Review: Array(3), 2nd Review: Array(1), Recieved: Array(7), Preparation: Array(1), …}
My question is how do I set the Complete: Array(1) etc to the data[] attribute in my this.renderChart() method??
I have tried doing something like this but It will not display anything
mounted () {
this.renderChart({
labels: ['Scanned', 'Recieved', 'Preparation', 'Review', '2nd Review' 'Complete'],
datasets: [
{
label: 'Data One',
borderColor: 'black',
pointBackgroundColor: 'white',
borderWidth: 1,
pointBorderColor: 'white',
backgroundColor: [
'#0077ff',
'#0022ff',
'#1133bb',
'#0088aa',
'#11ffdd',
'#aabbcc',
'#22aabb',
],
data: [
this.chartEngagements.complete,
this.chartEngagements.review,
this.chartEngagements.2ndreview,
this.chartEngagements.preparation,
this.chartEngagements.recieved,
this.chartEngagements.scanned,
]
},
]
}, {responsive: true, maintainAspectRatio: false});
However it doesn't display anything.. any help would be greatly appreciated or a point in the right direction!
Have you checked out the examples in the docs?
https://vue-chartjs.org/guide/#chart-with-api-data
Your problem is, that your data api call is async. So your chart is rendered, even if your data is not fully loaded.
There is also an example with vuex which is a bit outdated https://github.com/apertureless/vue-chartjs-vuex
You have to make sure that your data is fully loaded before you render your chart.
I faced similar issue while implementing Charts with API data in one of my Vue JS apps I was working on. I am using Vuex for state management, a simple solution for this problem is to move "chartData" from "data" to "computed" which would make it reactive. Below is the sample code from my app.
<template>
<line-chart v-if="chartData"
style="height: 100%"
chart-id="big-line-chart"
:chart-data="chartData"
:extra-options="extraOptions"
>
</line-chart>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
import * as expenseTypes from '../../store/modules/expense/expense-types';
import * as chartConfig from "../../components/reports/chart.config";
import BarChart from "../../components/reports/BarChart";
export default {
components: {
BarChart,
},
data () {
return {
extraOptions: chartConfig.chartOptionsMain
}
},
computed: {
...mapGetters({
allExpenses: expenseTypes.GET_ALL_EXPENSES,
expenseCount: expenseTypes.GET_EXPENSE_COUNT,
}),
expenseAmount() {
let expenseAmount = [];
this.allExpenses.map((item) => {
expenseAmount.push(item.amount);
})
return expenseAmount;
},
expenseLabels() {
let expenseLabels = [];
this.allExpenses.map((item) => {
expenseLabels.push(item.note);
})
return expenseLabels;
},
chartData() {
return {
datasets: [
{
data: this.expenseAmount
},
],
labels: this.expenseLabels
}
}
},
async mounted() {
await this.getAllExpenses();
await this.fillChartData();
},
methods: {
...mapActions({
getAllExpenses: expenseTypes.GET_ALL_EXPENSES_ACTION,
}),
},
};
</script>
Related
I am using vue-chartjs to create charts for my application. I am passing the chartData as a prop. My chart doesn't render at first but does when I resize the window. Here is my code. First the chart component:
<script>
import { Doughnut, mixins } from "vue-chartjs";
const { reactiveProp } = mixins;
export default {
extends: Doughnut,
mixins: [reactiveProp],
mounted() {
this.render();
},
methods: {
render() {
console.log(this.chartData)
let options = {
responsive: true,
maintainAspectRatio: false,
legend: {
display: false,
},
};
this.renderChart(this.chartData, options);
},
},
};
</script>
Now here is the code from the component where the chart is displayed:
template part
<v-container>
<ProjectDoughnutChart :chart-data="chartData" />
</v-container>
script part
components: {
ProjectDoughnutChart,
},
data() {
return {
chartData: {
labels: [],
datasets: [
{
backgroundColor: [],
hoverBackgroundColor: [],
data: [],
},
],
},
};
},
setChartsTimesheets() {
this.timesheets.forEach((timesheet) => {
let typeTotal = 0;
this.timesheets
.filter((timesheet1) => timesheet1.type==timesheet.type)
.forEach((timesheet1) => {
typeTotal+=timesheet1.billableAmount;
});
if (this.chartData.labels.indexOf(timesheet.type) === -1) {
let colors = this.getTaskColors(timesheet.type);
this.chartData.labels.push(timesheet.type);
this.chartData.datasets[0].data.push(typeTotal);
this.chartData.datasets[0].backgroundColor.push(colors.color);
this.chartData.datasets[0].hoverBackgroundColor.push(colors.hover);
}
});
},
Solved the problem using a similar solution as "Chart with API data" from the documentation.
TL;DR: Adding a v-if on the chart
For people, that have similar problem, but not using vue.js or the official solution doesnt cut it. I had to chart.update() the graph to show values, that were added after the graph was created.
See the example. If you comment the chart.update() line, the graph will not refresh until the window is resized.
let chart = new Chart(document.getElementById("chart"), {
type: "line",
data: {
labels: ["a", "b", "c", "d", "e", "f"],
datasets: [{
label: 'Dataset 1',
data: [1, 5, 12, 8, 2, 3],
borderColor: 'green',
}]
},
options: {
interaction: {
mode: 'index',
intersect: true,
},
stacked: false,
responsive: true,
}
});
// adding data to graph after it was created (like data from API or so...)
chart.data.labels.push("new data");
chart.data.datasets[0].data.push(9);
// with chart.update(), the changes are shown right away
// without chart.update(), you need to resize window first
chart.update();
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<canvas id="chart"></canvas>
I want to create pie-chart with vue-apexcharts. I had data from API but I don't know how to update the chart's data.
mounted() {
axios
.get("/data/episodes.json")
.then(response => {
console.log(response);
});
}
The chart I want to create is like this
Here is my understanding on doing, ...
first you have to define the data and option values of chart.
components: {
apexchart: VueApexCharts,
},
data: {
series: [],
chartOptions: {
chart: {
width: 380,
type: "pie",
},
labels: [],
responsive: [
{
breakpoint: 480,
options: {
chart: {
width: 200,
},
legend: {
position: "bottom",
},
},
},
],
},
},
Now on mount you have call your api to get the data and update the chart information. like this ...
I'm thinking of you server would return an array of objects having value and key.
mounted() {
axios.get("/data/episodes.json").then((response) => {
for (let i = 0; i < response.data.length; i++) {
this.data.series.push(response.data[i].value);
this.data.chartOptions.labels.push(response.data[i].key);
}
});
},
Finally, you have to add the chart component to the vue template. like this.
<div id="chart">
<apexchart type="pie" width="380" :options="chartOptions" :series="series"></apexchart>
</div>
Done,
Ask me if it is not clear for you.
I am writing a small covid project and trying to plot confirmed infection data using ApexCharts, but the graph is not showing. I enter the data from vuex in two tables. The data is valid however it comes from api and sa in the proxy object. What am I doing wrong? (I am using ApexCharts because vue Chartjs is not compatible with vue 3).
<template>
<apexchart width="500" type="bar" :options="options" :series="series"></apexchart>
</template>
<script>
import VueApexCharts from "vue3-apexcharts";
export default {
components: {
apexchart: VueApexCharts,
},
data(){
return {
series: [],
options: {
chart: {
type: "bar",
height: 400,
stacked: true
},
plotOptions: {
bar: {
horizontal: false
}
},
dataLabels: {
enabled: false
},
tooltip: {
shared: true,
followCursor: true
},
stroke: {
width: 1,
colors: ["#fff"]
},
fill: {
opacity: 1
},
legend: {
position: "top",
horizontalAlign: "center",
offsetX: 40
},
colors: ["rgb(95, 193, 215)", "rgb(226, 37, 43)", "rgb(94, 181, 89)"]
}
};
},
computed: {
getDate(){
return this.$store.getters['chart/getDate'];
},
getConfirmed(){
return this.$store.getters['chart/getConfirmed'];
}
},
methods: {
fillDate(){
this.options = {
xaxis: {
categories: this.getDate
}
}
this.series = [
{
name: 'Confirmed',
data: this.getConfirmed
}
];
}
},
async mounted() {
await this.fillDate();
}
}
The data from the vuex store are two arrays.
Proxy
[[Handler]]: Object
[[Target]]: Array(45)
[[IsRevoked]]: false
Instead of using mounted hook and method try to watch the computed properties then update the data based on that ones:
computed: {
getDate(){
return this.$store.getters['chart/getDate'];
},
getConfirmed(){
return this.$store.getters['chart/getConfirmed'];
}
},
watch:{
getDate:{
handler(newVal){
this.options = {
xaxis: {
categories: this.getDate
}
},
deep:true
},
getConfirmed:{
handler(newVal){
this.series = [
{
name: 'Confirmed',
data: this.getConfirmed
}
];
},
deep:true
}
}
I am a beginner in Vue and I want to create a project that uses Chart.js. I am using Vuex and am having a trouble to generate the data into the component.
<script>
import{Line} from 'vue-chartjs';
import {mapGetters,mapActions} from 'vuex';
export default {
extends:Line,
data: () => ({
chartdata: {
labels: ['January', 'February'],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: this.currentDeath
}
]
},
options: {
responsive: true,
maintainAspectRatio: false
}
}),
methods:{
...mapActions(["fetchData"]),
},
computed:{
...mapGetters(["currentDeath"])
},
created(){
this.fetchData()
},
mounted(){
const dates = this.
this.renderChart(this.chartData,this.options)
}
}
</script>
<style scoped>
</style>
It says on localhost that "currentDeath is undefined". However if I were to print it on screen it is populated with an array of data. Anyone knows how I can access its data?
Linechart.js
import { Line } from 'vue-chartjs'
export default {
extends: Line,
props:['chart']
mounted () {
this.renderChart({
labels: ['1','2','3','4','5','6','7'],
datasets: [
{
label: 'Data One',
backgroundColor: '#F64A32',
data: this.chart
}
]
}, {responsive: true, maintainAspectRatio: false})
}
}
I use the props to pass the data
example.vue
<template>
<line-chart :width="370" :height="246" :chart="chartdata"></line-chart>
</template>
<script>
import LineChart from './vue-chartjs/LineChart'
export default {
components: {
LineChart
},
},
data(){
return{
chartdata:[]
}
}
methods:{
getdata(){
this.chartdata=[10,20,30,40,50]
}
}
</script>
when I click the getdata() the chartdata I think it has been passed to the Linechart.js, But why the chart does not update? Still empty
If you want the data to change on the fly, you either need the reactiveMixin http://vue-chartjs.org/#/home?id=reactive-data
Or you have to trigger an chart update by yourself.
This is because, even Vue.js is reactive, Chart.js per se is not.
If you want to update your chart, simply add a watcher to your LineChart.js component and watch for changes in chart. And then call .update()
import { Line } from 'vue-chartjs'
export default {
extends: Line,
props:['chart']
watch: {
chart () {
this.$data._chart.update()
}
}
mounted () {
this.renderChart({
labels: ['1','2','3','4','5','6','7'],
datasets: [
{
label: 'Data One',
backgroundColor: '#F64A32',
data: this.chart
}
]
}, {responsive: true, maintainAspectRatio: false})
}
}