class_docstr: Abstract interface for data aggregation functionality for plotly figures.
class_docstr_tok: ["Abstract","interface","for","data","aggregation","functionality","for","plotly","figures","."]
docstr: Construct the to-be-updated front-end data, based on the layout change.
  
  Parameters
  ----------
  relayout_data: dict
      A dict containing the ``relayoutData`` (i.e., the changed layout data) of
      the corresponding front-end graph.
  
  Returns
  -------
  List[dict]:
      A list of dicts, where each dict-item is a representation of a trace its
      *data* properties which are affected by the front-end layout change. |br|
      In other words, only traces which need to be updated will be sent to the
      front-end. Additionally, each trace-dict withholds the *index* of its
      corresponding position in the ``figure[data]`` array with the ``index``-key
      in each dict.
docstr_tok: ["Construct","the","to-be-updated","front-end","data",",","based","on","the","layout","change",".","Parameters","--","--","--","--","--","relayout_data",":","dict","A","dict","containing","the","``","relayoutData","``","(","i.e.",",","the","changed","layout","data",")","of","the","corresponding","front-end","graph",".","Returns","--","--","--","-","List","[","dict","]",":","A","list","of","dicts",",","where","each","dict-item","is","a","representation","of","a","trace","its","*","data","*","properties","which","are","affected","by","the","front-end","layout","change",".","|br|","In","other","words",",","only","traces","which","need","to","be","updated","will","be","sent","to","the","front-end",".","Additionally",",","each","trace-dict","withholds","the","*","index","*","of","its","corresponding","position","in","the","``","figure","[","data","]","``","array","with","the","``","index","``","-key","in","each","dict","."]
code: def _construct_update_data(
      self,
      relayout_data: dict,
  ) -> Union[List[dict], None]:
      """Construct the to-be-updated front-end data, based on the layout change.
  
      Parameters
      ----------
      relayout_data: dict
          A dict containing the ``relayoutData`` (i.e., the changed layout data) of
          the corresponding front-end graph.
  
      Returns
      -------
      List[dict]:
          A list of dicts, where each dict-item is a representation of a trace its
          *data* properties which are affected by the front-end layout change. |br|
          In other words, only traces which need to be updated will be sent to the
          front-end. Additionally, each trace-dict withholds the *index* of its
          corresponding position in the ``figure[data]`` array with the ``index``-key
          in each dict.
  
      """
      current_graph = self._get_current_graph()
      updated_trace_indices, cl_k = [], []
      if relayout_data:
          # flatten the possibly nested dict using '.' as separator
          relayout_data = nested_to_record(relayout_data, sep=".")
          self._print("-" * 100 + "\n", "changed layout", relayout_data)
  
          cl_k = list(relayout_data.keys())
  
          # ------------------ HF DATA aggregation ---------------------
          # 1. Base case - there is an x-range specified in the front-end
          start_matches = self._re_matches(
              re.compile(r"xaxis\d*.range\[0]"), cl_k
          )
          stop_matches = self._re_matches(
              re.compile(r"xaxis\d*.range\[1]"), cl_k
          )
          if start_matches and stop_matches:  # when both are not empty
              for t_start_key, t_stop_key in zip(
                  start_matches, stop_matches
              ):
                  # Check if the xaxis<NUMB> part of xaxis<NUMB>.[0-1] matches
                  xaxis = t_start_key.split(".")[0]
                  assert xaxis == t_stop_key.split(".")[0]
                  # -> we want to copy the layout on the back-end
                  updated_trace_indices = (
                      self._check_update_figure_dict(
                          current_graph,
                          start=relayout_data[t_start_key],
                          stop=relayout_data[t_stop_key],
                          layout_xaxis_filter=xaxis,
                          updated_trace_indices=updated_trace_indices,
                      )
                  )
  
          # 2. The user clicked on either autorange | reset axes
          autorange_matches = self._re_matches(
              re.compile(r"xaxis\d*.autorange"), cl_k
          )
          spike_matches = self._re_matches(
              re.compile(r"xaxis\d*.showspikes"), cl_k
          )
          # 2.1 Reset-axes -> autorange & reset to the global data view
          if (
              autorange_matches and spike_matches
          ):  # when both are not empty
              for autorange_key in autorange_matches:
                  if relayout_data[autorange_key]:
                      xaxis = autorange_key.split(".")[0]
                      updated_trace_indices = self._check_update_figure_dict(
                          current_graph,
                          layout_xaxis_filter=xaxis,
                          updated_trace_indices=updated_trace_indices,
                      )
          # 2.1. Autorange -> do nothing, the autorange will be applied on the
          #      current front-end view
          elif (
              autorange_matches and not spike_matches
          ):  # when only autorange is not empty
              # PreventUpdate returns a 204 status code response on the
              # relayout post request
              return dash.no_update
  
      # If we do not have any traces to be updated, we will return an empty
      # request response
      if (
          not updated_trace_indices
      ):  # when updated_trace_indices is empty
          # PreventUpdate returns a 204 status-code response on the relayout post
          # request
          return dash.no_update
  
      # -------------------- construct callback data --------------------------
      # 1. Create the layout data for the front-end
      layout_traces_list: List[dict] = [relayout_data]
  
      # 2. Create the additional trace data for the frond-end
      relevant_keys = list(_hf_data_container._fields) + [
          "name",
          "marker",
      ]
      # Note that only updated trace-data will be sent to the client
      for idx in updated_trace_indices:
          trace = current_graph["data"][idx]
          # TODO: check if we can reduce even more
          trace_reduced = {
              k: trace[k] for k in relevant_keys if k in trace
          }
  
          # Store the index into the corresponding to-be-sent trace-data so
          # the client front-end can know which trace needs to be updated
          trace_reduced.update({"index": idx})
  
          layout_traces_list.append(trace_reduced)
      return layout_traces_list
  
imports: from __future__ import annotations
  import itertools
  import re
  from abc import ABC
  from collections import namedtuple
  from copy import copy
  from typing import Dict, Iterable, List, Optional, Tuple, Union
  from uuid import uuid4
  import dash
  import numpy
  import pandas
  import plotly.graph_objects
  from pandas.io.json._normalize import nested_to_record
  from plotly.basedatatypes import BaseFigure, BaseTraceType
  from ..aggregation import AbstractAggregator, MedDiffGapHandler, MinMaxLTTB
  from ..aggregation.aggregation_interface import DataPointSelector
  from ..aggregation.gap_handler_interface import AbstractGapHandler
  from ..aggregation.plotly_aggregator_parser import PlotlyAggregatorParser
  from .utils import round_number_str, round_td_str
label_desc: Use image node_id 21 for calling the AbstractFigureAggregator obj's underlying member method code with example usage: obj._construct_update_data(relayout_data) and returns: layout_traces_list, dash, dash