Black Lives Matter. Please consider donating to Black Girls Code today.

Question regarding accessing x-axis/time data range on zoom

I am using plot.ly to visualize industrial data from a chemical plant (lab results stored on SQL server, process temperatures/pressures/flow rates stored on Oracle MySQL server).

This all works, but I’d like to be able to display an average across the zoomed time series data after a zoom.

It looks like I can create a callback function, but I wasn’t clear on how to access the x-axis range (min and max) and data to loop through it, once I understand this I can easily calculate average, mean, standard deviation, etc, and display that in a DIV or chart legend.

I welcome any assistance on this relatively basic question.

I was able to resolve my issue, and added a DIV containing both average and standard deviation which populates after chart is drawn and also after zooming (average shown across zoomed interval only). math.js was used to compute standard deviation. There may be a better way to do this (not sure if plotly can return indexes into x-axis data rather than x-axis timedatestamps): I used this example as basis for pulling earliest/last datetimestamp from zoomed interval https://plotly.com/javascript/zoom-events/

I am including code snippet below in case it is of any use to others.

	// Invoke plot.ly to render the plot.  ShowLink modifier: Allows full plot editing.  Responsive modifier: Re-draws plot if window resized.  Editable modifier: Allows title, axis label, etc to be edited by user
        Plotly.newPlot('plotly-chart', plotly_vars['data'], plotly_vars['layout'], {showLink: true,responsive: true,editable: true} );

var myDiv = document.getElementById('plotly-chart'); // Define division on which plot.ly Event Handler acts upon

// Define Event processor to execute after user zooms in on a selected interval/area of plot
myDiv.on('plotly_relayout',
    function(eventdata){  
  console.log ('Zoom Event/running eventdata function')

  // console.table(data[0]['y']);  uncomment to dump y-axis
  var i; // Loop indice
  var first_x = eventdata['xaxis.range[0]']; // Retrieve earliest/leftmost time/date stamp from selected interval in String format, from selected interval
  var zoomed_y_array = [ ]; // Array consisting of all y values within zoomed time interval, used to compute standard deviation
  if (first_x==undefined) { first_x = new Date ('01/01/2000'); } // If this was a zoom out, set earliest/leftmost time/date stamp to Jan 1, 2000 @ midnight to include all data
  console.log('X-Axis Min:' + first_x); // Dump leftmost timedatestamp to web developer console window
  var last_x = eventdata['xaxis.range[1]']; // Retrieve latest/rightmost time/date stamp from selected interval in String format, from selected interval
  if (last_x==undefined) { last_x = new Date ('01/01/2099'); } // If this was a zoom out, set latest/rightmost time/date stamp to Jan 1, 2099 @ midnight to include all data
  console.log('X-Axis Max:' + last_x); // Dump rightmost/latest timedatestamp to web developer console window
  // console.table( plotly_vars['data']['x'] ); Uncomment this line to write x-axis data array to console window
  // console.log('First x-element: ' + plotly_vars['data'][0]['x'][0] ); Uncomment this line to write first x-axis element to console window
  var num_points =  plotly_vars['data'][0]['x'].length; // Compute total number of points on x-axis (entire dataset before zoom) based upon data array length
  console.log ('num_points: ' + num_points);
  var num_points_in_zoom = 0; // Initialize indice containing the number of points within the zoomed region (running counter)
  analyte_result_sum = 0; // Zero the sum of analyte results later used to compute average
for (i = 0; i < num_points; i++) { // Loop through entire dataset to sum across only those points within zoomed region (sum used to compute average)
  var single_date = plotly_vars['data'][0]['x'][i]; // Return a single time/date stamp in String format
   
   // Below statement compares timedatestamp of each point to endpoints of interval.  To allow a logical comparison, the string timedatestamps must be coerced
   // into numeric format with Date() function
   
  if ( new Date ( single_date ) > new Date (first_x) && new Date ( single_date ) < new Date (last_x) )
     { analyte_result_sum += plotly_vars['data'][0]['y'][i]; // Add y-axis analyte results to sum if their timedatestamp lies withn zoomed interval
       num_points_in_zoom += 1; // Increment count of total number of points later used to compute average
	   zoomed_y_array.push( plotly_vars['data'][0]['y'][i] ); // Build array comprising all y-values, for use in calculating standard deviation
     }
}
  console.log('Sum of analyte results:' + analyte_result_sum); // Write sum to console window for debugging purposes
  console.log('N, Number of Results in zoomed dataset interval:' + num_points_in_zoom); // Write number of points to console window for debugging purposes
  var zoom_average = analyte_result_sum / num_points_in_zoom; // Compute average across zoomed-interval
  console.log('Average Value:' + zoom_average); // Write average value to console window
  console.log ('N2, Number of Results in un-zoomed dataset: ' + num_points); // Write total number of points to console window
  var st_dev = math.std( zoomed_y_array ); // Compute standard deviation across all y-values/analyte values within zoomed time interval
  console.log ('σ stDev: ' + st_dev );
  document.getElementById("content").innerHTML = 'Average x̄ = ' + number_format(zoom_average,3) + ' StDev σ = ' + number_format(st_dev,4); // Write average rounded to 3 decimal places to web page
  
    });

  console.log ('Running code to compute average value immediately after rendering plot initially')

  // console.table(data[0]['y']);  uncomment to dump y-axis
  var i;
  var first_x = new Date ('01/01/2000'); 
  console.log('X-Axis Min:' + first_x);
  var last_x = new Date ('01/01/2099'); 
  console.log('X-Axis Max:' + last_x);
  console.table( plotly_vars['data']['x'] );
  console.log('First x-element: ' + plotly_vars['data'][0]['x'][0] );
  var num_points =  plotly_vars['data'][0]['x'].length;
  console.log ('num_points: ' + num_points);
  var num_points_in_zoom = 0;
  analyte_result_sum = 0;
for (i = 0; i < num_points; i++) {
  var single_date = plotly_vars['data'][0]['x'][i];
   
  if ( new Date ( single_date ) > new Date (first_x) && new Date ( single_date ) < new Date (last_x) )
     { analyte_result_sum += plotly_vars['data'][0]['y'][i];
       num_points_in_zoom += 1;
     }
}
  console.log('Sum of analyte results:' + analyte_result_sum);
  console.log('N, Number of Results in zoomed dataset interval:' + num_points_in_zoom);
  var zoom_average = analyte_result_sum / num_points_in_zoom;
  console.log('Average Value:' + zoom_average);
  console.log ('N2, Number of Results in un-zoomed dataset: ' + num_points);
  var st_dev = math.std( plotly_vars['data'][0]['y'] );
  console.log ('σ stDev: ' + st_dev );
  document.getElementById("content").innerHTML = 'Average x̄ = ' + number_format(zoom_average,3) + ' StDev σ = ' + number_format(st_dev,4) ;

}



/**
 * Custom JavaScript function that rounds a number w/
 * decimal places.
 *
 * @param val - The value that you want to format with decimal places.
 * @param decimals - The number of decimal places that should be used.
 * @returns {float}
 */
function number_format(val, decimals){
    //Parse the value as a float value
    val = parseFloat(val);
    //Format the value w/ the specified number
    //of decimal places and return it.
    return val.toFixed(decimals);
}