Declare min and max values from a CSV - javascript

I wish to be able to determine the minimum and maximum for each series in the below (series being pH, ORP, Tank, Heater and Room). Tank, Heater and Room should all be written to the same min and max variable as they display on the same scale (ie. Show me the min or max of any of the 3 sets of data – being Min of 22.20 & Max being 24.33 from the sample data below)
The raw data being imported is in the following format (there are far more columns)
For a complete sample see http://macca.myreef.info/24hr_final.csv
Sample:
pnt_1 1375935000.00 1375935300.00 1375935600.00 1375935900.00
pH 8.34 8.35 8.36 8.36
ORP 415.24 415.44 415.05 414.74
Tank 24.27 24.26 24.20 24.22
Heater 24.33 24.30 24.30 24.30
Room 22.20 22.32 22.44 22.52
Where pnt_1 is rubbish, column 1 is the "header", row 1 is epoch and the remaining data is the value (at that epoch time).
Hope I haven't lost you as yet.
Using the code below I have managed to get Highcharts to display almost as I want it – see http://macca.myreef.info/test1.html
I want to be able to
Declare the min and max of each row (treating the tank, Heater and Room row as 1) as a variable.
Use the min and max variables to set the axis
Eg. If minph = 8.34 and maxph = 8.36 I might declare
var minphscale = minph*0.9
var maxphscale = maxph*1.1
The reason for wanting to do this as variables is I am also working of presenting the most recent data as a Highchart of type gauge where I will use the variables to set the “bands” of color to indicate the amount of swing any given series has had as well as the actual series value as being the most recent sample. The variables minph and maxph would determine the band (Geez – I hope that makes sense.)
Current code is
<html>
<head>
<meta http-equiv = "Content-Type" content = "text/html; charset = utf-8">
<meta http-equiv = "refresh" content = "180">
<meta http-equiv = "cache-control" content = "no-cache">
<title>Daily Data</title>
<!-- 1. Add these JavaScript inclusions in the head of your page -->
<script src = "http://code.jquery.com/jquery-1.9.1.js"></script>
<script type = "text/javascript"
src = "http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
</script>
<script type="text/javascript" src="/js/highcharts.js"></script>
<!-- 2. Add the JavaScript to initialize the chart on document ready -->
<script type="text/javascript">
var minph = 13;
$(document).ready(function() {
var options = {
credits: {
enabled: false
},
plotOptions: {
line: {
marker: {
enabled: false
}
}
},
chart: {
renderTo: 'container',
type: 'line',
marginRight: 130,
marginBottom: 25,
zoomType: 'x',
spacingRight: 2
},
title: {
text: '24hr history',
x: -20 //center
},
subtitle: {
text: 'Temp',
x: -20
},
xAxis: {
tickInterval:60,
categories: []
},
yAxis: [
{ //Primary [0]
title: {
text: 'orp'
},
id: 'ORP',
opposite: true,
min: 350,
max: 450
},
{ //Secondary [1]
title: {
text: 'pH'
},
id: 'pH',
min: 8,
max: 9
},
{ //Tertiary [2]
title: {
text: 'Temp'
},
id: 'Temp',
min: 20,
max: 30,
opposite: false
}],
tooltip: {
crosshairs: true,
shared: true
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'top',
x: -10,
borderWidth: 1
},
series: []
};
$.get('24hr_final.csv', function(data) {
// Split the lines
var lines = data.split('\n');
$.each(lines, function(lineNo, line) {
var items = line.split(',');
// Below is an attempt to change UNIX EPOCH to Java EPOCH
// and load into series1 as a date
if (lineNo === 0) {
$.each(items, function(itemNo, item) {
if (itemNo > 0) {
var javaepoch = (item) / 0.001;
var date = new Date(javaepoch);
options.xAxis.categories.push(date);
}
});
} else {
var series = {
data: []
};
$.each(items, function(itemNo, item) {
if (itemNo === 0) {
// Set the Axis for each data type
series.name = item;
if (item == 'pH') {
series.yAxis = item;
}
if (item == 'ORP' ) {
series.yAxis = item;
}
if (item == 'Tank' ) {
series.yAxis = 'Temp';
}
if (item == 'Heater' ) {
series.yAxis = 'Temp';
}
if (item == 'Room' ) {
series.yAxis = 'Temp';
}
// Finished mods for axis
} else {
var minph = 5;
series.data.push(parseFloat(item));
}
});
options.series.push(series);
}
});
var chart = new Highcharts.Chart(options);
});
});
</script>
</head>
<body>
<div id = "container" style = "width: 100%; height: 400px; margin: 0 auto">
</div>
<script>
document.write ("Min pH is " + minph + ". <BR>")
</script>
Test 1
</body>
</html>

Well, I think you can do this in that way:
else {
var minph = 5,
val = parseFloat(item);
series.data.push(val);
// get min and max
series.minVal = series.minVal < val ? series.minVal : val;
series.maxVal = series.maxVal > val ? series.maxVal : val;
}
Then before creating chart set for connected yAxis minVal and maxVal as min and max. If you want to have three rows connected to one yAxis, compare that rows minVal and maxVal and choose min and max value of them.

Related

Multiple charts with same data not loading in same page: Highcharts

I am trying to display Highchart having same data in custom no. of times, Say I want to display the chart 2 times in same pagedynamically.
What I have done is that I set the chart in for loop in which I can repeat the chart multiple times dynamically.
Here is the Script That I have tried.
var len = 2 ;
var chartArea = document.getElementById("content");
for(var i=0;i<len;i++)
{
console.log("I", i);
chartArea.innerHTML +=
'<div id="container'+i+'"></div>';
var categories = ["1","2","3","4","5","6","7","8","9","10"];
Highcharts.stockChart('container'+i, {
rangeSelector: {
enabled: false
},
xAxis: {
labels: {
formatter: function() {
return categories[this.value];
}
}
},
navigator: {
xAxis: {
labels: {
formatter: function() {
return categories[this.value];
}
}
}
},
plotOptions: {
series: {
animation: {
duration: 2000
},
marker:{
enabled: false
}
}
},
series: [{
data: [3,5,3,6,2,6,4,9,4,6]
}]
});
But the problem is that only last graph shows the line chart. the other first chart have the x-axis labels bu the line graph is not showing.
Here is the Fiddle That I have tried.
http://jsfiddle.net/abnitchauhan/cenmohbw/
You forgot to append the child to the DOM tree.
When you create a new HTML element dynamically, it needs to be attached to an existing node in the DOM tree.
In Javascript you can do:
var existingNode = document.getElementById("content");
var newElement = document.createElement("div");
newElement.id = "someID";
existingNode.appendChild(newElement);
In jQuery, its more easy:
$("#content").append(`<div id="someID"></div>`);
In your case, the change would look like (only for loop changes) as:
for (var i = 0; i < len; i++) {
console.log("I", i);
$("#content").append(`<div id="container${i}"></div>`);
// rest of your code

Remove slice onClick events on Pie Charts in Chart.js

I have a question regarding piecharts on Chart.js.
What would be the best way to remove a slice when clicking on it?
I'm aware the method getSegmentsAtEvent() can be used to read the slice properties.
It's possible to find out which slicing I'm clicking looping through the slices object until a match is found.
Is there a simpler way to achieve it?
tks
This can be achieved using the functions: getSegmentsAtEvent(event) and removeData( index ) Chart.js API
With getSegmentsAtEvent you can recover the segment that has been clicked.
The next step, is to find the index of the slice in the chart. To do the search, you can iterate through all the current segments of the chart and call removeData when it's found. (I think there is no way to directly know the index)
var segments = myChart.segments;
for (var index = 0; index < segments.length; index++) {
if (activeLabel == segments[index].label) {
myChart.removeData(index);
}
}
Full demo:
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-2.0.2.js"></script>
<script type="text/javascript" src="Chart.js"></script>
<script type="text/javascript">
var data = [
{
value: 300,
color:"#F7464A",
highlight: "#FF5A5E",
label: "Red"
},
{
value: 50,
color: "#46BFBD",
highlight: "#5AD3D1",
label: "Green"
},
{
value: 100,
color: "#FDB45C",
highlight: "#FFC870",
label: "Yellow"
}
];
$(document).ready(
function () {
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx).Pie(data);
$("#myChart").click(
function(evt){
var activePoints = myChart.getSegmentsAtEvent(evt);
var activeLabel = activePoints[0].label;
var segments = myChart.segments;
for (var index = 0; index < segments.length; index++) {
if (activeLabel == segments[index].label) {
myChart.removeData(index);
}
}
}
);
}
);
</script>
</head>
<body>
<canvas id="myChart" width="400" height="400"></canvas>
</body>
</html>
Get the onclick property in options of chart.
This onclick event will trigger even when you click outside of pie (anywhere in canvas), so you have to filter it out by using myChart.getElementsAtEvent(event);
Get data of chart and then remove an item using checks(In the following snippet you can only remove china or any country with value less than 50).
Update the chart by using .update() method
Following is the required working snippet
var chart_click_event = function(event) {
debugger;
let activePoints = myChart.getElementsAtEvent(event);
//If you click on empty area this if check will not pass.
if (activePoints[0]) {
let chartData = activePoints[0]['_chart'].config.data;
let idx = activePoints[0]['_index'];
let label = chartData.labels[idx];
let value = chartData.datasets[0].data[idx];
if (label == 'China' || value < 50) {
chartData.labels.splice(idx, 1);
chartData.datasets[0].data.splice(idx, 1);
myChart.update();
}
}
}
var data = [{
data: [50, 55, 60, 33],
backgroundColor: [
"#4b77a9",
"#5f255f",
"#d21243",
"#B27200"
],
borderColor: "#fff"
}];
var options = {
tooltips: {
enabled: true
},
plugins: {
datalabels: {
color: '#fff',
}
},
onClick: chart_click_event
};
var ctx = document.getElementById("pie-chart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: ['Pakistan', 'China', 'US', 'Canada'],
datasets: data
},
options: options
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.7.0"></script>
<canvas id="pie-chart"></canvas>

setting google chart multiple axes from dynamically generated data

I'm trying to replicate the following code from a working example:
series: {0: {targetAxisIndex:0},
1: {targetAxisIndex:0},
2: {targetAxisIndex:1},
This is for setting which y-axis is used to plot different columns from a dataTable on a Google chart.
However I have a variable number of columns (based on user input), therefore am collecting an array of the required axis (the axisAssignment Array in the below example).
My code is below:
var series = {};
for (i=0;i<axisAssignment.length;i++)
{
series[i] = {targetAxisIndex: axisAssignment[i]};
}
return series;
However, all of my data is only being written to the left axis, despite the debugger suggesting that the object is correct. My option code is below:
var options =
{
hAxis: {title: xTitle},
vAxes: {0: {title: y1Type},
1: {title: y2Type}
},
series: calculateSeries(),
pointSize: 1,
legend: {position: 'top', textStyle: {fontSize: 10}}
};
Any assistance would be greatly apreciated.
Thanks
Tom
edit: whole file for reference (it's a work in progress so a bit of a mess I'm afraid)
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart());
function drawChart()
{
var title = "Node: "+currentNode;
var xTitle = "Date";
var yTitle = titles[currentVariable];
if (totalData !== null)
{
var tempData = newData();
var tempData2 = totalData;
dataArray[dataCount] = tempData;
var joinMark = countArray(dataCount);
totalData = google.visualization.data.join(tempData2,tempData,'full',[[0,0]],joinMark,[1]);
dataCount = dataCount+1;
}
else
{
totalData = newData();
dataArray[dataCount] = totalData;
dataCount = 1;
}
var options =
{
hAxis: {title: xTitle},
vAxes: {0: {title: y1Type},
1: {title: y2Type}
},
series: calculateSeries(),
pointSize: 0.5,
legend: {position: 'top', textStyle: {fontSize: 10}}
};
var chart = new google.visualization.ScatterChart(document.getElementById('graph'));
console.log(calculateSeries());
chart.draw(totalData, options);
function countArray(count)
{
var arrayCount= new Array();
if (count===1)
{
arrayCount[0] = count;
}
else
{
for (var i=0;i<count;i++)
{
var temp = i+1;
arrayCount[i] = temp;
}
}
return arrayCount;
}
function calculateSeries()
{
var series = {};
for (i=0;i<axisAssignment.length;i++)
{
series[i] = {targetAxisIndex: axisAssignment[i]};
}
return series;
}
function newData()
{
var dataType = dataIn[0];
dataIn.shift();
var axis = dataSelect(dataType);
axisAssignment.push(axis);
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', "Node: "+currentNode+": "+titles[currentVariable]);
var num = (dataIn.length);
data.addRows(num/2);
var i = 0;
var j = 0;
while (i<num)
{
var d = (dataIn[i]);
if (i%2===0)
{
d = new Date(d);
data.setCell(j,0,d);
i++;
}
else
{
data.setCell(j,1,parseFloat(d));
i++;
j++;
}
}
return data;
}
function dataSelect(type)
{
var axisNumber;
if (y1Type === null || y1Type === type)
{
y1Type = type;
axisNumber = 0;
}
else if (y2Type === null || y2Type === type)
{
y2Type = type;
axisNumber = 1;
}
else
{
alert("You already have 2 axes assigned.\n\nPlease clear the graph \nor select more objects of \ntype"+y1Type+" or \ntype "+y2Type+" to continue.");
axisNumber = null;
}
return axisNumber;
}
}
Ok, it seems that it's an issue with my choice of ScatterChart,
var options =
{
hAxis: {title: xTitle},
series: calculateSeries(),
vAxes: {0: {title: y1Type },
1: {title: y2Type}
},
pointSize: 0.5,
legend: {position: 'top', textStyle: {fontSize: 10}}
};
var chart = new google.visualization.LineChart(document.getElementById('graph'));
chart.draw(totalData, options);
I've changed it to LineChart and it's working fine, by keeping the pointSize option, the appearance is almost completely unchanged. Thanks for your help juvian.

plotting realtime data and turning on and off data series using flot api

I am using flot charts. I want to plot chart which is updated per second and also want to add the feature of turning off and on the data series.
I am able to make it work but has problems which I did not expect, like color of one series change when other series is turned off; other is when I update the array of data series the charts seems to move but it removes element from the right,at the same time the new value is plotted on the right hand side ...
var d1 = [] ;
var d2 = [] ;
var d3 = [] ;
$(function(){
{%for reading in readings%}
var time_stamp = parseFloat({{reading['timestamp']}} + 19800.00) * 1000
var A = parseFloat({{reading['values']['A']}}) ;
var V = parseFloat({{reading['values']['VLN']}}) - 50 ;
var W = parseFloat({{reading['values']['W']}}) / 1000 ;
d1.push([time_stamp,A]);
d2.push([time_stamp,V]);
d3.push([time_stamp,W]);
{%endfor%}
var datasets = {
"current":{
label : "A",
data : d1
},
"voltage":{
label : "V",
data : d2
},
"power":{
label : "W",
data : d3
},
}
var i = 0;
$.each(datasets, function(key, val) {
val.color = i;
++i;
});
// insert checkboxes
var choiceContainer = $("#choices");
$.each(datasets, function(key, val) {
choiceContainer.append("<br/><input type='checkbox' name='" + key +
"' checked='checked' id='id" + key + "'></input>" +
"<label for='id" + key + "'>"
+ val.label + "</label>");
});
choiceContainer.find("input").click(plotAccordingToChoices);
function plotAccordingToChoices() {
var data = [];
choiceContainer.find("input:checked").each(function () {
var key = $(this).attr("name");
if (key && datasets[key]) {
data.push(datasets[key]);
}
});
if (data.length > 0) {
$.plot("#placeholder", data, {
series: {
shadowSize: 0,
lines: {
show: true
},
},
yaxis: {
min: 0
},
xaxis: {
tickDecimals: 0,
mode:"time"
}
});
}
setTimeout(getNextDataset,1000);
}
plotAccordingToChoices();
});
function getNextDataset()
{
$.ajax({url : '/newdata' , success:function(result){
reading =JSON.parse(result);
var time_stamp = (parseFloat(reading.timestamp) + 19800.00) * 1000
var A = parseFloat(reading.values.A) ;
var W = parseFloat(reading.values.W) / 1000 ;
var V = parseFloat(reading.values.VLN) - 50 ;
d1.shift();d2.shift();d3.shift();
d1.push([time_stamp,A]);
d2.push([time_stamp,V]);
d3.push([time_stamp,W]);
var datasets = {
"current":{
label : "A",
data : d1
},
"voltage":{
label : "V",
data : d2
},
"power":{
label : "W",
data : d3
},
}
var data = [] ;
var choiceContainer = $("#choices");
choiceContainer.find("input:checked").each(function () {
var key = $(this).attr("name");
if (key && datasets[key]) {
data.push(datasets[key]);
}
});
if (data.length > 0) {
$.plot("#placeholder", data, {
series: {
shadowSize: 0,
lines: {
show: true
},
points:{
show:false
},
},
yaxis: {
min: 0
},
xaxis: {
tickDecimals: 0,
mode:"time"
}
});
}
}
});
setTimeout(getNextDataset,1000) ;
}
`
I am making use of code available in flot charts examples.Where am I going wrong ??
Thank you ?
Problem 1 : Color updating every time a checkbox was checked or unchecked
Reason: Every time the checkbox click event was triggered,some how the color used to get updated
Solution : Removed setTimeout(getNextDataset,1000); call from the function plotAccordingToChoices()
Problem 2: The data elements are removed from the right instead of left.
Reason : (Very dumb) Data was coming in descending order and I was using pushing data in that order only.So latest point was at location 0 of the array and oldest point was at location n-1.And I was removing (n-1)th point.
Solution : Replaced push in the beginning with unshift().Did the magic :P

HighCharts Loading from CSV File with Many Data Points

After much searching and wanting to bang my head against my desk, I'm posting my first question on stackoverflow.
I've got an ASP.NET web application that is generating some data on the server side and creating a CSV file on the server.
I'm using HighCharts to produce a graph. Everything is working great, however, depending on what kind of date range a user runs there can be a few data points or many data points.
The problem comes in when there are many data points. Look at the X-Axis, and you'll see what I mean. Is there anyway to "group" these where it doesn't show every single point on the X-Axis?
The dates are at random intervals.
I've created a JSFiddle with my client side code and the contents of my CSV file in a JavaScript variable.
Here is my code:
function parseDate(dateStr) {
var matches = dateStr.match(/([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{4})/)
return Date.UTC(matches[3], matches[1]-1, matches[2]);
}
var csv = 'Chart,3/4/2007,3/24/2007,4/13/2007,4/25/2007,9/19/2007,9/28/2007,11/5/2007,1/7/2008,1/14/2008,1/21/2008,1/27/2008,2/3/2008,2/10/2008,2/17/2008,2/24/2008,3/2/2008,3/23/2008,3/30/2008,4/5/2008,4/21/2008,5/3/2008,5/10/2008,5/17/2008,5/24/2008,5/31/2008,6/8/2008,6/15/2008,6/29/2008,7/4/2008,7/18/2008,7/25/2008,8/1/2008,8/8/2008,9/17/2010,11/25/2010,8/16/2012,1/17/2013,1/27/2013\nDates,180.00,175.50,167.00,166.50,170.00,171.50,174.00,163.00,162.50,164.00,166.50,166.50,167.50,170.00,170.00,171.00,169.00,166.50,166.00,166.50,162.00,160.00,160.50,162.50,164.00,164.00,165.00,165.50,166.00,169.00,171.00,170.00,171.00,165.00,165.00,189.00,177.00,175.50';
var options = {
chart: {
renderTo: 'chart',
defaultSeriesType: 'line'
},
title: {
text: 'Test Chart'
},
xAxis: {
type: 'datetime',
categories: []
},
yAxis: {
title: {
text: 'Pounds'
}
},
series: []
};
// Split the lines
var lines = csv.split('\n');
$.each(lines, function(lineNo, line) {
var items = line.split(',');
if (lineNo == 0) {
$.each(items, function(itemNo, item) {
if (itemNo > 0) options.xAxis.categories.push(parseDate(item));
});
}
else {
var series = {
data: []
};
$.each(items, function(itemNo, item) {
if (itemNo == 0) {
series.name = item;
} else {
series.data.push(parseFloat(item));
}
});
options.series.push(series);
}
});
var chart = new Highcharts.Chart(options);
Here is the link to JSFiddle:
http://jsfiddle.net/Q2hyF/6/
Thanks in Advance,
Robert
Check out HighStocks and its DataGrouping feature:
http://www.highcharts.com/stock/demo/data-grouping
It can handle much larger datasets than HighCharts can. However, there are drawbacks as the newest HighCharts features are not always immediately in HighStocks. There are generally only minor changes needed to your syntax to use HighStocks, if you want to test it.
I ended up getting this working and never posted the answer... Here is the answer.
Take a close look at:
series.data.push([parseDate(points[0]), parseFloat(points[1])]);
in the code below...
function parseDate(dateStr) {
var matches = dateStr.match(/([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{4})/)
return Date.UTC(matches[3], matches[1] - 1, matches[2]);
}
var csv = 'Chart,11/1/2013|6,11/2/2013|4,11/3/2013|6,11/4/2013|3,11/5/2013|5,11/6/2013|5,11/7/2013|5,11/8/2013|6,11/9/2013|4,11/10/2013|13,11/11/2013|12,11/12/2013|3,11/13/2013|5,11/14/2013|7,11/15/2013|9,11/16/2013|0,11/17/2013|2,11/18/2013|3,11/19/2013|2,11/20/2013|16,11/21/2013|6,11/22/2013|9,11/23/2013|9,11/24/2013|20,11/25/2013|10,11/26/2013|10,11/27/2013|4,11/28/2013|9,11/29/2013|7,11/30/2013|7';
var options = {
chart: {
renderTo: 'chart',
type: 'line'
},
title: {
text: 'Sales'
},
xAxis: {
type: 'datetime'
},
series: []
};
var lines = csv.split('\n');
$.each(lines, function (lineNo, line) {
var items = line.split(',');
var series = {
data: []
};
$.each(items, function (itemNo, item) {
if (itemNo == 0) {
series.name = item;
} else {
var points = item.split('|');
series.data.push([parseDate(points[0]), parseFloat(points[1])]);
}
});
options.series.push(series);
});
var chart = new Highcharts.Chart(options);
http://jsfiddle.net/rswilley601/gtsLatyr/

Categories