class_docstr: Abstract interface for data aggregation functionality for plotly figures.
class_docstr_tok: ["Abstract","interface","for","data","aggregation","functionality","for","plotly","figures","."]
docstr: Add a trace to the figure.
  
  Parameters
  ----------
  trace : BaseTraceType or dict
      Either:
  
        - An instances of a trace class from the ``plotly.graph_objects`` (go)
          package (e.g., ``go.Scatter``, ``go.Bar``)
        - or a dict where:
  
          - The type property specifies the trace type (e.g. scatter, bar,
            area, etc.). If the dict has no 'type' property then scatter is
            assumed.
          - All remaining properties are passed to the constructor
            of the specified trace type.
  max_n_samples : int, optional
      The maximum number of samples that will be shown by the trace.
  
      !!! note
          If this variable is not set; ``_global_n_shown_samples`` will be used.
  downsampler: AbstractAggregator, optional
      The abstract series downsampler method.
  
      !!! note
          If this variable is not set, ``_global_downsampler`` will be used.
  gap_handler: AbstractGapHandler, optional
      The abstract series gap handler method.
  
      !!! note
          If this variable is not set, ``_global_gap_handler`` will be used.
  limit_to_view: boolean, optional
      If set to True, the trace's datapoints will be cut to the corresponding
      front-end view, even if the total number of samples is lower than
      ``max_n_samples``, By default False.
  
      Remark that setting this parameter to True ensures that low frequency traces
      are added to the ``hf_data`` property.
  hf_x: Iterable, optional
      The original high frequency series positions, can be either a time-series or
      an increasing, numerical index. If set, this has priority over the trace its
      data.
  hf_y: Iterable, optional
      The original high frequency values. If set, this has priority over the
      trace its data.
  hf_text: Iterable, optional
      The original high frequency text. If set, this has priority over the trace
      its ``text`` argument.
  hf_hovertext: Iterable, optional
      The original high frequency hovertext. If set, this has priority over the
      trace its ```hovertext`` argument.
  hf_marker_size: Iterable, optional
      The original high frequency marker size. If set, this has priority over the
      trace its ``marker.size`` argument.
  hf_marker_color: Iterable, optional
      The original high frequency marker color. If set, this has priority over the
      trace its ``marker.color`` argument.
  check_nans: boolean, optional
      If set to True, the trace's data will be checked for NaNs - which will be
      removed. By default True.
      As this is a costly operation, it is recommended to set this parameter to
      False if you are sure that your data does not contain NaNs (or when the
      downsampler can handle NaNs, e.g., EveryNthPoint). This should considerably
      speed up the graph construction time.
  **trace_kwargs: dict
      Additional trace related keyword arguments.
      e.g.: row=.., col=..., secondary_y=...
  
      !!! info "See Also"
          [`Figure.add_trace`](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Figure.html#plotly.graph_objects.Figure.add_trace>) docs.
  
  Returns
  -------
  BaseFigure
      The Figure on which ``add_trace`` was called on; i.e. self.
  
  !!! note
  
      Constructing traces with **very large data amounts** really takes some time.
      To speed this up; use this [`add_trace`][figure_resampler.figure_resampler_interface.AbstractFigureAggregator.add_trace] method and
  
      1. Create a trace with no data (empty lists)
      2. pass the high frequency data to this method using the ``hf_x`` and ``hf_y``
         parameters.
  
      See the example below:
          ```python
          >>> from plotly.subplots import make_subplots
          >>> s = pd.Series()  # a high-frequency series, with more than 1e7 samples
          >>> fig = FigureResampler(go.Figure())
          >>> fig.add_trace(go.Scattergl(x=[], y=[], ...), hf_x=s.index, hf_y=s)
          ```
  
      !!! todo
          * explain why adding x and y to a trace is so slow
          * check and simplify the example above
  
  !!! tip
  
      * If you **do not want to downsample** your data, set ``max_n_samples`` to the
        the number of datapoints of your trace!
  
  !!! warning
  
      * The ``NaN`` values in either ``hf_y`` or ``trace.y`` will be omitted! We do
        not allow ``NaN`` values in ``hf_x`` or ``trace.x``.
      * ``hf_x``, ``hf_y``, ``hf_text``, and ``hf_hovertext`` are useful when you deal
        with large amounts of data (as it can increase the speed of this add_trace()
        method with ~30%). These arguments have priority over the trace's data and
        (hover)text attributes.
      * Low-frequency time-series data, i.e. traces that are not resampled, can hinder
        the the automatic-zooming (y-scaling) as these will not be stored in the
        back-end and thus not be scaled to the view.
        To circumvent this, the ``limit_to_view`` argument can be set, resulting in
        also storing the low-frequency series in the back-end.
docstr_tok: ["Add","a","trace","to","the","figure",".","Parameters","--","--","--","--","--","trace",":","BaseTraceType","or","dict","Either",":","-","An","instances","of","a","trace","class","from","the","``","plotly.graph_objects","``","(","go",")","package","(","e.g.",",","``","go.Scatter","``",",","``","go.Bar","``",")","-","or","a","dict","where",":","-","The","type","property","specifies","the","trace","type","(","e.g",".","scatter",",","bar",",","area",",","etc.",")",".","If","the","dict","has","no","'type","'","property","then","scatter","is","assumed",".","-","All","remaining","properties","are","passed","to","the","constructor","of","the","specified","trace","type",".","max_n_samples",":","int",",","optional","The","maximum","number","of","samples","that","will","be","shown","by","the","trace",".","!","!","!","note","If","this","variable","is","not","set",";","``","_global_n_shown_samples","``","will","be","used",".","downsampler",":","AbstractAggregator",",","optional","The","abstract","series","downsampler","method",".","!","!","!","note","If","this","variable","is","not","set",",","``","_global_downsampler","``","will","be","used",".","gap_handler",":","AbstractGapHandler",",","optional","The","abstract","series","gap","handler","method",".","!","!","!","note","If","this","variable","is","not","set",",","``","_global_gap_handler","``","will","be","used",".","limit_to_view",":","boolean",",","optional","If","set","to","True",",","the","trace","'s","datapoints","will","be","cut","to","the","corresponding","front-end","view",",","even","if","the","total","number","of","samples","is","lower","than","``","max_n_samples","``",",","By","default","False",".","Remark","that","setting","this","parameter","to","True","ensures","that","low","frequency","traces","are","added","to","the","``","hf_data","``","property",".","hf_x",":","Iterable",",","optional","The","original","high","frequency","series","positions",",","can","be","either","a","time-series","or","an","increasing",",","numerical","index",".","If","set",",","this","has","priority","over","the","trace","its","data",".","hf_y",":","Iterable",",","optional","The","original","high","frequency","values",".","If","set",",","this","has","priority","over","the","trace","its","data",".","hf_text",":","Iterable",",","optional","The","original","high","frequency","text",".","If","set",",","this","has","priority","over","the","trace","its","``","text","``","argument",".","hf_hovertext",":","Iterable",",","optional","The","original","high","frequency","hovertext",".","If","set",",","this","has","priority","over","the","trace","its","``","`","hovertext","``","argument",".","hf_marker_size",":","Iterable",",","optional","The","original","high","frequency","marker","size",".","If","set",",","this","has","priority","over","the","trace","its","``","marker.size","``","argument",".","hf_marker_color",":","Iterable",",","optional","The","original","high","frequency","marker","color",".","If","set",",","this","has","priority","over","the","trace","its","``","marker.color","``","argument",".","check_nans",":","boolean",",","optional","If","set","to","True",",","the","trace","'s","data","will","be","checked","for","NaNs","-","which","will","be","removed",".","By","default","True",".","As","this","is","a","costly","operation",",","it","is","recommended","to","set","this","parameter","to","False","if","you","are","sure","that","your","data","does","not","contain","NaNs","(","or","when","the","downsampler","can","handle","NaNs",",","e.g.",",","EveryNthPoint",")",".","This","should","considerably","speed","up","the","graph","construction","time",".","*","*","trace_kwargs",":","dict","Additional","trace","related","keyword","arguments",".","e.g",".",":","row=","..",",","col=","...",",","secondary_y=","...","!","!","!","info","``","See","Also","''","[","`","Figure.add_trace","`","]","(","https",":","\/\/plotly.com\/python-api-reference\/generated\/plotly.graph_objects.Figure.html","#","plotly.graph_objects.Figure.add_trace",">",")","docs",".","Returns","--","--","--","-","BaseFigure","The","Figure","on","which","``","add_trace","``","was","called","on",";","i.e",".","self",".","!","!","!","note","Constructing","traces","with","*","*","very","large","data","amounts","*","*","really","takes","some","time",".","To","speed","this","up",";","use","this","[","`","add_trace","`","]","[","figure_resampler.figure_resampler_interface.AbstractFigureAggregator.add_trace","]","method","and","1",".","Create","a","trace","with","no","data","(","empty","lists",")","2.","pass","the","high","frequency","data","to","this","method","using","the","``","hf_x","``","and","``","hf_y","``","parameters",".","See","the","example","below",":","``","`","python",">",">",">","from","plotly.subplots","import","make_subplots",">",">",">","s","=","pd.Series","(",")","#","a","high-frequency","series",",","with","more","than","1e7","samples",">",">",">","fig","=","FigureResampler","(","go.Figure","(",")",")",">",">",">","fig.add_trace","(","go.Scattergl","(","x=","[","]",",","y=","[","]",",","...",")",",","hf_x=s.index",",","hf_y=s",")","``","`","!","!","!","todo","*","explain","why","adding","x","and","y","to","a","trace","is","so","slow","*","check","and","simplify","the","example","above","!","!","!","tip","*","If","you","*","*","do","not","want","to","downsample","*","*","your","data",",","set","``","max_n_samples","``","to","the","the","number","of","datapoints","of","your","trace","!","!","!","!","warning","*","The","``","NaN","``","values","in","either","``","hf_y","``","or","``","trace.y","``","will","be","omitted","!","We","do","not","allow","``","NaN","``","values","in","``","hf_x","``","or","``","trace.x","``",".","*","``","hf_x","``",",","``","hf_y","``",",","``","hf_text","``",",","and","``","hf_hovertext","``","are","useful","when","you","deal","with","large","amounts","of","data","(","as","it","can","increase","the","speed","of","this","add_trace","(",")","method","with","~30","%",")",".","These","arguments","have","priority","over","the","trace","'s","data","and","(","hover",")","text","attributes",".","*","Low-frequency","time-series","data",",","i.e",".","traces","that","are","not","resampled",",","can","hinder","the","the","automatic-zooming","(","y-scaling",")","as","these","will","not","be","stored","in","the","back-end","and","thus","not","be","scaled","to","the","view",".","To","circumvent","this",",","the","``","limit_to_view","``","argument","can","be","set",",","resulting","in","also","storing","the","low-frequency","series","in","the","back-end","."]
code: def add_trace(
      self,
      trace: Union[BaseTraceType, dict],
      max_n_samples: int = None,
      downsampler: AbstractAggregator = None,
      gap_handler: AbstractGapHandler = None,
      limit_to_view: bool = False,
      # Use these if you want some speedups (and are working with really large data)
      hf_x: Iterable = None,
      hf_y: Iterable = None,
      hf_text: Union[str, Iterable] = None,
      hf_hovertext: Union[str, Iterable] = None,
      hf_marker_size: Union[str, Iterable] = None,
      hf_marker_color: Union[str, Iterable] = None,
      check_nans: bool = True,
      **trace_kwargs,
  ):
      """Add a trace to the figure.
  
      Parameters
      ----------
      trace : BaseTraceType or dict
          Either:
  
            - An instances of a trace class from the ``plotly.graph_objects`` (go)
              package (e.g., ``go.Scatter``, ``go.Bar``)
            - or a dict where:
  
              - The type property specifies the trace type (e.g. scatter, bar,
                area, etc.). If the dict has no 'type' property then scatter is
                assumed.
              - All remaining properties are passed to the constructor
                of the specified trace type.
      max_n_samples : int, optional
          The maximum number of samples that will be shown by the trace.\n
          !!! note
              If this variable is not set; ``_global_n_shown_samples`` will be used.
      downsampler: AbstractAggregator, optional
          The abstract series downsampler method.\n
          !!! note
              If this variable is not set, ``_global_downsampler`` will be used.
      gap_handler: AbstractGapHandler, optional
          The abstract series gap handler method.\n
          !!! note
              If this variable is not set, ``_global_gap_handler`` will be used.
      limit_to_view: boolean, optional
          If set to True, the trace's datapoints will be cut to the corresponding
          front-end view, even if the total number of samples is lower than
          ``max_n_samples``, By default False.\n
          Remark that setting this parameter to True ensures that low frequency traces
          are added to the ``hf_data`` property.
      hf_x: Iterable, optional
          The original high frequency series positions, can be either a time-series or
          an increasing, numerical index. If set, this has priority over the trace its
          data.
      hf_y: Iterable, optional
          The original high frequency values. If set, this has priority over the
          trace its data.
      hf_text: Iterable, optional
          The original high frequency text. If set, this has priority over the trace
          its ``text`` argument.
      hf_hovertext: Iterable, optional
          The original high frequency hovertext. If set, this has priority over the
          trace its ```hovertext`` argument.
      hf_marker_size: Iterable, optional
          The original high frequency marker size. If set, this has priority over the
          trace its ``marker.size`` argument.
      hf_marker_color: Iterable, optional
          The original high frequency marker color. If set, this has priority over the
          trace its ``marker.color`` argument.
      check_nans: boolean, optional
          If set to True, the trace's data will be checked for NaNs - which will be
          removed. By default True.
          As this is a costly operation, it is recommended to set this parameter to
          False if you are sure that your data does not contain NaNs (or when the
          downsampler can handle NaNs, e.g., EveryNthPoint). This should considerably
          speed up the graph construction time.
      **trace_kwargs: dict
          Additional trace related keyword arguments.
          e.g.: row=.., col=..., secondary_y=...
  
          !!! info "See Also"
              [`Figure.add_trace`](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Figure.html#plotly.graph_objects.Figure.add_trace>) docs.
  
      Returns
      -------
      BaseFigure
          The Figure on which ``add_trace`` was called on; i.e. self.
  
      !!! note
  
          Constructing traces with **very large data amounts** really takes some time.
          To speed this up; use this [`add_trace`][figure_resampler.figure_resampler_interface.AbstractFigureAggregator.add_trace] method and
  
          1. Create a trace with no data (empty lists)
          2. pass the high frequency data to this method using the ``hf_x`` and ``hf_y``
             parameters.
  
          See the example below:
              ```python
              >>> from plotly.subplots import make_subplots
              >>> s = pd.Series()  # a high-frequency series, with more than 1e7 samples
              >>> fig = FigureResampler(go.Figure())
              >>> fig.add_trace(go.Scattergl(x=[], y=[], ...), hf_x=s.index, hf_y=s)
              ```
  
          !!! todo
              * explain why adding x and y to a trace is so slow
              * check and simplify the example above
  
      !!! tip
  
          * If you **do not want to downsample** your data, set ``max_n_samples`` to the
            the number of datapoints of your trace!
  
      !!! warning
  
          * The ``NaN`` values in either ``hf_y`` or ``trace.y`` will be omitted! We do
            not allow ``NaN`` values in ``hf_x`` or ``trace.x``.
          * ``hf_x``, ``hf_y``, ``hf_text``, and ``hf_hovertext`` are useful when you deal
            with large amounts of data (as it can increase the speed of this add_trace()
            method with ~30%). These arguments have priority over the trace's data and
            (hover)text attributes.
          * Low-frequency time-series data, i.e. traces that are not resampled, can hinder
            the the automatic-zooming (y-scaling) as these will not be stored in the
            back-end and thus not be scaled to the view.
            To circumvent this, the ``limit_to_view`` argument can be set, resulting in
            also storing the low-frequency series in the back-end.
  
      """
      # to comply with the plotly data input acceptance behavior
      if isinstance(trace, (list, tuple)):
          raise ValueError(
              "Trace must be either a dict or a BaseTraceType"
          )
  
      max_out_s = (
          self._global_n_shown_samples
          if max_n_samples is None
          else max_n_samples
      )
  
      # Validate the trace and convert to a trace object
      if not isinstance(trace, BaseTraceType):
          trace = self._data_validator.validate_coerce(trace)[0]
  
      # First add a UUID, as each (even the non-hf_data traces), must contain this
      # key for comparison. If the trace already has a UUID, we will keep it.
      uuid_str = str(uuid4()) if trace.uid is None else trace.uid
      trace.uid = uuid_str
  
      # construct the hf_data_container
      # TODO in future version -> maybe regex on kwargs which start with `hf_`
      dc = self._parse_get_trace_props(
          trace,
          hf_x,
          hf_y,
          hf_text,
          hf_hovertext,
          hf_marker_size,
          hf_marker_color,
          check_nans,
      )
  
      # These traces will determine the autoscale its RANGE!
      #   -> so also store when `limit_to_view` is set.
      if trace["type"].lower() in self._high_frequency_traces:
          n_samples = len(dc.x)
          if n_samples > max_out_s or limit_to_view:
              self._print(
                  f"\t[i] DOWNSAMPLE {trace['name']}\t{n_samples}->{max_out_s}"
              )
  
              self._hf_data[uuid_str] = self._construct_hf_data_dict(
                  dc,
                  trace=trace,
                  downsampler=downsampler,
                  gap_handler=gap_handler,
                  max_n_samples=max_n_samples,
              )
  
              # Before we update the trace, we create a new pointer to that trace in
              # which the downsampled data will be stored. This way, the original
              # data of the trace to this `add_trace` method will not be altered.
              # We copy (by reference) all the non-data properties of the trace in
              # the new trace.
              trace = trace._props  # convert the trace into a dict
              # NOTE: there is no need to store `marker` property here.
              # If needed, it will be added  to `trace` via `check_update_trace_data`
              trace = {
                  k: trace[k]
                  for k in set(trace.keys()).difference(set(dc._fields))
              }
  
              # NOTE:
              # If all the raw data needs to be sent to the javascript, and the trace
              # is high-frequency, this would take significant time!
              # Hence, you first downsample the trace.
              trace = self._check_update_trace_data(trace)
              assert trace is not None
              return super(AbstractFigureAggregator, self).add_traces(
                  [trace],
                  **self._add_trace_to_add_traces_kwargs(trace_kwargs),
              )
          else:
              self._print(
                  f"[i] NOT resampling {trace['name']} - len={n_samples}"
              )
              trace._process_kwargs(
                  **{k: getattr(dc, k) for k in dc._fields}
              )
              return super(AbstractFigureAggregator, self).add_traces(
                  [trace],
                  **self._add_trace_to_add_traces_kwargs(trace_kwargs),
              )
  
      return super(self._figure_class, self).add_traces(
          [trace], **self._add_trace_to_add_traces_kwargs(trace_kwargs)
      )
  
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 14 for calling the AbstractFigureAggregator obj's underlying member method code with example usage: obj.add_trace(trace, max_n_samples, downsampler, gap_handler, limit_to_view, hf_x, hf_y, hf_text, hf_hovertext, hf_marker_size, hf_marker_color, check_nans) and returns: super, super, super