How to integrate a dynamic graph in a webpage? - html

I am getting dynamically generated data from my Raspberry PI in .csv format and I want to make a webpage for my institute to analyze the waveform of the output . The main feature of this graph is that the graph should auto-update according to the modified data. How should I go about making this?

I am assuming that the solution you are looking for must work in HTML 5 and JavaScript where there is NO server side processing. The raspberry pi posts a file to the server.
We are using morris charts which is JavaScript library
http://morrisjs.github.io/morris.js/
Morris uses a json format
1: read the csv file
2: convert the csv data to a json object
3: initialise the chart
try this example csv data
"elapsed","value",b
"Oct-12",24,2
"Oct-13",34,22
"Oct-14",33,7
"Oct-15",22,6
"Oct-16",28,17
"Oct-17",60,15
"Oct-18",60,17
"Oct-19",70,7
"Oct-20",67,18
"Oct-21",86,18
"Oct-22",86,18
$(document).ready(function() {
$.ajax({
url: "linechartdata.csv",
success: function(data) {
processData(data)
}
});
});
function processData(data) {
var record_num = 3; // or however many elements there are in each row
var dataLines = data.split(/\r\n|\n/);
var entries = dataLines[0].split(',');
var records = [];
var headers = entries.splice(0, record_num);
console.log(dataLines.length)
for (var i = 1; i < dataLines.length; i++) {
var obj = dataLines[i].split(',');
if (obj.length == headers.length) {
var tarr = [];
for (var j = 0; j < headers.length; j++) {
//doing it this way to get strings and numbers
var field01;
var field02;
var field03;
if (j == 0) {
field01 = obj[j]
}
if (j == 1) {
field02 = obj[j]
}
if (j == 2) {
field03 = obj[j]
}
var o = {
elapsed: field01,
value: field02,
b: field03
}
records.push(o);
}
}
}
initChart(records)
}
function initChart(records) {
var chart = Morris.Line({
element: 'morris-chart-network',
data: records,
axes: false,
xkey: 'elapsed',
ykeys: ['value', 'b'],
labels: ['Download Speed', 'Upload Speed'],
yLabelFormat: function(y) {
return y.toString() + ' Mb/s';
},
gridEnabled: false,
gridLineColor: 'transparent',
lineColors: ['#5b6b79', '#a5a5a5'],
lineWidth: [2, 1],
pointSize: [0, 2],
fillOpacity: .7,
gridTextColor: '#999',
parseTime: false,
resize: true,
behaveLikeLine: true,
hideHover: 'auto'
});
};
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Morris Chart</title>
</head>
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js"></script>
<body>
<div>Morris Chart</div>
<div id="morris-chart-network" style="width:800px;height:600px">
</div>
<div>
example
</div>

Related

Razor chart.js labels/data not in sync

I have a Razor application that generates three columns of data to use in a chart graph. The page and javascript to do that looks like this:
<div><canvas id="myChart"></canvas></div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
var Maanden = [];
var Totalen = [];
#foreach (var m in Model.Grafieks)
{
#:Maanden.push("#m.maand" + "-" + "#m.jaar");
#:Totalen.push(#m.Total);
}
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: Maanden,
datasets: [
{ label: 'Facturen €',
data: Totalen,
backgroundColor: 'rgb(255, 255, 132)',
borderColor: 'rgb(255, 99, 132)',
borderWidth: 1,
}
]
},
});
</script>
Problem is that the labels are displayed OK but the data is off. Every second column is empty and its data pushed to the next column:
Chrome says:
Is there something wrong pushing the data into the arrays?
I had to convert the comma in decimal Totalen to a period!
#foreach (var m in Model.Grafieks)
{
#:Maanden.push("#m.maand" + "-" + "#m.jaar");
<text>bedrag = parsePotentiallyGroupedFloat("#m.Total");</text>
#:Totalen.push(bedrag);
}
function parsePotentiallyGroupedFloat(stringValue) {
stringValue = stringValue.trim();
var result = stringValue.replace(/[^0-9]/g, '');
if (/[,\.]\d{2}$/.test(stringValue)) {
result = result.replace(/(\d{2})$/, '.$1');
}
return parseFloat(result);
}
The function "parsePotentiallyGroupedFloat" is from here: Convert String with Dot or Comma as decimal separator to number in JavaScript

AmCharts4 - Unable to load file - external JSON file produced from SQL database

I'm struggling to open my json arranged data in AmCharts4. In my previous charts I used very simple script (chart.data = ;), which unfortunately does not work this time. So I'm using chart.dataSource.url function proposed by AmCharts documentation. When, I load example file found on web everything works fine, as soon as I switch to my file the chart is not able to load file. I'm not able to find a similar problem on web, therefore I would be very grateful for help.
Here is my example with working url and my not working file.
Thanks in advance:
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
<style>
</style>
</head>
<body>
<div id="chartdiv"></div>
</body>
</html>
<!-- Styles -->
<style>
#chartdiv {
width: 100%;
height: 500px;
}
</style>
<!-- Resources -->
<script src="https://cdn.amcharts.com/lib/4/core.js"></script>
<script src="https://cdn.amcharts.com/lib/4/charts.js"></script>
<script src="https://cdn.amcharts.com/lib/4/themes/animated.js"></script>
<!-- Chart code -->
<script>
am4core.ready(function() {
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
var chart = am4core.create('chartdiv', am4charts.XYChart)
// Modify chart's colors
chart.colors.list = [
am4core.color("#264B29"),
am4core.color("#94B255"),
am4core.color("#456C39"),
am4core.color("#C4D563"),
am4core.color("#698F47"),
am4core.color("#F9F871"),
];
chart.legend = new am4charts.Legend()
chart.legend.position = 'top'
chart.legend.paddingBottom = 20
chart.legend.labels.template.maxWidth = 95
var xAxis = chart.xAxes.push(new am4charts.CategoryAxis())
xAxis.dataFields.category = 'year'
xAxis.renderer.cellStartLocation = 0.1
xAxis.renderer.cellEndLocation = 0.9
xAxis.renderer.grid.template.location = 0;
var yAxis = chart.yAxes.push(new am4charts.ValueAxis());
function createSeries(value, name) {
var series = chart.series.push(new am4charts.ColumnSeries())
series.dataFields.valueY = value
series.dataFields.categoryX = 'year'
series.name = name
series.events.on("hidden", arrangeColumns);
series.events.on("shown", arrangeColumns);
var bullet = series.bullets.push(new am4charts.LabelBullet())
bullet.interactionsEnabled = false
bullet.dy = 30;
bullet.label.text = '{valueY}'
bullet.label.fill = am4core.color('#ffffff')
return series;
}
// Add data
//Working url
//chart.dataSource.url = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-160/sample_data_serial.json";
//My SQL produced JSON file is not working
chart.dataSource.url = "data/my-file.php";
chart.dataSource.adapter.add("parsedData", function(data) {
var newData = [];
data.forEach(function(dataItem) {
var newDataItem = {};
Object.keys(dataItem).forEach(function(key) {
if (typeof dataItem[key] === "object") {
newDataItem["_id"] = dataItem[key]["#id"];
dataItem[key]["Column"].forEach(function(dataItem) {
newDataItem[dataItem["#name"]] = dataItem["#id"];
});
} else {
newDataItem[key] = dataItem[key];
}
});
newData.push(newDataItem);
});
data = newData;
return data;
});
createSeries('cars', 'The First');
createSeries('motorcycles', 'The Second');
createSeries('bicycles', 'The Third');
//createSeries('bilanca_lsk_lst', 'T4');
function arrangeColumns() {
var series = chart.series.getIndex(0);
var w = 1 - xAxis.renderer.cellStartLocation - (1 - xAxis.renderer.cellEndLocation);
if (series.dataItems.length > 1) {
var x0 = xAxis.getX(series.dataItems.getIndex(0), "yearX");
var x1 = xAxis.getX(series.dataItems.getIndex(1), "yearX");
var delta = ((x1 - x0) / chart.series.length) * w;
if (am4core.isNumber(delta)) {
var middle = chart.series.length / 2;
var newIndex = 0;
chart.series.each(function(series) {
if (!series.isHidden && !series.isHiding) {
series.dummyData = newIndex;
newIndex++;
}
else {
series.dummyData = chart.series.indexOf(series);
}
})
var visibleCount = newIndex;
var newMiddle = visibleCount / 2;
chart.series.each(function(series) {
var trueIndex = chart.series.indexOf(series);
var newIndex = series.dummyData;
var dx = (newIndex - trueIndex + middle - newMiddle) * delta
series.animate({ property: "dx", to: dx }, series.interpolationDuration, series.interpolationEasing);
series.bulletsContainer.animate({ property: "dx", to: dx }, series.interpolationDuration, series.interpolationEasing);
})
}
}
}
});
// end am4core.ready()
</script>
I found a typing error in my-file.php
Anyhow, after I solved typing issue the chart.dataSource.url function still did not work, but It worked using next php include script.
chart.data = <?php include './data/my-file.php'; ?>;

How to merge multiple intersecting polygons

I'm trying to merge or group polygons using turfjs.
The following illustration shows what it looks like before and how it should look like after the merge.
I'm working with Openlayers and Typescript and both have Polygons hence the alias TurfPolygon etc.
I'm convert my OpenLayers Polygons to Turfjs Polygons first, so I can use Turf functions.
const mergedIds: number[] = [];
const t0 = performance.now();
for (const object of arrayTurfObjects) {
if (mergedIds.find(x => x === object.properties.mergedId)) {
continue;
}
let mergeResultPolygon: TurfFeature<TurfPolygon> | null = null;
for (let indexNested = 0; indexNested < arrayTurfObjects.length; indexNested++) {
const nestedObject = arrayTurfObjects[indexNested];
if(nestedObject === object){
continue;
}
if(mergedIds.find(x => x === nestedObject.properties.mergedId)){
continue;
}
if(mergeResultPolygon){
if(booleanIntersects(mergeResultPolygon, nestedObject)){
mergeResultPolygon = TurfUnion(mergeResultPolygon, nestedObject) as TurfFeature<TurfPolygon, any>;
mergedIds.push(nestedObject.properties.mergedId);
indexNested = 0;
}
} else {
if(booleanIntersects(object, nestedObject)){
mergeResultPolygon = TurfUnion(object, nestedObject) as TurfFeature<TurfPolygon, any>;
mergedIds.push(nestedObject.properties.mergedId);
indexNested = 0;
}
}
}
if (mergeResultPolygon) {
const polygon = new Polygon(mergeResultPolygon.geometry.coordinates);
const feature = new Feature(polygon);
feature.setStyle(new Style({
stroke: new Stroke({
color: ColorCode.BLACK,
width: 5,
}),
fill: new Fill({
color: 'rgba(255,0,0, 0.6)',
}),
}));
//Here is an function to add the mergeResultPolygon to the map to check if it's correct
}
}
const t1 = performance.now();
console.log((t1 - t0) + ' milliseconds.');
I'm iterating over the same array, which contains the polygons twice.
First I check if the polygon is already merged, so I can skip, and I'm declaring my merge result polygon.
Then comes the nested loop where I skip the polygon, if it's the same as the polygon in my outer loop and if its already merged.
To start my merging process I'm looking for the first polygon that intersects the current outer loop polygon, so I can set a value for my mergeResultPolygon.
After that I just merge more polygons to that variable.
As you can see I have to reset the nested loop, so I can iterate again.
I'm doing this, because I don't have any kind of order, so the previous polygon could intersect the merge Result Polygon.
My problem is that I'm doing this on the client side and the performance is not that great.
Is there a better solution for this problem?
Demonstration of getting merged polygons from a union of all polygons
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.5.0/css/ol.css" type="text/css">
<style>
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.5.0/build/ol.js"></script>
<script src="https://unpkg.com/#turf/turf#6.3.0/turf.min.js"></script>
</head>
<body>
<div id="map" class="map"></div>
<script type="text/javascript">
var count = 200;
var features = new Array(count);
var e = 4500000;
for (var i = 0; i < count; ++i) {
var coordinates = [2 * e * Math.random() - e, 2 * e * Math.random() - e];
features[i] = new ol.Feature(new ol.geom.Polygon.fromExtent(ol.extent.buffer(coordinates.concat(coordinates), 200000)));
}
var source = new ol.source.Vector({
features: features,
});
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
new ol.layer.Vector({
source: source
})
],
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
var result;
format = new ol.format.GeoJSON();
source.forEachFeature(function(feature) {
var turfPolygon = format.writeFeatureObject(feature);
if (!result) {
result = turfPolygon;
} else {
result = turf.union(result, turfPolygon);
}
});
var results = [];
var olResult = format.readFeature(result);
if (olResult.getGeometry().getType() === 'MultiPolygon') {
olResult.getGeometry().getPolygons().forEach(function(polygon) {
results.push(new ol.Feature(polygon));
});
} else {
results.push(olResult);
}
map.addLayer(
new ol.layer.Vector({
source: new ol.source.Vector({
features: results,
}),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'red',
width: 2
})
})
})
);
</script>
</body>
</html>

Live update the charts.js graph on a web page using json data received from a remote server

I am working on displaying weather info received from a weather station to display as live chart on my web page. I am using charts.js library to render weather data that's fetched from the weather station as JSON data.
In The code, function loadChart() fetched the json data about one field from weather station i.e. 'Humidity' and passes it (as int) to dspChrt(hum) to render the graph.
The main task to do in dspChrt(hum) method that renders the graph to put the data received from laodChrt() in an array that is updated each minute to use it as parameter to display live weather data as a line graph.
As the weather station updates data each minute, I am using setInterval(loadChart, 60000) method to fetch updated json data each minute.
I am following this tutorial that uses this method I am trying to implement.
[Chart.js] little update example
But it's not working though.
Here is my code:
<html>
<head>
<meta charset="utf-8">
<title>Weather Update</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<link rel="stylesheet" href="style.css">
<script>
function dspChrt(hum[]) { // to be called by loadChart() to render live chart
var ctx = document.getElementById('myChart').getContext('2d');
var N = 10;
for(i=0; i<N; i++)
hum.push(0);
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['M', 'T', 'W', 'T', 'F', 'S', 'S'],
datasets: [{
label: 'Humidity',
data: hum, // json value received used in method
backgroundColor: "rgba(153,255,51,0.4)"
}, {
label: 'Temprature',
data: [2, 29, 5, 5, 2, 3, 10],
backgroundColor: "rgba(255,153,0,0.4)"
}]
}
});
}
</script>
<script>
var myVar = setInterval(loadChart, 60000);
function loadChrt() { //fetches json data & calls dspChart() to render graph
var wData, hum;
var requestURL = 'https://cors.io/?http://api.holfuy.com/live/?s=759&pw=h1u5l4kka&m=JSON&tu=C&su=m/s'; //URL of the JSON data
var request = new XMLHttpRequest({
mozSystem: true
}); // create http request
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
wData = JSON.parse(request.responseText);
hum = wData.humidity;
console.log("wData: " + wData);
console.log("hum: " + hum);
dspChrt(hum);
}
}
request.open('GET', requestURL);
request.send(); // send the request
//dspChrt(hum);
}
</script>
</head>
<body onload="loadChart();">
<div class="container">
<h2>Weather Update</h2>
<div>
<canvas id="myChart"></canvas>
</div>
</div>
</body>
</html>
You have typo in the for function name loadChart.
The variable declarations and function definitions are needed to be added before being used.
Reduced the length of array to 7 instead of 10.
Here is updated code snippet. I've added the temperature as well. ;)
var humArray = [];
var temArray = [];
var N = 7;
for (i = 0; i < N; i++) {
humArray.push(0);
temArray.push(0);
}
function loadChart() { //fetches json data & calls dspChart() to render graph
var wData, hum, tem;
var requestURL = 'https://cors.io/?http://api.holfuy.com/live/?s=759&pw=h1u5l4kka&m=JSON&tu=C&su=m/s'; //URL of the JSON data
var request = new XMLHttpRequest({
mozSystem: true
}); // create http request
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
wData = JSON.parse(request.responseText);
hum = wData.humidity;
tem = wData.temperature;
humArray.shift();
humArray.push(hum);
temArray.shift();
temArray.push(tem);
dspChrt(humArray, temArray);
}
}
request.open('GET', requestURL);
request.send(); // send the request
//dspChrt(hum);
}
var myVar = setInterval(loadChart, 60000);
function dspChrt(humArray, temArray) { // to be called by loadChart() to render live chart
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['M', 'T', 'W', 'T', 'F', 'S', 'S'],
datasets: [{
label: 'Humidity',
data: humArray, // json value received used in method
backgroundColor: "rgba(153,255,51,0.4)"
}, {
label: 'Temprature',
data: temArray,
backgroundColor: "rgba(255,153,0,0.4)"
}]
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<body onload="loadChart();">
<div class="container">
<h2>Weather Update</h2>
<div>
<canvas id="myChart"></canvas>
</div>
</div>
</body>
Hope it helps.

Piechart not being rendered when values supplied through d3.json

I am trying to read the values as specified in a JSON and based on those values creating a Piechart in d3.json. But on supplying values manually, the piechart is fully functional! The JSON file is present in the same directory as the .html file. Moreover, the var dataset is being populated with the desired values, which is verified by logging the dataset in the console. And I am not getting any error in the Chrome Browser.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sentiments Score</title>
<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<div id="chart"></div>
<script type="text/javascript">
var dataset = [
{ "label": 'Neutral'},
{ "label": 'Positive'},
{ "label": 'Negative' }
];
d3.json("senti_analysis.json", function(data){
for (var i =0; i<dataset.length;i++)
{
if (dataset[i].label == 'Neutral')
{
dataset[i].count = +data.key.senti.neu;
}
else if (dataset[i].label == 'Positive') {
dataset[i].count = +data.key.senti.pos;
}
else
{
dataset[i].count = +data.key.senti.neg;
}
}
});
/*
var dataset = [{ label: 'Neutral', count: 0.45 },
{ label: 'Positive', count: 0.45 },
{ label: 'Negative', count: 0.10 }
];*/
console.log(dataset);
var w = 360;
var h = 360;
var r = Math.min(w, h) / 2;
var color = d3.scaleOrdinal(d3.schemeCategory20b);
var svg = d3.select('#chart')
.append('svg')
.attr('width', w)
.attr('height', h)
.append('g')
.attr('transform', 'translate(' + (w / 2) + ',' + (h / 2) + ')');
var arc = d3.arc()
.innerRadius(0)
.outerRadius(r);
var pie = d3.pie()
.value(function(d) { return d.count; })
.sort(null);
var path = svg.selectAll('path')
.data(pie(dataset))
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d, i) {
return color(d.data.label);
});
</script>
</body>
The json file I am trying to read is as below:
{
"key": {
"senti": {
"neg": 0.10,
"neu": 0.45,
"pos": 0.45,
"compound": 0.784
},
"post": "I am excited to do Sentiment Analysis. I live in Tempe
and I love learning!"
}
}