I have existing charts that displays data for a full day 12:00am - 12:00am.
Now required to change one chart forward to display 4:00am - 4:00am.
I have managed to shift the x axis labels (.add(4, 'hours')) but the chart data is still in the same position.
How do I shift the charted data forward 4 hours?
Limited scope to change global variables as this will impact other charts.
var getChartSeries = function(response, chart_series_data) {
var lines = response.graph_data.lines;
for (var i=0; i<lines.length; i++) {
var series = lines[i];
var dateFormat = graphDateFormat;
if (chartIntraday) dateFormat = 'HH:mm:ss';
var currSeriesData = [];
for (var j=0; j<series.data.length; j++) {
var row = series.data[j];
var yValue = parseFloat(row[1]);
var point = {
x: moment(row[0], dateFormat).add(4, 'hours').valueOf(),
y: yValue,
displayValue: row[3]
};
currSeriesData.push(point);
}
// Set the series name, legend label, and the line identifier
var name = formatLegendLabel(series.display_name, response);
var label = response.label;
if (response.display_name != undefined && response.display_name != '') label = series.display_name + ' : ' + label;
By default chart adjusts extremes to the provided data. To display these few hours before the first point use xAxis.min property.
Live demo: http://jsfiddle.net/kkulig/xqdqooh9/
API reference: https://api.highcharts.com/highcharts/xAxis.min
Related
I have google chart (line chart), need to customize legend with some extra information. Please refer this http://plnkr.co/edit/ysZwYaAQpMhHarcA2UHq?p=preview [Plunker][1] to know more in detail. I want legend information like this below snap
So if you see in below image, and my fiddle I have R1, R2 , R3 and so on as releases to select, and each release has its own score, so I want that score to be shown as R1 100 just like below image.
Note that graph data is different, and the dropdown for selection of releases data is different. but both have releaseId R1 , R2. So on selection of dropdown value say R1,R2 or R3 I am pushing only that row from graphdata to drawgraph.
So basically, I need to show selected R1 score in legend.
Please give me some idea or link where this is done earlier. Thanks in advance.
to add the score to the legend,
you can add the score to the column label before drawing the chart
replace the drawChart function with the following...
function drawChart() {
var chartColors = [];
var chartColumns = [0];
var checks = document.getElementsByTagName('input');
for (var i = 0; i < $scope.selectedNewRelease.length; i++) {
var seriesColumn = getColumnIndex(x, $scope.selectedNewRelease[i].releaseId);
chartColumns.push(seriesColumn);
x.setColumnLabel(seriesColumn, x.getColumnLabel(seriesColumn) + ' ' + $scope.selectedNewRelease[i].score);
}
var view = new google.visualization.DataView(x);
view.setColumns(chartColumns);
chart.draw(view, options);
if ($scope.selectedNewRelease.length>0) {
$scope.Grtgraph=true;
}else{
$scope.Grtgraph=false;
}
}
function getColumnIndex(data, columnLabel) {
for (var i = 0; i < data.getNumberOfColumns(); i++) {
if (data.getColumnLabel(i) === columnLabel) {
return i;
}
}
}
I'm confused with my Google Apps script which is purposed to calculate the sum of the cells only if these cells are bold.
Here is the source:
function SumIfNotBold(range, startcol, startrow){
// convert from int to ALPHANUMERIC
// - thanks to Daniel at http://stackoverflow.com/a/3145054/2828136
var start_col_id = String.fromCharCode(64 + startcol);
var end_col_id = String.fromCharCode(64 + startcol + range[0].length -1);
var endrow = startrow + range.length - 1
// build the range string, then get the font weights
var range_string = start_col_id + startrow + ":" + end_col_id + endrow
var ss = SpreadsheetApp.getActiveSpreadsheet();
var getWeights = ss.getRange(range_string).getFontWeights();
var x = 0;
var value;
for(var i = 0; i < range.length; i++) {
for(var j = 0; j < range[0].length; j++) {
if(getWeights[i][j].toString() != "bold") {
value = range[i][j];
if (!isNaN(value)){
x += value;
}
}
}
}
return x;
Here is the formula:
=(SumIfNotBold(K2:K100,COLUMN(K2), ROW(K2)))*1
I have three major concerns:
When I set up a trigger to launch this script on any edits I accidentally receive an email from Google Apps stating that
TypeError: Cannot read property "length" from undefined. (line 7, file
"SumIfNotBold")
Thus, how can I fix it? Are there any ways to ignore these automatically delivered notifications?
The formula doesn't calculate the sum of cells if they are on the other list. For example, if I put the formula on B list but the cells are located on A list then this script doesn't work properly in terms of deriving wrong calculations.
When the cell values are updated the formula derivation is not. In this case I'm refreshing the formula itself (i.e., changing "K2:K50" to "K3:K50" and once back) to get an updated derivation.
Please, help me with fixing the issues with this script. Or, if it would be better to use a new one to calculate the sum in non-bold cells then I'll be happy to accept your new solution.
Here is a version of this script that addresses some of the issues you raised. It is invoked simply as =sumifnotbold(A3:C8) or =sumifnotbold(Sheet2!A3:C8) if using another sheet.
As any custom function, it is automatically recalculated if an entry in the range to which it refers is edited.
It is not automatically recalculated if you change the font from bold to normal or back. In this case you can quickly refresh the function by delete-undo on any nonempty cell in the range which it sums. (That is, delete some number, and then undo the deletion.)
Most of the function gets a reference to the passed range by parsing the formula in the active cell. Caveat: this is based on the assumption that the function is used on its own, =sumifnotbold(B2:C4). It will not work within another function like =max(A1, sumifnotbold(B2:C4).
function sumifnotbold(reference) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var formula = SpreadsheetApp.getActiveRange().getFormula();
var args = formula.match(/=\w+\((.*)\)/i)[1].split('!');
try {
if (args.length == 1) {
var range = sheet.getRange(args[0]);
}
else {
sheet = ss.getSheetByName(args[0].replace(/'/g, ''));
range = sheet.getRange(args[1]);
}
}
catch(e) {
throw new Error(args.join('!') + ' is not a valid range');
}
// everything above is range extraction from the formula
// actual computation begins now
var weights = range.getFontWeights();
var numbers = range.getValues();
var x = 0;
for (var i = 0; i < numbers.length; i++) {
for (var j = 0; j < numbers[0].length; j++) {
if (weights[i][j] != "bold" && typeof numbers[i][j] == 'number') {
x += numbers[i][j];
}
}
}
return x;
}
I am currently using Angular Chart (http://jtblin.github.io/angular-chart.js/)
I need to find the current dataset/series Index.
In my angular controller:
$scope.mainChart.series = ['Past year', 'Current year'];
$scope.mainChart.data = [
[10, 20, 30, 40], // 2015 - Index 0
[50, 60, 70, 80] // 2016 - Index 1
];
In the points array exists the property _datasetIndex. My onClick function is:
$scope.mainChart.onClick = function (points, event) {
$log.log( points[0]._datasetIndex ); // 0
$log.log( points[1]._datasetIndex ); // 1
};
How can I get the current series index that are clicked?
My canvas element is:
<canvas id="line" class="chart chart-line" chart-data="mainChart.data" chart-labels="mainChart.labels" chart-click="mainChart.onClick" chart-series="mainChart.series" chart-options="mainChart.options" chart-y-axes="mainChart.multiAxis" chart-legend="true" height="270"></canvas>
Lenin Meza: Your answer helped me.
Herewith I have posted shortcut/alternate way of fetching label and series.
$scope.mainChart.onClick = function (points, event) {
// Get current chart
var chart = points[0]._chart.controller;
var activePoint = chart.getElementAtEvent(event);
if (activePoint.length > 0) {
// Get current Dataset
var model = activePoint[0]._model;
// Get current serie by dataset index
var series = model.datasetLabel;
//get the internal index of slice in pie chart
var clickedElementindex = activePoints[0]["_index"];
//get specific label by index
var label = model.label;
//get value by index
var value = chart.data.datasets[dataset].data[clickedElementindex];
}
};
Angular-Chart is wrapped around AngularJS+Chart.js. According to Chart.js you have this http://www.chartjs.org/docs/#advanced-usage-prototype-methods ..getElementsAtEvent(e) if you could find the Chart instance.
Otherwise, if you are running out of time you can do the following.
First you need to distinguish all the points, so there are no points that have the same (label & series index & data set index).
function induceIndex(point){
//FIND the INDEX of the SET
var dataSetIndex= $scope.mainChart.series.findIndex(sElem=>sElem === point.dataSetLabel);
//GET the SET itself
var dataSet = $scope.mainChart.data[seriesIndex];
//FIND the POINT in the DATASET asserting that it is at the same INDEX of its LABEL
var pointIndex = dataset.findIndex((dElem,index)=>dElem=== point.value && $scope.mainChart.labels[index] === point.label);
//do what you want
return pointIndex;
}
I have multiple Charts in my Dashboard and i resolve this with this code:
$scope.mainChart.onClick = function (points, event) {
// Get current chart
var chart = points[0]._chart.controller;
var activePoint = chart.getElementAtEvent(event);
if (activePoint.length > 0) {
// Get current Dataset
var dataset = activePoint[0]._datasetIndex;
// Get current serie by dataset index
var serie = $scope.mainChart.series[dataset];
//get the internal index of slice in pie chart
var clickedElementindex = activePoints[0]["_index"];
//get specific label by index
var label = chart.data.labels[clickedElementindex];
//get value by index
var value = chart.data.datasets[dataset].data[clickedElementindex];
}
};
I am creating a scattered Graph using NVD3 using the code they have provided in their limited documentation. I have created a Scatter graph function that loops over a JSON and pushes the values to the data array.
Now I have 2 values for x axis in my Json , x and run Number. What i want is that the graph should be plotted for the value "x" (which have equal gaps) but it should display values of Run Number on the x axis (which have unequal gaps). We want to do this to make the graph more symmetric, as it is not important for us to display the gaps in graph accurately.
What i did was create a new Array xAxisValue and push the Run Numbers onto it while we loop the JSON to get values. values for x are pushed onto the data array ,
Then using
chart.xAxis.axisLabel('Run No.').tickFormat(d3.format('0d')).tickValues(
xAxisValue);
I set the Tick Values to the xAxisValue (run Number) and then pass the data variable to the draw chart function
d3.select('#chart svg').datum(myData).call(chart);
But this does not seem to work. My Axis is blank and hovering over a value displays the tool tip displays values of x instead of run number.
Because we are dynamically updating the graph i have separated the add Graph and upgrade graph function
Here is the code
function addGraph() {
var jsons = [];
chart = nv.models.scatterChart().showDistX(true).showDistY(true)
.transitionDuration(350).color(d3.scale.category10().range());
chart.tooltipContent(function(key) {
return '<h3>' + key + '</h3>';
});
chart.scatter.onlyCircles(false);
var myData = scatterData(2, 11, jsons);
d3.select('#chart svg').datum(myData).call(chart);
// add zoom handler
nv.utils.windowResize(chart.update);
return chart;
}
Upgrade Graph Function
function upgradeGraph() {
minValue = 1000000, maxValue = 0, minValueY = 100000000, maxValueY = 0;
var jsons = [];
d3.select('svg').text('');
if ($("#check2").is(':checked')) {
jsons.push("charge_ONTk_Barrel_L2_mpv.json");
}
if ($("#check1").is(':checked')) {
jsons.push("charge_ONTk_Barrel_L1_mpv.json");
}
if ($("#check3").is(':checked')) {
jsons.push("charge_ONTk_Barrel_L3_mpv.json");
}
var myData = scatterData(2, 11, jsons);
chart.xAxis.axisLabel('Run No.').tickFormat(d3.format('0d')).tickValues(
xAxisValue);
chart.yAxis.axisLabel('S/N (mpv)').tickFormat(d3.format('.04f'));
for (var i = 0; i < xAxisValue.length; i++) {
console.log("Run Number: " + xAxisValue[i]);
}
console.log("Min Y: " + minValueY + " Max Y " + maxValueY);
chart.forceX([ minValue - 2, maxValue + 2 ]);
chart.forceY([ minValueY - 3, maxValueY + 3 ]);
d3.select('#chart svg').datum(myData).call(chart);
// add zoom
addZoom({
xAxis : chart.xAxis,
yAxis : chart.yAxis,
yDomain : chart.yDomain,
xDomain : chart.xDomain,
redraw : function() {
chart.update();
},
svg : chart.svg
});
nv.utils.windowResize(chart.update);
return chart;
}
And the ScatterData Function
function scatterData(groups, points, jsons) {
var data = [];
data.push({
key : 'Error',
values : [],
color : '#FBEC5D'
});
data.push({
key : 'Bin Content ',
values : [],
color : '#0D4F8B'
});
for (var i = 0; i < jsons.length; i++) {
xAxisValue = [];
var jsonURL = jsons[i];
var xmlhttp = new XMLHttpRequest();
var url = "alljsons/" + jsons[i];
var parameters = location.search;
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var myArr = JSON.parse(xmlhttp.responseText);
var jsonName = jsonURL.split(".");
var temp = jsonName[0];
var value = myArr[temp];
// $(".title" + loop).html(temp);
for ( var i in value) {
if (value[i].run > maxValue) {
maxValue = value[i].x;
}
if (value[i].run < minValue) {
minValue = value[i].x;
}
if (value[i].y > maxValueY) {
maxValueY = value[i].y;
}
if (value[i].y < minValueY) {
minValueY = value[i].y;
}
xAxisValue.push(value[i].run);
data[1].values.push({
x : value[i].x,
y : value[i].y,
size : 6 // Configure the size of each scatter point
,
shape : "circle"
});
var err = value[i].y - value[i].yErr;
if (err < 0) {
err = 0;
console.log("error: " + err);
}
data[0].values.push({
x : value[i].x,
y : err,
size : 6 // Configure the size of each scatter point
,
shape : "triangle-down"
});
}
}
};
xmlhttp.open("GET", url, false);
xmlhttp.send();
}
return data;
}
Here is the Output i am getting
If I understand your question correctly:
For the x-axis ticks, I would use D3's axis.tickformat function. You could create a function mapXToRunNumber(x) that takes an x value and returns a run number (you seem to be close to having this already). Then, you would use: chart.xAxis.tickFormat(mapXtoRunNumber);
For the tooltip to also show the same value as the x-axis, you would use the nvD3 function chart.interactiveLayer.tooltip.headerFormatter(mapXToRunNumber).
Is it possible to get the lowest value in the chart itself assuming that the data is dynamic?Take a look at this example Fiddle.
$(function () {
var d1 = [];
for (var i = 0; i < 14; i += 0.5)
d1.push([i, Math.sin(i)]);
$.plot($("#placeholder"), [ d1]);
});
How can I get the lowest value in this line chart?
Update: It seems my earlier example didn't quite make sense please take a look at this link: https://abtw.alliancebernstein.com.tw/APAC/TW/Funds/American-Income.htm?ShareClassId=60006908 make sure to turn off Flash plugin so that Flotchart will render. Now looking at the area chart I want to get the lowest value base on the chart rendered. Is this possible?
If you save your plot object like so
var plot = $.plot($("#placeholder"), [ d1]);
you can get the minimum value from it with
var minimum = plot.getData()[0].yaxis.datamin;
The same is possible for maximum value (datamax), for the xaxis and for other data series (the index behind getData()).
http://jsfiddle.net/fenderistic/Sf5Yr/
Simply keep a lowest variable, and check throughout the for-loop to see if the value lower, if so, replace the current lowest value with it.
$(function () {
var d1 = [];
//Assuming you're always starting at zero
var lowest = Math.sin(0);
for (var i = 0; i < 14; i += 0.5) {
d1.push([i, Math.sin(i)]);
if (Math.sin(i) < lowest) {
lowest = Math.sin(i);
}
}
alert(lowest)
$.plot($("#placeholder"), [d1]);
});