class_docstr: The query objects are constructed on the client.
code: def _init_series_columns(
      self,
      series_columns: list[Column] | None,
      metrics: list[Metric] | None,
      is_timeseries: bool | None,
  ) -> None:
      if series_columns:
          self.series_columns = series_columns
      elif is_timeseries and metrics:
          self.series_columns = self.columns
      else:
          self.series_columns = []
  
imports: from __future__ import annotations
  import json
  import logging
  from datetime import datetime
  from pprint import pformat
  from typing import Any, NamedTuple, TYPE_CHECKING
  from flask import g
  from flask_babel import gettext
  from pandas import DataFrame
  from superset import feature_flag_manager
  from superset.common.chart_data import ChartDataResultType
  from superset.exceptions import InvalidPostProcessingError, QueryClauseValidationException, QueryObjectValidationError
  from superset.sql_parse import sanitize_clause
  from superset.superset_typing import Column, Metric, OrderBy
  from superset.utils import pandas_postprocessing
  from superset.utils.core import DTTM_ALIAS, find_duplicates, get_column_names, get_metric_names, is_adhoc_metric, json_int_dttm_ser, QueryObjectFilterClause
  from superset.utils.hashing import md5_sha_from_dict
label_desc: Use image node_id 6 for calling the QueryObject obj's underlying member method code with example usage: obj._init_series_columns(series_columns, metrics, is_timeseries) without return types