How can I scale my dataset values as a percentage of the index in chart.js? - chart.js

Sorry if the question is poorly worded.Here is my chart
I am looking into scaling the chart's display of dataset(s) values as a percentage such as:
//input
data:{
datasets[{
label: 'data1',
data: [15, 22, 18, 35, 16, 29, 40]
},
{
label: 'data2',
data: [20, 21, 20, 19, 21, 22, 35]
}]
data1's points on the chart would be displayed as [42.9, 51.2, 47.4, 64.8, 43.2, 56.9, 57.1]
data2's points on the chart would be displayed as [57.1, 48.8, 52.6, 35.2, 56.8, 43.1, 42.9]
It should look like this. All visible lines should stack up to 100%. If a dataset is hidden, how can I recalculate the percentage and update the chart so that everything stays stacked up to 100%?
I thought about doing a plugin where I do the calculation using myLine.data.datasets but then I don't know how to remove a hidden dataset's values from the calculation and I'm not sure how to display it unless I overwrite the original datasets. I'm pretty sure this is the wrong approach.
Any help would be greatly appreciated.

So, I figured it out. I needed to write a function to calculate the percentage area of the points in the index and then update the datasets with the calculated percentage values.
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*
* DS_update calculates the percentage area of the input datasets
*
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function DS_update(dataset_in, ds_vis){
// make a deep copy (no references to the source)
var temp = jQuery.extend(true, [], dataset_in);
// gets the sum of all datasets at a given index
function getTotal(index){
total = 0;
// step through the datasets
dataset_in.forEach(function(e, i){
// inc total if the dataset is visible
if(ds_vis[i]){
total += e[index];
}
// do nothing if the dataset is hidden
});
return total;
}
// update temp array with calculated percentage values
temp.forEach(function(el, ind){
var j = ind;
el.forEach(function(e, i){
// calculate percentage to the hundredths place
temp[j][i] = Math.round((e / getTotal(i))*10000)/100;
});
});
return temp;
}
Once I tested the functions I had to run them before initial load of the chart or else the user would see the datasets as non area-percent (raw data). which looks something like this:
// Keep source array to use in the tool tips
var Src_ary = Input_data; // multidimensional array of input data
// holds the percent-area calculations as datapoints
var Prod_ary = DS_update(Src_ary, Init_visible(Src_ary));
Next up was updating the onClick for the legend. I need this to update the calculations every time an item's visibility is toggled:
legend: {
position: 'bottom',
usePointStyle: true,
onClick:
function(e, legendItem){
var index = legendItem.datasetIndex;
var ci = this.chart;
var meta = ci.getDatasetMeta(index);
var vis_ary = [];
var updatedSet = [];
// See controller.isDatasetVisible comment
meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
// load the visible array
for(var i = 0; i < (ci.data.datasets || []).length; i++){
switch (ci.getDatasetMeta(i).hidden){
case null:
vis_ary.push(true);
break;
default:
vis_ary.push(false);
break;
}
}
// update datasets using vis_ary to tell us which sets are visible
updatedSet = DS_update(Prod_ary, vis_ary);
myLine.data.datasets.forEach(function (e,i){
e.data = updatedSet[i];
});
// We did stuff ... rerender the chart
ci.update();
}
}
END RESULT
This is what I was trying to do: highchart fiddle
This is what I ended up with:fiddle
It took a few days and a lot of reading through chartjs.org's documentation to put this together. In the end I think it came out pretty good considering I am new to chart.js and borderline illiterate with javascript.

Related

How to add horizontal line at front of the line bullet in live data amcharts

i'm working on amchart live data you can check here https://www.amcharts.com/demos/live-data/. So i want to add horizonal line at front of the line bullet like you can check here https://iqoption.com/en/ in this site when you signup and click on trade there will be chart show. at front of the line bullet there is horizontal line i want like this. So let me know is it possible ??
Amchart is a quite popular charting library, and after a few minutes of searches, it is a quite easy task to do.
Based on the live-data demo provided by amchart your have to add some line to that code.
To start add an axisrange line to the chart.
// goal guides
var axisRange = valueAxis.axisRanges.create();
axisRange.value = 4;
axisRange.grid.strokeOpacity = 1;
axisRange.label.text = "Goal"; // This text will be displayed on the right side of chart.
axisRange.label.align = "right";
axisRange.label.verticalCenter = "bottom";
axisRange.label.fillOpacity = 0.8;
After this block you will see the vertical line on the chart but this will not move along the chart
In order to start to move the line you have to modify the startInterval() function
From the function your have access to the previously declared axisrange variable
so after getting the next value you have to assign this value to the axisrange position and label this way
function startInterval() {
interval = setInterval(function() {
visits =
visits + Math.random();
var lastdataItem = series.dataItems.getIndex(series.dataItems.length - 1);
chart.addData(
{ date: new Date(lastdataItem.dateX.getTime() + 1000), value: visits },
1
);
// Add this two line to the startinterval function or where you
calculate the next value
axisRange.value=visits;
axisRange.label.text=visits;
}, 1000);
}

Data with pair X and Y values

Is it possible to use a the pair X and Y in the data option in Chart.js to create the bar char?
data: [
['08/09/2016', 12],
['09/09/2016', 19]
],
Being in the form of [X, Y]
I didn't find any reference about it in the docs. The closer I got was this found in the line charts example:
data: [{
x: -10,
y: 0
}, {
x: 0,
y: 10
}, {
x: 10,
y: 5
}]
There is no built-in way to create your chart using an array straight into the data.
But you can create a small work around using Chart.js plugins. They let you handle events triggered during the whole creation of the chart, such as before it is initialized, after a resize, etc.
Follows a small plugin that will populate all the data for you using an array :
var myPlugin = {
// We edit what is happening before the chart is initialized.
beforeInit: function(chart) {
var data = chart.config.data;
// `APIarray` is what you get from your API.
// For every data in this array ...
for (var i = 0; i < APIarray.length; i++) {
// Populate the labels array with the first value ..
data.labels.push(APIarray[i][0]);
// .. and the data with the second value
data.datasets[0].data.push(APIarray[i][1]);
}
}
};
Then you need to add this newly created plugin to your Chart plugin services :
Chart.pluginService.register(myPlugin);
Make sure to register the plugin before creating the chart (before calling new Chart()), or else it won't work.
I also suggest to have an empty data in your chart (before the plugin occurs) to make sure you won't have data you don't want.
You can see a fully working example on this jsFiddle.

LineChart with certain columns

i am displaying a line chart and have data toggle on/off set up based on the answer (given by Abinaya Selvaraju) here:
Show/hide lines/data in Google Chart
it works great.
now i want to certain columns to be automatically grayed out when the chart first displays.
i think i need to do something like what's shown in the answer and came up with this:
for (var regionCol=0; regionCol<chartData.getNumberOfColumns();regionCol++){
if ((regionCol >= 2) && (regionCol <=7)){
columns[regionCol] = {
label: chartData.getColumnLabel(regionCol),
type: chartData.getColumnType(regionCol),
calc: function () {
return null;
}
};
// grey out the legend entry
//series[col - 1].color = '#CCCCCC';
series[Math.floor(regionCol/3)].color = '#CCCCCC';
}
else{
// show the data series
columns[regionCol] = regionCol;
//series[col - 1].color = null;
series[Math.floor(regionCol/3)].color = null;
}
}
var viewToHideRegions = new google.visualization.DataView(chartData);
viewToHideRegions.setColumns(columns);
chart.draw(viewToHideRegions, options);
/* code to set regions to be hidden */
This is how my chart data is defined:
chartData.addColumn('string', 'Date'); // Implicit series 1 data col.
chartData.addColumn('number', colIdxName); // Implicit domain label col.
chartData.addColumn({type:'string', role:'annotation'});
chartData.addColumn({type:'string', role:'annotationText'});
chartData.addColumn('number', dpndata[colGenIdx]['name']); // Implicit domain label col.
chartData.addColumn({type:'string', role:'annotation'});
chartData.addColumn({type:'string', role:'annotationText'});
When I run all of this, i get the message "All series on a given axis must be of the same data type"
I can't spot what I've got wrong.
Can anyone help?
There are a couple things you need to fix here. First, you only have 7 columns, and the column indices start at 0, so checking column indices 2-7 will start too late and overflow the end of the column list. Second, you always want your domain column (index 0) to be included, but you don't want to list it in the series option. Third, the "annotation" and "annotationText" columns need to have their roles specified in the view.
Your code should look something like this (to grey out all series by default):
var columns = [0];
for (var regionCol = 1; regionCol < chartData.getNumberOfColumns(); regionCol++) {
columns[regionCol] = {
label: chartData.getColumnLabel(regionCol),
type: chartData.getColumnType(regionCol),
role: chartData.getColumnProperty(regionCol, 'role'),
calc: function () {
return null;
}
};
// grey out the legend entry
if (regionCol % 3 == 1) {
series[Math.floor(regionCol / 3) - 1].color = '#CCCCCC';
}
}
var viewToHideRegions = new google.visualization.DataView(chartData);
viewToHideRegions.setColumns(columns);
chart.draw(viewToHideRegions, options);
/* code to set regions to be hidden */

google charts, tooltip replace column value

I'm using a combo chart from the google graph api (combo chart type). I want to add custom tooltips to add information about each point in the graph, but one of the value is replaced by the tooltip.
Here a very similar example graphic:
adding tooltip to graphs
Supposing that I'm using that graph. In my case, the value 106 (for the year 2011), is replaced by Growth 14% (the tooltip value)
Here the code that generates the data:
function gcomboChart () {
var data = new google.visualization.DataTable();
var dataVal =
[
["January",37903,655396,3411359,"Tooltip January"],
["February",33813,559595,3035931,"Tooltip February"],
["March",54073,725638,4561690,"Tooltip March"]
];
data.addColumn('string','month');
data.addColumn('number','Value1');
data.addColumn('number','Value2');
data.addColumn('number','Value3');
data.addColumn({type:'string', role:'tooltip'});
data.addRows(dataVal);
return(data);
}
//Here the code that generates the graph:
function drawChartComboChartID14cc19be5eef() {
var data = gcomboChart();
var options = { focusTarget: 'category'};
options["allowHtml"] = true;
options["seriesType"] = "bars";
options["series"] = {0: {targetAxisIndex:1,type:"line"}};
options["series"] = {0: {targetAxisIndex:2,type:"line"}};
options["vAxes"] = [{title:'Left Axis',format:'#,###',titleTextStyle:{color: 'orange'},textStyle:{color: 'orange'},textPosition:'out'},
{title:'Right Axis',format:'#,###',titleTextStyle:{color: 'blue'},textStyle:{color: 'blue'},textPosition:'out'}];
options["width"] = 1000;
options["height"] = 600;
options["pointSize"] = 9;
var chart = new google.visualization.ComboChart(
document.getElementById('ComboChart'));
chart.draw(data,options);
}
If you use the code, you'll see that the value of the third variable (Value3), is overwritten by the tooltip. I don't know hoy to get rid of that problem.
I want to show the three values of 'Value1-3' plus the tooltip
Can you please give me a hand?
Thanks!
Tooltips by default will replace the tooltip for that data point. It will not add an additional tooltip. To get around this, you need to add an additional series, and format the tooltip manually within that data value. You can then hide it from the legend, and have it display all nice as follows:
Here is the code:
function gcomboChart () {
var data = new google.visualization.DataTable();
//{v: x, f: y} allows you to set a manual format for each data point
var dataVal =
[
["January",37903,655396,3411359,{v: 0, f:"Tooltip January"}],
["February",33813,559595,3035931,{v: 0, f:"Tooltip February"}],
["March",54073,725638,4561690,{v: 0, f:"Tooltip March"}]
];
data.addColumn('string','month');
data.addColumn('number','Value1');
data.addColumn('number','Value2');
data.addColumn('number','Value3');
// Changed to standard data rather than tooltip role
data.addColumn('number','');
data.addRows(dataVal);
return(data);
}
//Here the code that generates the graph:
function drawVisualization() {
var data = gcomboChart();
var options = { focusTarget: 'category'};
options["allowHtml"] = true;
options["seriesType"] = "bars";
// the below line makes sure the tooltip is not shown in the legend
options["series"] = {0: {targetAxisIndex:0,type:"line"},3: {visibleInLegend:false}};
options["vAxes"] = [{title:'Left Axis',format:'#,###',titleTextStyle:{color: 'orange'},textStyle:{color: 'orange'},textPosition:'out'},
{title:'Right Axis',format:'#,###',titleTextStyle:{color: 'blue'},textStyle:{color: 'blue'},textPosition:'out'}];
options["width"] = 1000;
options["height"] = 600;
options["pointSize"] = 9;
var chart = new google.visualization.ComboChart(
document.getElementById('visualization'));
chart.draw(data,options);
}
Note: I should have switched series 3 to a line as well so that it doesn't push the bars over one. Change the series setting as follows to make it look nicer: options["series"] = {0: {targetAxisIndex:0,type:"line"},3: {visibleInLegend:false,type:"line"}};

Can I use different if-conditions in Highstock-code?

I want that my Highstock-Chart is very dynamic. I extract the number of series and yAxis from var dataarray. So I can get e.g. 2 series or 6 or 3 or or or...
But now I have to set the code for the yAxis and series according to the number of series that are arriving. And if dataarray is e.g. 2 long the program should jump in the accordingly if-condition.
But that doesn't work in real life. Here is my code. What can I do instead? Can't I use JavaScript in Highstock-Code?
No you can't, and it's not because Highstock, but Javascript langauge.
When you create chart in that way:
new Highcharts.StokChart({
//options
})
you are passing a literal { abc: something, xyz: somethineElse } where you can't put if-else conditions.
I think you can create something like this:
var xAxis,
series;
if(x == 2) {
xAxis = { /* options */ };
series = [ /* options */ ];
} else {
// something else
}
var chartName = new Highcharts.StockChart({
xAxis: xAxis,
series: series
});