docstr: Aggregate the data in `hf_trace_data` between `start_idx` and `end_idx`.
  
  Returns:
      - x: the aggregated x-values
      - y: the aggregated y-values
      - indices: the indices of the hf_data data that were aggregated
  
      These indices are useful to select the corresponding hf_data from
      non `x` and `y` data (e.g. `text`, `marker_size`, `marker_color`).
docstr_tok: ["Aggregate","the","data","in","`","hf_trace_data","`","between","`","start_idx","`","and","`","end_idx","`",".","Returns",":","-","x",":","the","aggregated","x-values","-","y",":","the","aggregated","y-values","-","indices",":","the","indices","of","the","hf_data","data","that","were","aggregated","These","indices","are","useful","to","select","the","corresponding","hf_data","from","non","`","x","`","and","`","y","`","data","(","e.g",".","`","text","`",",","`","marker_size","`",",","`","marker_color","`",")","."]
code: def aggregate(
      hf_trace_data: dict,
      start_idx: int,
      end_idx: int,
  ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
      """Aggregate the data in `hf_trace_data` between `start_idx` and `end_idx`.
  
      Returns:
          - x: the aggregated x-values
          - y: the aggregated y-values
          - indices: the indices of the hf_data data that were aggregated
  
          These indices are useful to select the corresponding hf_data from
          non `x` and `y` data (e.g. `text`, `marker_size`, `marker_color`).
  
      """
      hf_x = hf_trace_data["x"][start_idx:end_idx]
      hf_y = hf_trace_data["y"][start_idx:end_idx]
  
      # No downsampling needed ; we show the raw data as is, but with gap-detection
      if (end_idx - start_idx) <= hf_trace_data["max_n_samples"]:
          indices = np.arange(
              len(hf_y)
          )  # no downsampling - all values are selected
          if len(indices):
              return PlotlyAggregatorParser._handle_gaps(
                  hf_trace_data,
                  hf_x=hf_x,
                  agg_x=hf_x,
                  agg_y=hf_y,
                  indices=indices,
              )
          else:
              return hf_x, hf_y, indices
  
      downsampler = hf_trace_data["downsampler"]
  
      hf_x_parsed = PlotlyAggregatorParser.parse_hf_data(hf_x)
      hf_y_parsed = PlotlyAggregatorParser.parse_hf_data(hf_y)
  
      if isinstance(downsampler, DataPointSelector):
          s_v = hf_y_parsed
          if isinstance(
              s_v, pd.Categorical
          ):  # pd.Categorical (has no .values)
              s_v = s_v.codes
          indices = downsampler.arg_downsample(
              hf_x_parsed,
              s_v,
              n_out=hf_trace_data["max_n_samples"],
              **hf_trace_data.get("downsampler_kwargs", {}),
          )
          if isinstance(hf_trace_data["x"], pd.RangeIndex):
              # we avoid slicing the default pd.RangeIndex (as this is not an
              # in-memory array) - this proves to be faster than slicing the index.
              agg_x = (
                  start_idx
                  + hf_trace_data["x"].start
                  + indices * hf_trace_data["x"].step
              )
          else:
              agg_x = hf_x[indices]
          agg_y = hf_y[indices]
      elif isinstance(downsampler, DataAggregator):
          agg_x, agg_y = downsampler.aggregate(
              hf_x_parsed,
              hf_y_parsed,
              n_out=hf_trace_data["max_n_samples"],
              **hf_trace_data.get("downsampler_kwargs", {}),
          )
          if isinstance(hf_trace_data["x"], pd.RangeIndex):
              # we avoid slicing the default pd.RangeIndex (as this is not an
              # in-memory array) - this proves to be faster than slicing the index.
              agg_x = (
                  start_idx
                  + hf_trace_data["x"].start
                  + agg_x * hf_trace_data["x"].step
              )
          # The indices are just the range of the aggregated data
          indices = np.arange(len(agg_x))
      else:
          raise ValueError(
              "Invalid downsampler instance, must be either a "
              + f"DataAggregator or a DataPointSelector, got {type(downsampler)}"
          )
  
      return PlotlyAggregatorParser._handle_gaps(
          hf_trace_data,
          hf_x=hf_x,
          agg_x=agg_x,
          agg_y=agg_y,
          indices=indices,
      )
  
file_path: plotly-resampler/plotly_resampler/aggregation/plotly_aggregator_parser.py
imports: from __future__ import annotations
  import bisect
  from typing import Tuple, Union
  import numpy
  import pandas
  import pytz
  from .aggregation_interface import DataAggregator, DataPointSelector
  from .gap_handler_interface import AbstractGapHandler
  from .gap_handlers import NoGapHandler
label_desc: Use image node_id 5 for calling the PlotlyAggregatorParser obj's underlying member method code with example usage: obj.aggregate(hf_trace_data, start_idx, end_idx) and returns: PlotlyAggregatorParser, PlotlyAggregatorParser, hf_x,  hf_y,  indices