javascriptplotlyplotly.js

Plotly how to change the range and color of gauge programatically


I want to update the range of the colored steps range of a gauge dynamically. The gauge:

var humidityData = [
  {
    domain: { x: [0, 1], y: [0, 1] },
    value: 0,
    title: { text: "Feuchtigkeit" },
    type: "indicator",
    mode: "gauge+number+delta",
    delta: { reference: 69 },
    gauge: {
      axis: { range: [40, 103] },
      steps: [
        { range: [10, 65], color: "red" },
        { range: [65, 68], color: "yellow" },
        { range: [68, 75], color: "lightgreen" },
        { range: [75, 78], color: "yellow" },
        { range: [78, 103], color: "red" },
      ],
    },
  },
];

But the following does not update the ranges:

if (temperature_soll!=20) {
    var temp_soll = ((20*1.8)+32)
    var temperature_update = {
      value: temperature,
      'delta.reference': temp_soll,
      'gauge.axis.range': [((10*1.8)+32), ((30*1.8)+32)],
      'gauge.steps.range': [((10*1.8)+32), ((15*1.8)+32)], color:"red",
      'gauge.steps.range': [((15*1.8)+32), ((18*1.8)+32)], color: "yellow",
      'gauge.steps.range': [((18*1.8)+32), ((22*1.8)+32)], color: "lightgreen",
      'gauge.steps.range': [((22*1.8)+32), ((25*1.8)+32)], color: "yellow",
      'gauge.steps.range': [((25*1.8)+32), ((30*1.8)+32)], color: "red",
    };
  };

The colored ranges are still the same: enter image description here

On a previous post of me, it was the speciality of nested values. Seems to be here something the same, but in a different way. Any hint on that would be nice.

Kind regards Frank

For better understanding, here the full main.js:

var temperatureHistoryDiv = document.getElementById("temperature-history");
var humidityHistoryDiv = document.getElementById("humidity-history");

var temperatureGaugeDiv = document.getElementById("temperature-gauge");
var humidityGaugeDiv = document.getElementById("humidity-gauge");

// History Data
var temperatureTrace = {
  x: [],
  y: [],
  name: "Temperatur",
  mode: "lines+markers",
  type: "line",
};
var humidityTrace = {
  x: [],
  y: [],
  name: "Feuchtigkeit",
  mode: "lines+markers",
  type: "line",
};

var temperatureLayout = {
  autosize: false,
  title: {
    text: "Temperatur",
  },
  font: {
    size: 14,
    color: "#7f7f7f",
  },
  colorway: ["#B22222"],
  width: 450,
  height: 260,
  margin: { t: 30, b: 20, pad: 5 },
};
var humidityLayout = {
  autosize: false,
  title: {
    text: "Feuchtigkeit",
  },
  font: {
    size: 14,
    color: "#7f7f7f",
  },
  colorway: ["#00008B"],
  width: 450,
  height: 260,
  margin: { t: 30, b: 20, pad: 5 },
};

Plotly.newPlot(temperatureHistoryDiv, [temperatureTrace], temperatureLayout);
Plotly.newPlot(humidityHistoryDiv, [humidityTrace], humidityLayout);

// Gauge Data
var temperatureData = [
  {
    domain: { x: [0, 1], y: [0, 1] },
    value: 0,
    title: { text: "Temperatur" },
    type: "indicator",
    mode: "gauge+number+delta",
    delta: { reference: 20 },
    gauge: {
      axis: { range: [10, 30] },
      steps: [
        { range: [10, 15], color: "red" },
        { range: [15, 18], color: "yellow" },
        { range: [18, 22], color: "lightgreen" },
        { range: [22, 25], color: "yellow" },
        { range: [25, 30], color: "red" },
      ],
    },
  },
];

var humidityData = [
  {
    domain: { x: [0, 1], y: [0, 1] },
    value: 0,
    title: { text: "Feuchtigkeit" },
    type: "indicator",
    mode: "gauge+number+delta",
    delta: { reference: 69 },
    gauge: {
      axis: { range: [40, 103] },
      steps: [
        { range: [10, 65], color: "red" },
        { range: [65, 68], color: "yellow" },
        { range: [68, 75], color: "lightgreen" },
        { range: [75, 78], color: "yellow" },
        { range: [78, 103], color: "red" },
      ],
    },
  },
];

var layout = { width: 300, height: 250, margin: { t: 0, b: 0, l: 0, r: 0 }};

Plotly.newPlot(temperatureGaugeDiv, temperatureData, layout);
Plotly.newPlot(humidityGaugeDiv, humidityData, layout);

// Will hold the arrays we receive from our BME280 sensor
// Temperature
let newTempXArray = [];
let newTempYArray = [];
// Humidity
let newHumidityXArray = [];
let newHumidityYArray = [];

// The maximum number of data points displayed on our scatter/line graph
let MAX_GRAPH_POINTS = 60;
let ctr = 0;

// Callback function that will retrieve our latest sensor readings and redraw our Gauge with the latest readings
function updateSensorReadings() {
  fetch(`/sensorReadings`)
    .then((response) => response.json())
    .then((jsonResponse) => {
      let temperature_soll = jsonResponse.temperature_soll.toFixed(1);
      let temperature = jsonResponse.temperature.toFixed(1);
      let humidity = jsonResponse.humidity.toFixed(1);
      let humidity_soll = jsonResponse.humidity_soll.toFixed(1);
      

      updateBoxes(temperature, humidity);

      updateGauge(temperature_soll, temperature, humidity, humidity_soll);

      // Update Temperature Line Chart
      updateCharts(
        temperatureHistoryDiv,
        newTempXArray,
        newTempYArray,
        temperature
      );
      // Update Humidity Line Chart
      updateCharts(
        humidityHistoryDiv,
        newHumidityXArray,
        newHumidityYArray,
        humidity
      );
    });
}

function updateBoxes(temperature, humidity, pressure, altitude) {
  let temperatureDiv = document.getElementById("temperature");
  let humidityDiv = document.getElementById("humidity");

  temperatureDiv.innerHTML = temperature + " C";
  humidityDiv.innerHTML = humidity + " %";
}

function updateGauge(temperature_soll, temperature, humidity, humidity_soll) {
  //Celsius values in json
  if (temperature_soll==20) {
    var temperature_update = {
      value: temperature,
      'delta.reference': temperature_soll,
      'gauge.axis': [
        { range: [10, 30] },
      ],
      'gauge.steps': [
        { range: [10, 15], color: "red" },
        { range: [15, 18], color: "yellow" },
        { range: [18, 22], color: "lightgreen" },
        { range: [22, 25], color: "yellow" },
        { range: [25, 30], color: "red" },
      ],
    };
  };
  //Fahrenheit values in json
  if (temperature_soll!=20) {
    //var temp_soll = ((20*1.8)+32)
    var temperature_update = {
      value: temperature,
      'delta.reference': 68,
      'gauge.axis': [
        { range: [50, 86] },
      ],
      'gauge.steps': [
        { range: [50, 59], color: "red" },
        { range: [((15*1.8)+32), ((18*1.8)+32)], color: "yellow" },
        { range: [((18*1.8)+32), ((22*1.8)+32)], color: "lightgreen" },
        { range: [((22*1.8)+32), ((25*1.8)+32)], color: "yellow" },
        { range: [((25*1.8)+32), ((30*1.8)+32)], color: "red" },
      ],
    };
  };
  
  
  var humidity_update = {
    value: humidity,
    'delta.reference': humidity_soll,
  };
  Plotly.update(temperatureGaugeDiv, temperature_update);
  Plotly.update(humidityGaugeDiv, humidity_update);
}

function updateCharts(lineChartDiv, xArray, yArray, sensorRead) {
  if (xArray.length >= MAX_GRAPH_POINTS) {
    xArray.shift();
  }
  if (yArray.length >= MAX_GRAPH_POINTS) {
    yArray.shift();
  }
  xArray.push(ctr++);
  yArray.push(sensorRead);

  var data_update = {
    x: [xArray],
    y: [yArray],
  };

  Plotly.update(lineChartDiv, data_update);
}


// Continuos loop that runs evry 3 seconds to update our web page with the latest sensor readings
(function loop() {
  setTimeout(() => {
    updateSensorReadings();
    loop();
  }, 3000);
})();


Solution

  • It seems you need to rebuild the entire gauge object, actually in your situation the simplest is to rebuild the trace since you got all the info for updating. Here is the full code (it switches randomly between the two json mocks you've provided in the comments) :

    var temperatureHistoryDiv = document.getElementById("temperature-history");
    var humidityHistoryDiv = document.getElementById("humidity-history");
    
    var temperatureGaugeDiv = document.getElementById("temperature-gauge");
    var humidityGaugeDiv = document.getElementById("humidity-gauge");
    
    // History Data
    var temperatureTrace = {
      x: [],
      y: [],
      name: "Temperatur",
      mode: "lines+markers",
      type: "line",
    };
    var humidityTrace = {
      x: [],
      y: [],
      name: "Feuchtigkeit",
      mode: "lines+markers",
      type: "line",
    };
    
    var temperatureLayout = {
      autosize: false,
      title: {
        text: "Temperatur",
      },
      font: {
        size: 14,
        color: "#7f7f7f",
      },
      colorway: ["#B22222"],
      width: 450,
      height: 260,
      margin: { t: 30, b: 20, pad: 5 },
    };
    var humidityLayout = {
      autosize: false,
      title: {
        text: "Feuchtigkeit",
      },
      font: {
        size: 14,
        color: "#7f7f7f",
      },
      colorway: ["#00008B"],
      width: 450,
      height: 260,
      margin: { t: 30, b: 20, pad: 5 },
    };
    
    Plotly.newPlot(temperatureHistoryDiv, [temperatureTrace], temperatureLayout);
    Plotly.newPlot(humidityHistoryDiv, [humidityTrace], humidityLayout);
    
    // Gauge Data
    var temperatureData = [
      {
        domain: { x: [0, 1], y: [0, 1] },
        value: 0,
        title: { text: "Temperatur" },
        type: "indicator",
        mode: "gauge+number+delta",
        delta: { reference: 20 },
        gauge: {
          axis: { range: [10, 30] },
          steps: [
            { range: [10, 15], color: "red" },
            { range: [15, 18], color: "yellow" },
            { range: [18, 22], color: "lightgreen" },
            { range: [22, 25], color: "yellow" },
            { range: [25, 30], color: "red" },
          ],
        },
      },
    ];
    
    var humidityData = [
      {
        domain: { x: [0, 1], y: [0, 1] },
        value: 0,
        title: { text: "Feuchtigkeit" },
        type: "indicator",
        mode: "gauge+number+delta",
        delta: { reference: 69 },
        gauge: {
          axis: { range: [40, 103] },
          steps: [
            { range: [10, 65], color: "red" },
            { range: [65, 68], color: "yellow" },
            { range: [68, 75], color: "lightgreen" },
            { range: [75, 78], color: "yellow" },
            { range: [78, 103], color: "red" },
          ],
        },
      },
    ];
    
    var layout = { width: 300, height: 250, margin: { t: 0, b: 0, l: 0, r: 0 }};
    
    Plotly.newPlot(temperatureGaugeDiv, temperatureData, layout);
    Plotly.newPlot(humidityGaugeDiv, humidityData, layout);
    
    // Will hold the arrays we receive from our BME280 sensor
    // Temperature
    let newTempXArray = [];
    let newTempYArray = [];
    // Humidity
    let newHumidityXArray = [];
    let newHumidityYArray = [];
    
    // The maximum number of data points displayed on our scatter/line graph
    let MAX_GRAPH_POINTS = 60;
    let ctr = 0;
    
    // Callback function that will retrieve our latest sensor readings and redraw our Gauge with the latest readings
    function updateSensorReadings() {
      // fetch(`/sensorReadings`)
      //   .then((response) => response.json())
      new Promise((resolve, reject) => {
        const json = Math.random() <= 0.5 ? {
          "status":"ok",
          "temperature_soll":68,
          "temperature":76.4240036,
          "humidity":42.64257813,
          "humidity_soll":30
        } : {"status":"ok",
          "temperature_soll":20,
          "temperature":24.71999931,
          "humidity":42.51953125,
          "humidity_soll":30
        };
        
        resolve(json); 
      }).then((jsonResponse) => {
          let temperature_soll = jsonResponse.temperature_soll.toFixed(1);
          let temperature = jsonResponse.temperature.toFixed(1);
          let humidity = jsonResponse.humidity.toFixed(1);
          let humidity_soll = jsonResponse.humidity_soll.toFixed(1);
          
    
          updateBoxes(temperature, humidity);
    
          updateGauge(temperature_soll, temperature, humidity, humidity_soll);
    
          // Update Temperature Line Chart
          updateCharts(
            temperatureHistoryDiv,
            newTempXArray,
            newTempYArray,
            temperature
          );
          // Update Humidity Line Chart
          updateCharts(
            humidityHistoryDiv,
            newHumidityXArray,
            newHumidityYArray,
            humidity
          );
        });
    }
    
    function updateBoxes(temperature, humidity, pressure, altitude) {
      let temperatureDiv = document.getElementById("temperature");
      let humidityDiv = document.getElementById("humidity");
    
      temperatureDiv.innerHTML = temperature + " C";
      humidityDiv.innerHTML = humidity + " %";
    }
    
    function updateGauge(temperature_soll, temperature, humidity, humidity_soll) {
      //Celsius values in json
      if (temperature_soll==20) {
        var temperature_update = {
          value: temperature,
          delta: { reference: temperature_soll },
          gauge: {
            axis: { range: [10, 30] },
            steps: [
            { range: [10, 15], color: "red" },
            { range: [15, 18], color: "yellow" },
            { range: [18, 22], color: "lightgreen" },
            { range: [22, 25], color: "yellow" },
            { range: [25, 30], color: "red" },
            ],
          },
        };
      };
      //Fahrenheit values in json
      if (temperature_soll!=20) {
        var temperature_update = {
          value: temperature,
          delta: { reference: 68 },
          gauge: {
            axis: { range: [50, 86] },
            steps: [
              { range: [50, 59], color: "red" },
              { range: [((15*1.8)+32), ((18*1.8)+32)], color: "yellow" },
              { range: [((18*1.8)+32), ((22*1.8)+32)], color: "lightgreen" },
              { range: [((22*1.8)+32), ((25*1.8)+32)], color: "yellow" },
              { range: [((25*1.8)+32), ((30*1.8)+32)], color: "red" },
            ]
          }   
        };
      };
      
      var humidity_update = {
        value: humidity,
        'delta.reference': humidity_soll,
      };
      Plotly.restyle(temperatureGaugeDiv, temperature_update);
      Plotly.update(humidityGaugeDiv, humidity_update);
    }
    
    function updateCharts(lineChartDiv, xArray, yArray, sensorRead) {
      if (xArray.length >= MAX_GRAPH_POINTS) {
        xArray.shift();
      }
      if (yArray.length >= MAX_GRAPH_POINTS) {
        yArray.shift();
      }
      xArray.push(ctr++);
      yArray.push(sensorRead);
    
      var data_update = {
        x: [xArray],
        y: [yArray],
      };
    
      Plotly.update(lineChartDiv, data_update);
    }
    
    
    // Continuos loop that runs evry 3 seconds to update our web page with the latest sensor readings
    (function loop() {
      setTimeout(() => {
        updateSensorReadings();
        loop();
      }, 3000);
    })();
    <head>
        <script src='https://cdn.plot.ly/plotly-2.32.0.min.js'></script>
    </head>
    
    <body>
        <div id='myDiv'></div>
        <div id='temperature'></div>
        <div id='humidity'></div>    
        <div id='temperature-history'></div>
        <div id='humidity-history'></div>  
        <div id='temperature-gauge'></div>
        <div id='humidity-gauge'></div>
    </body>