Search code examples
javascriptjsonamchartspost-processing

Getting the weather forecast data to load in amcharts dataloader


I am very new to programming. So please bear with me. I want to show the real time weather forecast data, specifically the temperature and precipitation vs time period using amcharts. The weather data I am taking from openweathermap.org. Sample: "https://samples.openweathermap.org/data/2.5/forecast?q=M%C3%BCnchen,DE&appid=b6907d289e10d714a6e88b30761fae22" And I want it to use in the following standard amcharts example with dataloader.

var chart = AmCharts.makeChart("chartdiv", {
        "type": "serial",
        "theme": "dark",
        "dataLoader": {
          "url": "data/serial2.json",
          "showErrors": true,
          "complete": function ( chart ) {
            console.log( "Loading complete" );
          },
          "load": function ( options, chart ) {
            console.log( "File loaded: ", options.url );
          },
          "error": function ( options, chart ) {
            console.log( "Error occured loading file: ", options.url );
          }
        },
        "categoryField": "year",
        "startDuration": 1,
        "rotate": false,
        "categoryAxis": {
          "gridPosition": "start"
        },
        "valueAxes": [{
          "position": "top",
          "title": "Million USD",
          "minorGridEnabled": true
        }],
        "graphs": [{
          "type": "column",
          "title": "Income",
          "valueField": "income",
          "fillAlphas":1,
          "balloonText": "<span style='font-size:13px;'>[[title]] in [[category]]:<b>[[value]]</b></span>"
        }, {
          "type": "line",
          "title": "Expenses",
          "valueField": "expenses",
          "lineThickness": 2,
          "bullet": "round",
          "balloonText": "<span style='font-size:13px;'>[[title]] in [[category]]:<b>[[value]]</b></span>"
        }],
        "legend": {
          "useGraphSettings": true
        },
        "creditsPosition": "top-right",
        "responsive": {
          "enabled": true
        }
      });

      function reloadData() {
        chart.dataLoader.loadData();
      }
    

The problem I am facing is that the weather data is a complex json and I am not being able to simply replace the catagory field and value field with the temperature and precipitation.

Can anyone guide me how to go about this? Any lead will be much aprreciated. Thank you!


Solution

  • Given that your source JSON is in a complex format that doesn't directly work with AmCharts, you have to use the dataLoader's postProcess callback to take the response and adapt it to your needs. If you look at the openweathermap sample API response documentation, you'll see that it maps out each field and what they correspond to. The main properties of interest are: main.temp, dt, rain.3h and snow.3h. You'll want to pull this information out for each point and assign it to your array. Your API response has each point under the list array, so you'll want to loop through that.

    Here's what the postProcess method will look like:

      "dataLoader": {
        "url": "YOUR API URL HERE",
        "postProcess": function(jsonData) { 
          var newData = []; //dataProvider for your chart
    
          //loop through your API response's list array for the data you need
          jsonData.list.forEach(function(periodInfo) {
            //set up the data point with the converted timestamp,
            //converted temperature, and placeholder for precipitation
            var dataPoint = {
              "date": periodInfo.dt * 1000, //convert to milliseconds
              "temperature": periodInfo.main.temp - 273.15, //convert kelvin to celsius
              "precipitation": 0
            };
            //check if we have a value for rain precipitation before adding it to our precipitation property
            if (periodInfo.rain !== undefined && periodInfo.rain['3h'] !== undefined) {
              dataPoint.precipitation += periodInfo.rain['3h'];
            }
            //check if we have a value for snow precipitation before adding it in
            if (periodInfo.snow !== undefined && periodInfo.snow['3h'] !== undefined) {
              dataPoint.precipitation += periodInfo.snow['3h'];
            }
            //finally, add it to your new data array
            newData.push(dataPoint);
          });
          //return the new array to be assigned to the chart's dataProvider
          return newData;
        }
      },
    

    Now you have your data mapped, you have to update your makeChart call to look for those properties by creating graph objects with the corresponding valueField properties (temperature and precipitation), setting your categoryField to date and create a categoryAxis with parseDates enabled and a minPeriod set to hh since the data is hourly. You might also want to create a second value axis for your precipitation values.

    Here's a snippet of the updated makeChart properties:

      //create value axes for both temperature and precip values
      "valueAxes": [{
        "id": "temperature",
        "title": "Temperature (C)"
      }, {
        "id": "precipitation",
        "title": "Precipitation (mm)",
        "position": "right"
      }],
      "synchronizeGrid": true, //make sure the grids from both axes are synchronized
      "graphs": [{
        "bullet": "round",
        "valueField": "temperature"
      },{
        "fillAlphas": 0.9,
        "lineAlpha": 0.2,
        "type": "column",
        "valueField": "precipitation",
        "valueAxis": "precipitation" //plot this against the precipitation value axis
      }],
      "categoryField": "date",
      "categoryAxis": {
        "parseDates": true,
        "minPeriod": "hh" //make sure we plot hourly data correctly
      },
    

    Here's a demo using a static JSON file of the above API response to illustrate this. I added some other quality of life settings such as a cursor and setting the precision. I recommend looking at the AmCharts API documentation for more information.