          """ Update the latest preview item """
          if not self.runningtask.get() or not self._tab_is_active:
              return
          if self.vars["enabled"].get():
              logger.trace("Updating page")
              self.display_item_set()
              self.load_display()
          self.after(self._waittime, self._update_page)
  
      def display_item_set(self):
 
</s> remove     def select_item(self, event):
        """ Update the session summary info with
            the selected item or launch graph """
        region = self.tree.identify("region", event.x, event.y)
        selection = self.tree.focus()
        values = self.tree.item(selection, "values")
 </s> add     def _select_item(self, event):
        """ Update the session summary info with the selected item or launch graph.

        If the mouse is clicked on the graph icon, then the session summary pop-up graph is
        launched. Otherwise the selected ID is stored.

        Parameters
        ----------
        event: :class:`tkinter.Event`
            The tkinter mouse button release event
        """
        region = self._tree.identify("region", event.x, event.y)
        selection = self._tree.focus()
        values = self._tree.item(selection, "values") </s> remove         self._clear_session()
        session = get_config().session
        if not session.initialized:
 </s> add         if not Session.is_training: </s> remove         session = get_config().session
        smooth_amount_var = get_config().tk_vars["smoothgraph"]
        if session.initialized and session.logging_disabled:
 </s> add         if Session.is_training and Session.logging_disabled: </s> remove         self.vars["is_training"].trace("w", self._remove_current_session)
 </s> add  </s> remove     def get_loss(self, session=None):
 </s> add     def _cache_data(self, session_id, is_training=False):
        """ Cache TensorBoard logs for the given session ID on first access.

        Populates :attr:`_cache` with timestamps and loss data.

        If this is a training session and the data is being queried for the training session ID
        then get the latest available data and append to the cache

        Parameters
        -------
        session_id: int
            The session ID to cache the data for
        is_training: bool, optional
            ``True`` if a current training session is running otherwise ``False``.
            Default: ``False``
        """
        labels = []
        step = []
        loss = []
        timestamps = []
        last_step = -1
        live_data = is_training and session_id == max(self._log_filenames)

        if live_data:
            iterator = self._get_latest_live()
        else:
            iterator = tf.compat.v1.io.tf_record_iterator(self._log_filenames[session_id])

        try:
            for record in iterator:
                event = event_pb2.Event.FromString(record)
                if not event.summary.value or not event.summary.value[0].tag.startswith("batch_"):
                    continue

                if last_step == -1:
                    last_step = event.step if live_data else 0

                if event.step != last_step:
                    loss.append(step)
                    step = []
                    last_step = event.step

                summary = event.summary.value[0]
                tag = summary.tag

                if tag == "batch_total":
                    timestamps.append(event.wall_time)
                    continue

                lbl = tag.replace("batch_", "")
                if lbl not in labels:
                    labels.append(lbl)

                step.append(summary.simple_value)

        except tf_errors.DataLossError as err:
            logger.warning("The logs for Session %s are corrupted and cannot be displayed. "
                           "The totals do not include this session. Original error message: "
                           "'%s'", session_id, str(err))

        if step:
            loss.append(step)

        loss = np.array(loss, dtype="float32")
        timestamps = np.array(timestamps, dtype="float64")

        logger.debug("Caching session id: %s, labels: %s, loss: %s, timestamps: %s",
                     session_id, labels, loss.shape, timestamps.shape)

        if live_data and session_id in self._cache:
            self._add_latest_data_to_cache(session_id, loss, timestamps)
        else:
            self._cache[session_id] = dict(labels=labels,
                                           loss=zlib.compress(loss),
                                           loss_shape=loss.shape,
                                           timestamps=zlib.compress(timestamps),
                                           timestamps_shape=timestamps.shape)

    def _get_latest_live(self):
        """ Obtain the latest event logs for live training data and add to the cache """
        if self._training_iterator is None:
            training_session_id = self.session_ids[-1]
            filename = self._log_filenames[training_session_id]
            self._training_iterator = tf.compat.v1.io.tf_record_iterator(filename)
            logger.debug("Set live training iterator %s for session_id: %s",
                         self._training_iterator, training_session_id)

        i = 0
        while True:
            try:
                yield next(self._training_iterator)
                i += 1
            except StopIteration:
                logger.debug("End of data reached")
                break
            except tf.errors.DataLossError as err:
                # Truncated records are ignored. The iterator holds the offset, so the record will
                # be completed at the next call.
                logger.debug("Truncated record. Original Error: %s", err)
                break
        logger.debug("Collected %s records from live log file", i)

    def _add_latest_data_to_cache(self, session_id, loss, timestamps):
        """ Append the latest received live training data to the cached data.

        Parameters
        ----------
        session_id: int
            The training session ID to update the cache for
        loss: :class:`numpy.ndarray`
            The latest loss values returned from the iterator
        timestamps: :class:`numpy.ndarray`
            The latest time stamps returned from the iterator
        """
        if not np.any(loss) and not np.any(timestamps):
            logger.debug("No new live data to cache.")
            return

        logger.debug("Adding live data to cache: (loss: %s, timestamps: %s)",
                     loss.shape, timestamps.shape)

        cache = self._cache[session_id]

        past_loss = np.frombuffer(zlib.decompress(cache["loss"]),
                                  dtype="float32").reshape(cache["loss_shape"])
        new_loss = np.concatenate((past_loss, loss))
        cache["loss_shape"] = new_loss.shape
        cache["loss"] = zlib.compress(new_loss)
        del past_loss

        past_timestamps = np.frombuffer(zlib.decompress(cache["timestamps"]),
                                        dtype="float64").reshape(cache["timestamps_shape"])
        new_timestamps = np.concatenate((past_timestamps, timestamps))
        cache["timestamps_shape"] = new_timestamps.shape
        cache["timestamps"] = zlib.compress(new_timestamps)
        del past_timestamps

    def _from_cache(self, session_id=None, is_training=False):
        """ Get the session data from the cache.

        If the request data does not exist in the cache, then populate it.

        Parameters
        ----------
        session_id: int, optional
            The Session ID to return the data for. Set to ``None`` to return all session
            data. Default ``None`
        is_training: bool, optional
            ``True`` if a current training session is running otherwise ``False``.
            Default: ``False``

        Returns
        -------
        dict
            The session id(s) as key, with the event data as value
        """
        if session_id is not None and session_id not in self._cache:
            self._cache_data(session_id)
        elif is_training and session_id == self.session_ids[-1]:
            self._cache_data(session_id, is_training=is_training)
        elif session_id is None and not all(idx in self._cache for idx in self._log_filenames):
            for sess in self._log_filenames:
                if sess not in self._cache:
                    self._cache_data(sess)

        if session_id is None:
            return self._cache
        return {session_id: self._cache[session_id]}

    def get_loss(self, session_id=None, is_training=False):
            logger.trace("Updating page: %s", self.__class__.__name__)
          """ Update the latest preview item """
          if not self.runningtask.get() or not self._tab_is_active:
              return
          if self.vars["enabled"].get():
            logger.trace("Updating page: %s", self.__class__.__name__)
              self.display_item_set()
              self.load_display()
          self.after(self._waittime, self._update_page)
  
      def display_item_set(self):
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_page.py