Related
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
]
I am trying to implement a stacked bar graph and I would like to understand if there is anyway that we can specify the category along with the data point in series.
I have Categories as :
xAxis: {
categories: ['DEV', 'TEST', 'Stage']
},
Series data:
series: [{
name: 'Severity-1',
data: [['TEST',20]]
},{
name: 'Severity-2',
data: [['TEST',20]]
}]
In above snippet I am trying to add a point value '30' to 'TEST' category but when I load the graph it shows up under 'DEV' category.
Example: http://jsfiddle.net/G5S9L/1/
Any idea?
Did you try:
{"xAxis": { "type" : "category" .... } ... }
It should get category from your data.
You need to use category index instead of category name, so proper example will be:
series: [{
name: 'Severity-1',
data: [[1,20]] //0-DEV, 1-TEST, 2-Stage
},{
name: 'Severity-2',
data: [[1,20]]
}]
Hey Vipul Do you want something like this ? Please check the link below for the code.
series: [{
name: 'Severity-1',
data: [['TEST',20]]
},{
name: 'Severity-2',
data: [['TEST',20]]
}]
CHECK EXAMPLE
is there any way to pass some additional data to the series object that will use to show in the chart 'tooltip'?
for example
tooltip: {
formatter: function() {
return '<b>'+ this.series.name +'</b><br/>'+
Highcharts.dateFormat('%b %e', this.x) +': '+ this.y;
}
here we can only use series.name , this.x & this.y to the series. lets say i need to pass another dynamic value alone with the data set and can access via series object. is this possible?
Thank you all in advance.
Yes, if you set up the series object like the following, where each data point is a hash, then you can pass extra values:
new Highcharts.Chart( {
...,
series: [ {
name: 'Foo',
data: [
{
y : 3,
myData : 'firstPoint'
},
{
y : 7,
myData : 'secondPoint'
},
{
y : 1,
myData : 'thirdPoint'
}
]
} ]
} );
In your tooltip you can access it via the "point" attribute of the object passed in:
tooltip: {
formatter: function() {
return 'Extra data: <b>' + this.point.myData + '</b>';
}
}
Full example here: https://jsfiddle.net/burwelldesigns/jeoL5y7s/
Additionally, with this solution, you can even put multiple data as much as you want :
tooltip: {
formatter: function () {
return 'Extra data: <b>' + this.point.myData + '</b><br> Another Data: <b>' + this.point.myOtherData + '</b>';
}
},
series: [{
name: 'Foo',
data: [{
y: 3,
myData: 'firstPoint',
myOtherData: 'Other first data'
}, {
y: 7,
myData: 'secondPoint',
myOtherData: 'Other second data'
}, {
y: 1,
myData: 'thirdPoint',
myOtherData: 'Other third data'
}]
}]
Thank you Nick.
For time series data, especially with enough data points to activate the turbo threshold, the proposed solutions above will not work. In the case of the turbo threshold, this is because Highcarts expects the data points to be an array like:
series: [{
name: 'Numbers over the course of time',
data: [
[1515059819853, 1],
[1515059838069, 2],
[1515059838080, 3],
// you get the idea
]
}]
In order not to lose the benefits of the turbo threshold (which is important when dealing with lots of data points), I store the data outside of the chart and look up the data point in the tooltip formatter function. Here's an example:
const chartData = [
{ timestamp: 1515059819853, value: 1, somethingElse: 'foo'},
{ timestamp: 1515059838069, value: 2, somethingElse: 'bar'},
{ timestamp: 1515059838080, value: 3, somethingElse: 'baz'},
// you get the idea
]
const Chart = Highcharts.stockChart(myChart, {
// ...options
tooltip: {
formatter () {
// this.point.x is the timestamp in my original chartData array
const pointData = chartData.find(row => row.timestamp === this.point.x)
console.log(pointData.somethingElse)
}
},
series: [{
name: 'Numbers over the course of time',
// restructure the data as an array as Highcharts expects it
// array index 0 is the x value, index 1 is the y value in the chart
data: chartData.map(row => [row.timestamp, row.value])
}]
})
This approach will work for all chart types.
I am using AJAX to get my data from SQL Server, then I prepare a js array that is used as the data in my chart.
JavaScript code once the AJAX is successfull:
...,
success: function (data) {
var fseries = [];
var series = [];
for (var arr in data) {
for (var i in data[arr]['data'] ){
var d = data[arr]['data'][i];
//if (i < 5) alert("d.method = " + d.method);
var serie = {x:Date.parse(d.Value), y:d.Item, method:d.method };
series.push(serie);
}
fseries.push({name: data[arr]['name'], data: series, location: data[arr]['location']});
series = [];
};
DrawChart(fseries);
},
Now to show extra meta-data in the tooltip:
...
tooltip: {
xDateFormat: '%m/%d/%y',
headerFormat: '<b>{series.name}</b><br>',
pointFormat: 'Method: {point.method}<br>Date: {point.x:%m/%d/%y } <br>Reading: {point.y:,.2f}',
shared: false,
},
I use a DataRow to iterate through my result set, then I use a class to assign the values prior to passing back in Json format. Here is the C# code in the controller action called by Ajax.
public JsonResult ChartData(string dataSource, string locationType, string[] locations, string[] methods, string fromDate, string toDate, string[] lstParams)
{
List<Dictionary<string, object>> dataResult = new List<Dictionary<string, object>>();
Dictionary<string, object> aSeries = new Dictionary<string, object>();
string currParam = string.Empty;
lstParams = (lstParams == null) ? new string[1] : lstParams;
foreach (DataRow dr in GetChartData(dataSource, locationType, locations, methods, fromDate, toDate, lstParams).Rows)
{
if (currParam != dr[1].ToString())
{
if (!String.IsNullOrEmpty(currParam)) //A new Standard Parameter is read and add to dataResult. Skips first record.
{
Dictionary<string, object> bSeries = new Dictionary<string, object>(aSeries); //Required else when clearing out aSeries, dataResult values are also cleared
dataResult.Add(bSeries);
aSeries.Clear();
}
currParam = dr[1].ToString();
aSeries["name"] = cParam;
aSeries["data"] = new List<ChartDataModel>();
aSeries["location"] = dr[0].ToString();
}
ChartDataModel lst = new ChartDataModel();
lst.Value = Convert.ToDateTime(dr[3]).ToShortDateString();
lst.Item = Convert.ToDouble(dr[2]);
lst.method = dr[4].ToString();
((List<ChartDataModel>)aSeries["data"]).Add(lst);
}
dataResult.Add(aSeries);
var result = Json(dataResult.ToList(), JsonRequestBehavior.AllowGet); //used to debug final dataResult before returning to AJAX call.
return result;
}
I realize there is a more efficient and acceptable way to code in C# but I inherited the project.
Just to add some kind of dynamism :
Did this for generating data for a stacked column chart with 10 categories.
I wanted to have for each category 4 data series and wanted to display additional information (image, question, distractor and expected answer) for each of the data series :
<?php
while($n<=10)
{
$data1[]=array(
"y"=>$nber1,
"img"=>$image1,
"ques"=>$ques,
"distractor"=>$distractor1,
"answer"=>$ans
);
$data2[]=array(
"y"=>$nber2,
"img"=>$image2,
"ques"=>$ques,
"distractor"=>$distractor2,
"answer"=>$ans
);
$data3[]=array(
"y"=>$nber3,
"img"=>$image3,
"ques"=>$ques,
"distractor"=>$distractor3,
"answer"=>$ans
);
$data4[]=array(
"y"=>$nber4,
"img"=>$image4,
"ques"=>$ques,
"distractor"=>$distractor4,
"answer"=>$ans
);
}
// Then convert the data into data series:
$mydata[]=array(
"name"=>"Distractor #1",
"data"=>$data1,
"stack"=>"Distractor #1"
);
$mydata[]=array(
"name"=>"Distractor #2",
"data"=>$data2,
"stack"=>"Distractor #2"
);
$mydata[]=array(
"name"=>"Distractor #3",
"data"=>$data3,
"stack"=>"Distractor #3"
);
$mydata[]=array(
"name"=>"Distractor #4",
"data"=>$data4,
"stack"=>"Distractor #4"
);
?>
In the highcharts section:
var mydata=<? echo json_encode($mydata)?>;
// Tooltip section
tooltip: {
useHTML: true,
formatter: function() {
return 'Question ID: <b>'+ this.x +'</b><br/>'+
'Question: <b>'+ this.point.ques +'</b><br/>'+
this.series.name+'<br> Total attempts: '+ this.y +'<br/>'+
"<img src=\"images/"+ this.point.img +"\" width=\"100px\" height=\"50px\"/><br>"+
'Distractor: <b>'+ this.point.distractor +'</b><br/>'+
'Expected answer: <b>'+ this.point.answer +'</b><br/>';
}
},
// Series section of the highcharts
series: mydata
// For the category section, just prepare an array of elements and assign to the category variable as the way I did it on series.
Hope it helps someone.
I just play around with Highcharts (http://www.highcharts.com) inside of a test app based on rails 3.1.1 and HAML. I'm still new to js and I try to accomplish a nice integration of highcharts.
In my controller I set up some json arrays for usage in highcharts.
#category_ids_json = Category.all(:conditions => { :income => false},:select => "id").to_json
#categories_json = Category.all(:conditions => { :income => false}, :select => "id,title,income").to_json
#transactions_json = Transaction.all(:select => "date,title,amount,category_id").to_json
Out of these instance variables, I filter some values and create a new array, which i use for the highcharts data array:
var category_transactions_sum = new Array();
category_transactions_sum.push({title:categories[c].title, amount: transactions_sum})
The content of the array looks somehting like this:
[{title: "Salary", amount: 50},{title: "Food", amount: 25},{title: "Recreation", amount: 10}]
Now I'm stuck when it is time to initialize Highcharts. This is how I initialize it right now:
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
series: [{
type: 'pie',
name: 'Expenses',
data: [
[category_transactions_sum[0].title, category_transactions_sum[0].amount],
[category_transactions_sum[1].title, category_transactions_sum[1].amount],
[category_transactions_sum[2].title, category_transactions_sum[2].amount],
[category_transactions_sum[3].title, category_transactions_sum[3].amount],
[category_transactions_sum[4].title, category_transactions_sum[4].amount],
[category_transactions_sum[5].title, category_transactions_sum[5].amount],
[category_transactions_sum[6].title, category_transactions_sum[6].amount],
[category_transactions_sum[7].title, category_transactions_sum[7].amount],
[category_transactions_sum[8].title, category_transactions_sum[8].amount],
[category_transactions_sum[9].title, category_transactions_sum[9].amount],
[category_transactions_sum[10].title, category_transactions_sum[10].amount],
[category_transactions_sum[11].title, category_transactions_sum[11].amount],
[category_transactions_sum[12].title, category_transactions_sum[12].amount],
[category_transactions_sum[13].title, category_transactions_sum[13].amount],
[category_transactions_sum[14].title, category_transactions_sum[14].amount],
[category_transactions_sum[15].title, category_transactions_sum[15].amount],
[category_transactions_sum[16].title, category_transactions_sum[16].amount],
[category_transactions_sum[17].title, category_transactions_sum[17].amount],
[category_transactions_sum[18].title, category_transactions_sum[18].amount],
[category_transactions_sum[19].title, category_transactions_sum[19].amount],
[category_transactions_sum[20].title, category_transactions_sum[20].amount],
[category_transactions_sum[21].title, category_transactions_sum[21].amount],
[category_transactions_sum[22].title, category_transactions_sum[22].amount],
[category_transactions_sum[23].title, category_transactions_sum[23].amount],
[category_transactions_sum[24].title, category_transactions_sum[24].amount],
[category_transactions_sum[25].title, category_transactions_sum[25].amount],
[category_transactions_sum[26].title, category_transactions_sum[26].amount],
]
}]
});
My Questions:
How would i iterate through the category_transactions_sum array to get rid of that bunch of lines inside of the "data" declaration of highcharts. I tried a for loop but it didn't work.
Is there a better way to insert the data into highcharts? Highcharts needs data in this format:
data: [
['Firefox', 45.0],
['IE', 26.8],
['Safari', 8.5],
['Opera', 6.2],
['Others', 0.7]
]
Is it possible to do something like this?
data: [
myArrayWithPreparedData
]
If yes, how would i build this array?
Many thanks for helping a newbie out.
I believe you want something like this:
data: $.map(category_transactions_sum, function(i, c) { return [c.title, c.amount]; })
you can try this (works for me):
temp = $.map(json, function(i) { return [[i.in_time, i.status]]; })
showData = JSON.parse(JSON.stringify(temp, null, ""));
and then use in the series as :
chart.addSeries({
data: showData
});
Alex almost has it.
Should be:
someVar = [{title: "Salary", amount: 50},{title: "Food", amount: 25},{title: "Recreation", amount: 10}]
data = $.map(someVar, function(i) { return [[i.title, i.amount]]; })
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
series: [{
type: 'pie',
name: 'Expenses',
data: data
}]
});
On debug. when execution is leaving the controller I debug and the variable contains :
?sArray
{string[17, 2]}
[0, 0]: "Arecleoch"
[0, 1]: "21"
[1, 0]: "Barnesmore"
[1, 1]: "3"
etc etc....
then in the javascript its received as :
?sdata
{...}
[0]: "Arecleoch"
[1]: "21"
[2]: "Barnesmore"
[3]: "3"
[4]: "Beinn An Tuirc"
[5]: "1"
[6]: "Beinn An Tuirc Phase 2"
etc
so the pie is displayed as one solid circle of colour
puzzled, any ideas?
controller code below :
public JsonResult GetChartData_IncidentsBySite()
{
var allSites = _securityRepository.FindAllSites();
var qry = from s in _db.Sites
join i in _db.Incidents on s.SiteId equals i.SiteId
group s by s.SiteDescription
into grp
select new
{
Site = grp.Key,
Count = grp.Count()
};
string[,] sArray = new string[qry.Count(),2];
int y = 0;
foreach (var row in qry.OrderBy(x => x.Site))
{
if ((row.Count > 0) && (row.Site != null))
{
sArray[y, 0] = row.Site.ToString();
sArray[y, 1] = row.Count.ToString();
y++;
}
}
return Json(sArray , JsonRequestBehavior.AllowGet);
}
Here is the javascript code :
$.getJSON(url, null, function(sdata) {
debugger;
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false
},
title: {
text: 'Number of Environmental Incidents by Site'
},
tooltip: {
formatter: function() {
return '<b>' + this.point.name + '</b>: ' + this.y + ' %';
}
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: false
},
showInLegend: true
}
},
series: [{
type: 'pie',
name: 'Incidents by Site',
data: sdata
}]
});
});
});
In the version that works, data is an Array of Arrays of String ;
data: [["Arecleoch",21], ...
(Notice there is no oppening quotes before the first bracket).
In the version that does not work, it is a String representing the Array.
I suspect the charts API only expect an Array (in this case, an array of array, actually).
So it depends on what this does :
$.getJSON(url, null, function(data) {
// What is the type of data here ?
From your controller and the display of your debugger, I think data is itself an Array of Arrays. You should directly pass it to the charts API (without the sData = data.toString()) function wich actually transforms the Array ['a', 'b', 'c'] into a String representing the array, like "['a', 'b', 'c']");
// Callback parameter renamed to show it is an Array of Arrays
$.getJSON(url, null, function(aaData) {
// ... skipped ...
series: [{
type: 'pie',
name: 'Incidents by Site',
data: aaData /* Use the Array itself */
}]
Edit : my solution will only work if the controller output something like :
{
data : [[ "Arecleoch", 21], ["Whatever", 42]]
}
However it seems like your controller returns something like
{
data : "[['Arecleoch', 21],['Whatever', 42]]"
}
(Maybe without the { data : } part, I don't know if you need a top-level element or if you are derectly returning the Array in JSON)
Is that the case ? If so, then you'll have to either :
change the controller
parse the string on the client side, in javascript