          self.ax1.set_xlim(0, 1)
  
      def axes_limits_set(self, data):
          """ Set the axes limits """
          xmax = self.calcs.iterations - 1 if self.calcs.iterations > 1 else 1
          if data:
              ymin, ymax = self.axes_data_get_min_max(data)
              self.ax1.set_ylim(ymin, ymax)
              self.ax1.set_xlim(0, xmax)
              logger.trace("axes ranges: (y: (%s, %s), x:(0, %s)", ymin, ymax, xmax)
 
</s> remove             self.ax1.set_xlim(0, xmax)
 </s> add             self.ax1.set_xlim(xmin, xmax) </s> remove         for item in data:
            dataset = list(filter(lambda x: x is not None, item))
            if not dataset:
                continue
            ymin.append(min(dataset) * 1000)
            ymax.append(max(dataset) * 1000)
 </s> add         for item in data:  # TODO Handle as array not loop
            ymin.append(np.nanmin(item) * 1000)
            ymax.append(np.nanmax(item) * 1000) </s> remove     def remove_raw(self):
        """ Remove raw values from stats if not requested """
        if "raw" in self.selections:
 </s> add     @classmethod
    def _flatten_outliers(cls, data):
        """ Remove the outliers from a provided list.

        Removes data more than 1 Standard Deviation from the mean.

        Parameters
        ----------
        data: :class:`numpy.ndarray`
            The data to remove the outliers from

        Returns
        -------
        :class:`numpy.ndarray`
            The data with outliers removed
        """
        logger.debug("Flattening outliers: %s", data.shape)
        mean = np.mean(data)
        limit = np.std(data)
        logger.debug("mean: %s, limit: %s", mean, limit)
        retdata = np.where(abs(data - mean) < limit, data, mean)
        logger.debug("Flattened outliers")
        return retdata

    def _remove_raw(self):
        """ Remove raw values from :attr:`stats` if they are not requested. """
        if "raw" in self._selections: </s> remove     def calc_smoothed(self, data):
        """ Smooth the data """
        last = data[0]  # First value in the plot (first time step)
        weight = self.args["smooth_amount"]
        smoothed = list()
        for point in data:
            smoothed_val = last * weight + (1 - weight) * point  # Calculate smoothed value
            smoothed.append(smoothed_val)                        # Save it
            last = smoothed_val                                  # Anchor the last smoothed value

        return smoothed

    @staticmethod
    def calc_trend(data):
        """ Compile trend data """
 </s> add     def _calc_smoothed(self, data):
        """ Smooth the data.

        Parameters
        ----------
        data: :class:`numpy.ndarray`
            The data to smoothen

        Returns
        -------
        :class:`numpy.ndarray`
            The smoothed data
        """
        return ExponentialMovingAverage(data, self._args["smooth_amount"])()

    @classmethod
    def _calc_trend(cls, data):
        """ Calculate polynomial trend of the given data.

        Parameters
        ----------
        data: :class:`numpy.ndarray`
            The data to calculate the trend for

        Returns
        -------
        :class:`numpy.ndarray`
            The trend for the given data
        """ </s> remove         xrng = [x for x in range(self.calcs.iterations)]
 </s> add         if self.calcs.start_iteration > 0:
            end_iteration = self.calcs.start_iteration + self.calcs.iterations
            xrng = list(range(self.calcs.start_iteration, end_iteration))
        else:
            xrng = list(range(self.calcs.iterations))

        xmin = self.calcs.start_iteration
        if self.calcs.start_iteration > 0:
            xmax = self.calcs.iterations + self.calcs.start_iteration
        else:
            xmax = self.calcs.iterations
        xmax = max(1, xmax - 1)

          self.ax1.set_xlim(0, 1)
  
      def axes_limits_set(self, data):
          """ Set the axes limits """
        xmin = self.calcs.start_iteration
        if self.calcs.start_iteration > 0:
            xmax = self.calcs.iterations + self.calcs.start_iteration
        else:
            xmax = self.calcs.iterations
        xmax = max(1, xmax - 1)

          if data:
              ymin, ymax = self.axes_data_get_min_max(data)
              self.ax1.set_ylim(ymin, ymax)
              self.ax1.set_xlim(0, xmax)
              logger.trace("axes ranges: (y: (%s, %s), x:(0, %s)", ymin, ymax, xmax)
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/display_graph.py