          datapoints = len(data)
  
          if datapoints <= (self.args["avg_samples"] * 2):
              logger.info("Not enough data to compile rolling average")
              return avgs
  
          for idx in range(0, datapoints):
              if idx < presample or idx >= datapoints - postsample:
                  avgs.append(None)
                  continue
 
</s> remove         if datapoints <= (self.args["avg_samples"] * 2):
 </s> add         if datapoints <= (self._args["avg_samples"] * 2): </s> remove         for idx in range(0, datapoints):
            if idx < presample or idx >= datapoints - postsample:
                avgs.append(None)
                continue
            avg = sum(data[idx - presample:idx + postsample]) / self.args["avg_samples"]
            avgs.append(avg)
        logger.debug("Calculated Average")
 </s> add         avgs = np.cumsum(data, dtype="float64")
        avgs[window:] = avgs[window:] - avgs[:-window]
        avgs = avgs[window - 1:] / window
        avgs = np.pad(avgs, (pad, datapoints - (avgs.shape[0] + pad)), constant_values=(np.nan,))
        logger.debug("Calculated Average: shape: %s", avgs.shape) </s> remove         avgs = list()
        presample = ceil(self.args["avg_samples"] / 2)
        postsample = self.args["avg_samples"] - presample
        datapoints = len(data)
 </s> add         window = self._args["avg_samples"]
        pad = ceil(window / 2)
        datapoints = data.shape[0] </s> remove     def calc_avg(self, data):
        """ Calculate rolling average """
 </s> add         Parameters
        ----------
        data: :class:`numpy.ndarray`
            The data to calculate the moving average for

        Returns
        -------
        :class:`numpy.ndarray`
            The moving average for the given data
        """ </s> remove             self.selected_id.set(values[0])
            if region == "tree" and self.check_valid_data(values):
                datapoints = int(values[self.columns.index("iterations")])
                self.data_popup(datapoints)

    def check_valid_data(self, values):
        """ Check there is valid data available for popping up a graph """
        col_indices = [self.columns.index("batch"), self.columns.index("iterations")]
 </s> add             self._selected_id.set(values[0])
            if region == "tree" and self._check_valid_data(values):
                data_points = int(values[self._columns.index("iterations")])
                self._data_popup(data_points)

    def _check_valid_data(self, values):
        """ Check there is valid data available for popping up a graph.

        Parameters
        ----------
        values: list
            The values that exist for a single session that are to be validated
        """
        col_indices = [self._columns.index("batch"), self._columns.index("iterations")]
            return np.array([], dtype="float64")
          datapoints = len(data)
  
          if datapoints <= (self.args["avg_samples"] * 2):
              logger.info("Not enough data to compile rolling average")
            return np.array([], dtype="float64")
  
          for idx in range(0, datapoints):
              if idx < presample or idx >= datapoints - postsample:
                  avgs.append(None)
                  continue
keep keep keep keep replace keep keep keep keep keep
 GUI - Stats optimization (#1067)

* Faster stat loading + caching

* Compress data in cache

* Optimize some calculations

* Vectorize smoothing

* stats.Calculations optimized

* Load latest training data from live iterator

* Add options to training graph 
lib/gui/stats.py