class_docstr: Stacks adjacent observations into a single vector. Downsamples by the
  specified stride (less than or equal to the shingle size) if desired.
  
  More concretely, consider an input time series,
  
  .. code-block:: python
  
      TimeSeries(
          UnivariateTimeSeries((t1[0], x1[0]), ..., (t1[m], t1[m])),
          UnivariateTimeSeries((t2[0], x2[0]), ..., (t2[m], t2[m])),
      )
  
  Applying a shingle of size 3 and stride 2 will yield
  
  .. code-block:: python
  
      TimeSeries(
          UnivariateTimeSeries((t1[0], x1[0]), (t1[2], x1[2]), ..., (t1[m-2], x1[m-2])),
          UnivariateTimeSeries((t1[1], x1[1]), (t1[3], x1[3]), ..., (t1[m-1], x1[m-1])),
          UnivariateTimeSeries((t1[2], x1[2]), (t1[4], x1[4]), ..., (t1[m],   x1[m])),
  
          UnivariateTimeSeries((t2[0], x2[0]), (t2[2], x2[2]), ..., (t2[m-2], x2[m-2])),
          UnivariateTimeSeries((t2[1], x2[1]), (t2[3], x2[3]), ..., (t2[m-1], x2[m-1])),
          UnivariateTimeSeries((t2[2], x2[2]), (t2[4], x2[4]), ..., (t2[m],   x2[m])),
      )
  
  If the length of any univariate is not perfectly divisible by the stride, we
  will pad it on the left side with the first value in the univariate.
class_docstr_tok: ["Stacks","adjacent","observations","into","a","single","vector",".","Downsamples","by","the","specified","stride","(","less","than","or","equal","to","the","shingle","size",")","if","desired",".","More","concretely",",","consider","an","input","time","series",",","..","code-block",":",":","python","TimeSeries","(","UnivariateTimeSeries","(","(","t1","[","0","]",",","x1","[","0","]",")",",","...",",","(","t1","[","m","]",",","t1","[","m","]",")",")",",","UnivariateTimeSeries","(","(","t2","[","0","]",",","x2","[","0","]",")",",","...",",","(","t2","[","m","]",",","t2","[","m","]",")",")",",",")","Applying","a","shingle","of","size","3","and","stride","2","will","yield","..","code-block",":",":","python","TimeSeries","(","UnivariateTimeSeries","(","(","t1","[","0","]",",","x1","[","0","]",")",",","(","t1","[","2","]",",","x1","[","2","]",")",",","...",",","(","t1","[","m-2","]",",","x1","[","m-2","]",")",")",",","UnivariateTimeSeries","(","(","t1","[","1","]",",","x1","[","1","]",")",",","(","t1","[","3","]",",","x1","[","3","]",")",",","...",",","(","t1","[","m-1","]",",","x1","[","m-1","]",")",")",",","UnivariateTimeSeries","(","(","t1","[","2","]",",","x1","[","2","]",")",",","(","t1","[","4","]",",","x1","[","4","]",")",",","...",",","(","t1","[","m","]",",","x1","[","m","]",")",")",",","UnivariateTimeSeries","(","(","t2","[","0","]",",","x2","[","0","]",")",",","(","t2","[","2","]",",","x2","[","2","]",")",",","...",",","(","t2","[","m-2","]",",","x2","[","m-2","]",")",")",",","UnivariateTimeSeries","(","(","t2","[","1","]",",","x2","[","1","]",")",",","(","t2","[","3","]",",","x2","[","3","]",")",",","...",",","(","t2","[","m-1","]",",","x2","[","m-1","]",")",")",",","UnivariateTimeSeries","(","(","t2","[","2","]",",","x2","[","2","]",")",",","(","t2","[","4","]",",","x2","[","4","]",")",",","...",",","(","t2","[","m","]",",","x2","[","m","]",")",")",",",")","If","the","length","of","any","univariate","is","not","perfectly","divisible","by","the","stride",",","we","will","pad","it","on","the","left","side","with","the","first","value","in","the","univariate","."]
code: def __call__(self, time_series: TimeSeries) -> TimeSeries:
      if self.multivar_skip and time_series.dim > 1:
          self.inversion_state = "skip"
          return time_series
  
      new_vars = OrderedDict()
  
      for name, var in time_series.items():
          # Left-pad the time series with the first value
          x0 = var.np_values[0]
          vals = np.concatenate(
              (np.full(self.size - 1, x0), var.np_values)
          )
  
          # Stack adjacent observations into vectors of length self.size,
          # and apply any striding desired
          i0 = (len(var) - 1) % self.stride
          times = var.index[i0 :: self.stride]
          all_vals = np.stack(
              [
                  vals[i : len(vals) - self.size + i + 1]
                  for i in range(self.size)
              ]
          )
          all_vals = all_vals[:, i0 :: self.stride]
  
          # Convert the stacked values into UnivariateTimeSeries objects
          new_vars.update(
              OrderedDict(
                  [
                      (f"{name}_{i}", UnivariateTimeSeries(times, x))
                      for i, x in enumerate(all_vals)
                  ]
              )
          )
  
      # The inversion state is just the timestamps of the univariates before
      # shingling occurs, and the name of the original univariate
      self.inversion_state = [
          (name, v.index) for name, v in time_series.items()
      ]
      return TimeSeries(new_vars)
  
imports: from collections import OrderedDict
  import logging
  from typing import Union
  import numpy
  from merlion.transform.base import TransformBase, InvertibleTransformBase
  from merlion.utils import UnivariateTimeSeries, TimeSeries
  from merlion.utils.resample import infer_granularity, granularity_str_to_seconds, AlignPolicy, AggregationPolicy, MissingValuePolicy
label_desc: Use image node_id 3 for calling the Shingle obj's underlying member method code with example usage: obj.__call__(time_series) and returns: TimeSeries, time_series