Search code examples
javascriptcsvchartsgoogle-visualizationjquery-csv

Google Chart from multiple csv


I'm pretty new to javascript and I need your help. I'm currently working on a science project about monitoring fumaroles temperatures (Alban Hills, Italy). So I get data every 15 mins and I created a .csv file named like fumarola1-YY-m-d.csv (e.g. fumarola1-2021-06-20.csv) like this:

time,temp
00:00:01,52.1
00:15:01,51.5
00:30:01,51.5
00:45:01,51.5
01:00:01,51.5

I created a Google Chart to display the DAILY changes of temperature, but I still have a problem: is there a way to load multiple csv file in one chart (e.g. fumarola1-2021-06-20.csv and fumarola1-2021-06-19.csv)? I want to diplay the current day, yesterday and maybe 2 days ago too. Drawing a trendline would be great too! Thanks in advance, I'll show you my code below.

<!DOCTYPE html>
<head>
 <meta charset="utf-8">
 <title>Daily temperatures</title>

 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
 <script type="text/javascript" src="https://www.google.com/jsapi"></script>
 <script src="temp/jquery.csv.min.js"></script>

<script type="text/javascript">
  google.load('visualization', '1', { packages: ['corechart', 'controls'] });
</script>

<script type="text/javascript">
function drawVisualization() {
var oggidata = new Date().toJSON().slice(0,10).replace(/-/g,'-');
var nomefile = "temp/fumarola1-" + oggidata + ".csv";
   $.get(nomefile, function(csvString) {
      var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar});
      var data = new google.visualization.arrayToDataTable(arrayData);
      var pi_temp = new google.visualization.ChartWrapper({
         chartType: 'LineChart',
         containerId: 'pi_temp',
         dataTable: data,
         options:{
            lineWidth: 1,
            width: 1000, height: 500,
            title: 'Today: fumarola1-' + oggidata + '.csv',
            hAxis: {title: 'Hour'},
            vAxis: {title: 'Temp (Celsius)'},
            series: { 0: {visibleInLegend: false}},
            trendlines: { 0: {} },
         }
      });
      pi_temp.draw();
   });
}
google.setOnLoadCallback(drawVisualization)
</script>

<div id="pi_temp"></div>
</body>
</html>

And here jquery.csv.min.js

RegExp.escape=function(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")},function(a){"use strict";var b;b="undefined"!=typeof jQuery&&jQuery?jQuery:{},b.csv={defaults:{separator:",",delimiter:'"',headers:!0},hooks:{castToScalar:function(a){var b=/\./;if(isNaN(a))return a;if(b.test(a))return parseFloat(a);var c=parseInt(a);return isNaN(c)?null:c}},parsers:{parse:function(b,c){function d(){if(j=0,k="",c.start&&c.state.rowNum<c.start)return i=[],c.state.rowNum++,void(c.state.colNum=1);if(c.onParseEntry===a)h.push(i);else{var b=c.onParseEntry(i,c.state);b!==!1&&h.push(b)}i=[],c.end&&c.state.rowNum>=c.end&&(l=!0),c.state.rowNum++,c.state.colNum=1}function e(){if(c.onParseValue===a)i.push(k);else{var b=c.onParseValue(k,c.state);b!==!1&&i.push(b)}k="",j=0,c.state.colNum++}var f=c.separator,g=c.delimiter;c.state.rowNum||(c.state.rowNum=1),c.state.colNum||(c.state.colNum=1);var h=[],i=[],j=0,k="",l=!1,m=RegExp.escape(f),n=RegExp.escape(g),o=/(D|S|\r\n|\n|\r|[^DS\r\n]+)/,p=o.source;return p=p.replace(/S/g,m),p=p.replace(/D/g,n),o=new RegExp(p,"gm"),b.replace(o,function(a){if(!l)switch(j){case 0:if(a===f){k+="",e();break}if(a===g){j=1;break}if(/^(\r\n|\n|\r)$/.test(a)){e(),d();break}k+=a,j=3;break;case 1:if(a===g){j=2;break}k+=a,j=1;break;case 2:if(a===g){k+=a,j=1;break}if(a===f){e();break}if(/^(\r\n|\n|\r)$/.test(a)){e(),d();break}throw new Error("CSVDataError: Illegal State [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");case 3:if(a===f){e();break}if(/^(\r\n|\n|\r)$/.test(a)){e(),d();break}if(a===g)throw new Error("CSVDataError: Illegal Quote [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");throw new Error("CSVDataError: Illegal Data [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");default:throw new Error("CSVDataError: Unknown State [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]")}}),0!==i.length&&(e(),d()),h},splitLines:function(b,c){function d(){if(h=0,c.start&&c.state.rowNum<c.start)return i="",void c.state.rowNum++;if(c.onParseEntry===a)g.push(i);else{var b=c.onParseEntry(i,c.state);b!==!1&&g.push(b)}i="",c.end&&c.state.rowNum>=c.end&&(j=!0),c.state.rowNum++}var e=c.separator,f=c.delimiter;c.state.rowNum||(c.state.rowNum=1);var g=[],h=0,i="",j=!1,k=RegExp.escape(e),l=RegExp.escape(f),m=/(D|S|\n|\r|[^DS\r\n]+)/,n=m.source;return n=n.replace(/S/g,k),n=n.replace(/D/g,l),m=new RegExp(n,"gm"),b.replace(m,function(a){if(!j)switch(h){case 0:if(a===e){i+=a,h=0;break}if(a===f){i+=a,h=1;break}if("\n"===a){d();break}if(/^\r$/.test(a))break;i+=a,h=3;break;case 1:if(a===f){i+=a,h=2;break}i+=a,h=1;break;case 2:var b=i.substr(i.length-1);if(a===f&&b===f){i+=a,h=1;break}if(a===e){i+=a,h=0;break}if("\n"===a){d();break}if("\r"===a)break;throw new Error("CSVDataError: Illegal state [Row:"+c.state.rowNum+"]");case 3:if(a===e){i+=a,h=0;break}if("\n"===a){d();break}if("\r"===a)break;if(a===f)throw new Error("CSVDataError: Illegal quote [Row:"+c.state.rowNum+"]");throw new Error("CSVDataError: Illegal state [Row:"+c.state.rowNum+"]");default:throw new Error("CSVDataError: Unknown state [Row:"+c.state.rowNum+"]")}}),""!==i&&d(),g},parseEntry:function(b,c){function d(){if(c.onParseValue===a)g.push(i);else{var b=c.onParseValue(i,c.state);b!==!1&&g.push(b)}i="",h=0,c.state.colNum++}var e=c.separator,f=c.delimiter;c.state.rowNum||(c.state.rowNum=1),c.state.colNum||(c.state.colNum=1);var g=[],h=0,i="";if(!c.match){var j=RegExp.escape(e),k=RegExp.escape(f),l=/(D|S|\n|\r|[^DS\r\n]+)/,m=l.source;m=m.replace(/S/g,j),m=m.replace(/D/g,k),c.match=new RegExp(m,"gm")}return b.replace(c.match,function(a){switch(h){case 0:if(a===e){i+="",d();break}if(a===f){h=1;break}if("\n"===a||"\r"===a)break;i+=a,h=3;break;case 1:if(a===f){h=2;break}i+=a,h=1;break;case 2:if(a===f){i+=a,h=1;break}if(a===e){d();break}if("\n"===a||"\r"===a)break;throw new Error("CSVDataError: Illegal State [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");case 3:if(a===e){d();break}if("\n"===a||"\r"===a)break;if(a===f)throw new Error("CSVDataError: Illegal Quote [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");throw new Error("CSVDataError: Illegal Data [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");default:throw new Error("CSVDataError: Unknown State [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]")}}),d(),g}},helpers:{collectPropertyNames:function(a){var b,c,d=[];for(b in a)for(c in a[b])a[b].hasOwnProperty(c)&&d.indexOf(c)<0&&"function"!=typeof a[b][c]&&d.push(c);return d}},toArray:function(c,d,e){d=d!==a?d:{};var f={};f.callback=e!==a&&"function"==typeof e?e:!1,f.separator="separator"in d?d.separator:b.csv.defaults.separator,f.delimiter="delimiter"in d?d.delimiter:b.csv.defaults.delimiter;var g=d.state!==a?d.state:{};d={delimiter:f.delimiter,separator:f.separator,onParseEntry:d.onParseEntry,onParseValue:d.onParseValue,state:g};var h=b.csv.parsers.parseEntry(c,d);return f.callback?void f.callback("",h):h},toArrays:function(c,d,e){d=d!==a?d:{};var f={};f.callback=e!==a&&"function"==typeof e?e:!1,f.separator="separator"in d?d.separator:b.csv.defaults.separator,f.delimiter="delimiter"in d?d.delimiter:b.csv.defaults.delimiter;var g=[];return d={delimiter:f.delimiter,separator:f.separator,onPreParse:d.onPreParse,onParseEntry:d.onParseEntry,onParseValue:d.onParseValue,onPostParse:d.onPostParse,start:d.start,end:d.end,state:{rowNum:1,colNum:1}},d.onPreParse!==a&&d.onPreParse(c,d.state),g=b.csv.parsers.parse(c,d),d.onPostParse!==a&&d.onPostParse(g,d.state),f.callback?void f.callback("",g):g},toObjects:function(c,d,e){d=d!==a?d:{};var f={};f.callback=e!==a&&"function"==typeof e?e:!1,f.separator="separator"in d?d.separator:b.csv.defaults.separator,f.delimiter="delimiter"in d?d.delimiter:b.csv.defaults.delimiter,f.headers="headers"in d?d.headers:b.csv.defaults.headers,d.start="start"in d?d.start:1,f.headers&&d.start++,d.end&&f.headers&&d.end++;var g=[],h=[];d={delimiter:f.delimiter,separator:f.separator,onPreParse:d.onPreParse,onParseEntry:d.onParseEntry,onParseValue:d.onParseValue,onPostParse:d.onPostParse,start:d.start,end:d.end,state:{rowNum:1,colNum:1},match:!1,transform:d.transform};var i={delimiter:f.delimiter,separator:f.separator,start:1,end:1,state:{rowNum:1,colNum:1}};d.onPreParse!==a&&d.onPreParse(c,d.state);var j=b.csv.parsers.splitLines(c,i),k=b.csv.toArray(j[0],d);g=b.csv.parsers.splitLines(c,d),d.state.colNum=1,d.state.rowNum=k?2:1;for(var l=0,m=g.length;m>l;l++){for(var n=b.csv.toArray(g[l],d),o={},p=0;p<k.length;p++)o[k[p]]=n[p];h.push(d.transform!==a?d.transform.call(a,o):o),d.state.rowNum++}return d.onPostParse!==a&&d.onPostParse(h,d.state),f.callback?void f.callback("",h):h},fromArrays:function(c,d,e){d=d!==a?d:{};var f={};f.callback=e!==a&&"function"==typeof e?e:!1,f.separator="separator"in d?d.separator:b.csv.defaults.separator,f.delimiter="delimiter"in d?d.delimiter:b.csv.defaults.delimiter;var g,h,i,j,k="";for(i=0;i<c.length;i++){for(g=c[i],h=[],j=0;j<g.length;j++){var l=g[j]===a||null===g[j]?"":g[j].toString();l.indexOf(f.delimiter)>-1&&(l=l.replace(f.delimiter,f.delimiter+f.delimiter));var m="\n|\r|S|D";m=m.replace("S",f.separator),m=m.replace("D",f.delimiter),l.search(m)>-1&&(l=f.delimiter+l+f.delimiter),h.push(l)}k+=h.join(f.separator)+"\r\n"}return f.callback?void f.callback("",k):k},fromObjects:function(c,d,e){d=d!==a?d:{};var f={};if(f.callback=e!==a&&"function"==typeof e?e:!1,f.separator="separator"in d?d.separator:b.csv.defaults.separator,f.delimiter="delimiter"in d?d.delimiter:b.csv.defaults.delimiter,f.headers="headers"in d?d.headers:b.csv.defaults.headers,f.sortOrder="sortOrder"in d?d.sortOrder:"declare",f.manualOrder="manualOrder"in d?d.manualOrder:[],f.transform=d.transform,"string"==typeof f.manualOrder&&(f.manualOrder=b.csv.toArray(f.manualOrder,f)),f.transform!==a){var g=c;c=[];var h;for(h=0;h<g.length;h++)c.push(f.transform.call(a,g[h]))}var i=b.csv.helpers.collectPropertyNames(c);if("alpha"===f.sortOrder&&i.sort(),f.manualOrder.length>0){var j,k=[].concat(f.manualOrder);for(j=0;j<i.length;j++)k.indexOf(i[j])<0&&k.push(i[j]);i=k}var l,j,m,n,o=[];for(f.headers&&o.push(i),l=0;l<c.length;l++){for(m=[],j=0;j<i.length;j++)n=i[j],m.push(n in c[l]&&"function"!=typeof c[l][n]?c[l][n]:"");o.push(m)}return b.csv.fromArrays(o,d,f.callback)}},b.csvEntry2Array=b.csv.toArray,b.csv2Array=b.csv.toArrays,b.csv2Dictionary=b.csv.toObjects,"undefined"!=typeof module&&module.exports&&(module.exports=b.csv)}.call(this);

Thank you and have a nice day!


Solution

  • for starters, you're using an old version of google charts.
    jsapi should no longer be used.
    instead load the following...

    <script src="https://www.gstatic.com/charts/loader.js"></script>
    

    this will only change the load statement.

    google.charts.load('current', {
      packages: ['controls']
    }).then(function () {
    
       // place chart code here
    
    });
    

    next, we need to gather all the data before drawing the chart.
    we can make all the requests, then combine all the data into one array.
    here, we use a while loop to request the data from the last three days, including today.

      // gather data for last three days (including today)
      var chartData = null;
      var requests = [];
      var dateEnd = new Date();
      var dateRequest = new Date(dateEnd.getFullYear(), dateEnd.getMonth(), dateEnd.getDate() - 2);
      while (dateRequest.getTime() <= dateEnd.getTime()) {
        var oggidata = dateRequest.toJSON().slice(0,10).replace(/-/g,'-');
        requests.push(makeRequest(oggidata));
        dateRequest = new Date(dateRequest.getFullYear(), dateRequest.getMonth(), dateRequest.getDate() + 1);
      }
    

    then we can use the when statement, to know when all the requests have been made and completed,
    then draw our chart.

      // wait for all requests to finish
      $.when.apply($, requests).done(function () {
        // create, sort data table by date / time
        var data = new google.visualization.arrayToDataTable(chartData);
        data.sort([{column: 0}]);
    
        // draw chart
        var pi_temp = new google.visualization.ChartWrapper({
           chartType: 'LineChart',
           containerId: 'pi_temp',
           dataTable: data,
           options:{
              lineWidth: 1,
              width: 1000, height: 500,
              title: 'Today: fumarola1-' + oggidata + '.csv',
              hAxis: {title: 'Hour', format: 'MM/dd hh:mm:ss'},
              vAxis: {title: 'Temp (Celsius)'},
              series: { 0: {visibleInLegend: false}},
              trendlines: { 0: {} },
           }
        });
        pi_temp.draw();
      });
    

    finally, this is the function we use to make the csv request and combine the data.
    note: in order to draw a trendline, we must convert the time string to an actual date. trendlines are not supported by a discrete axis (where the axis values are strings)

      // make csv request, return promise
      function makeRequest(oggidata) {
        return $.get("temp/fumarola1-" + oggidata + ".csv", function(csvString) {
          var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar});
          arrayData = arrayData.map(function (row, index) {
            if (index === 0) {
              // return column headings
              return row;
            } else {
              // convert time string to date
              return [new Date(oggidata + 'T' + row[0]), row[1]];
            }
          });
    
          // combine data
          if (chartData === null) {
            chartData = arrayData;
          } else {
            // remove column headings, add remaining rows
            arrayData.splice(0, 1);
            chartData = chartData.concat(arrayData);
          }
        });
      }
    

    see following full snippet...

    google.charts.load('current', {
      packages: ['controls']
    }).then(function () {
      // gather data for last three days (including today)
      var chartData = null;
      var requests = [];
      var dateEnd = new Date();
      var dateRequest = new Date(dateEnd.getFullYear(), dateEnd.getMonth(), dateEnd.getDate() - 2);
      while (dateRequest.getTime() <= dateEnd.getTime()) {
        var oggidata = dateRequest.toJSON().slice(0,10).replace(/-/g,'-');
        requests.push(makeRequest(oggidata));
        dateRequest = new Date(dateRequest.getFullYear(), dateRequest.getMonth(), dateRequest.getDate() + 1);
      }
    
      // wait for all requests to finish
      $.when.apply($, requests).done(function () {
        // create, sort data table by date / time
        var data = new google.visualization.arrayToDataTable(chartData);
        data.sort([{column: 0}]);
    
        // draw chart
        var pi_temp = new google.visualization.ChartWrapper({
           chartType: 'LineChart',
           containerId: 'pi_temp',
           dataTable: data,
           options:{
              lineWidth: 1,
              width: 1000, height: 500,
              title: 'Today: fumarola1-' + oggidata + '.csv',
              hAxis: {title: 'Hour', format: 'MM/dd hh:mm:ss'},
              vAxis: {title: 'Temp (Celsius)'},
              series: { 0: {visibleInLegend: false}},
              trendlines: { 0: {} },
           }
        });
        pi_temp.draw();
      });
    
      // make csv request, return promise
      function makeRequest(oggidata) {
        return $.get("temp/fumarola1-" + oggidata + ".csv", function(csvString) {
          var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar});
          arrayData = arrayData.map(function (row, index) {
            if (index === 0) {
              // return column headings
              return row;
            } else {
              // convert time string to date
              return [new Date(oggidata + 'T' + row[0]), row[1]];
            }
          });
    
          // combine data
          if (chartData === null) {
            chartData = arrayData;
          } else {
            arrayData.splice(0, 1);
            chartData = chartData.concat(arrayData);
          }
        });
      }
    });