code: def sim_anomalous_data_and_forecasts(
      sample_size, anomaly_num, anomaly_magnitude=20, seed=None
  ):
      """This function construct normal data and injects anomalies into the data
          (returned in ``"df"`` item of the result).
          It also creates two forecasts (given in ``"forecast_dfs"``) for the same
          data of varying quality in terms of accuracy.
          The first forecast is constructed to be more accurate.
          The fuction also returns train and test versions of these data which are
          constructed to be the first and second half of the generated data respectively.
  
      Parameters
      ----------
      sample_size : `int`
          The total sample size of the data generated
      anomaly_num : `int`
          The number of anomalies injected into the data
      anomaly_magnitude : `float`, default 20
          The magnitude of the anomalies injected, which is the mean of the normal
          distribution used to add the anomalies.
      seed : `int` or None, default None
          The seed used in randomization. If None, no seed is set.
  
  
      Returns
      -------
      result : `dict`
      A dictionary consisting of these items
  
          - ``"df"`` : `pandas.DataFrame`
              A dataframe which includes a time series with columns
              - "ts" : to denote time, ranging from 0 to ``sample_size``
              - "y" : the value of the series
              - "is_anomaly" : boolean to denote is the point is an anomaly
          - ``"forecast_dfs"`` : `list` [`pandas.DataFrame`]
              A list of two dataframes which are to be considered to come from
              a predictive model.
              These are constructed simply by adding noise to observations.
              The first forecast is more accurate by construction (less noisy).
              below.
          - ``"df_train"`` : `pandas.DataFrame`
              First half of ``"df"`` defined above, which is usually to be used in
              training step.
          - ``"forecast_dfs_train"`` : `list` [`pandas.DataFrame`]
              First half of the forecast data given in ``"forecast_dfs"`` defined
              above.
          - ``"df_test"`` : `pandas.DataFrame`
              Second half of ``"df"`` defined above, which is usually used in testing
              step.
          - ``"forecast_dfs_test"`` : `list` [`pandas.DataFrame`]
              Second half of the forecast data given in ``"forecast_dfs"`` defined
              above.
          - ``"fig"``: `plotly.graph_objects.Figure`
              A plotly interactive figure, to compare the observed data with the two
              predictions constructed in this function.
  
      """
  
      np.random.seed(seed=seed)
      y = np.arange(0, sample_size, dtype=float)
      is_anomaly = [False] * sample_size
      y_pred0 = y + np.random.normal(
          loc=0.0, scale=1.0, size=sample_size
      )
  
      y_pred1 = y + np.random.normal(
          loc=0.0, scale=10.0, size=sample_size
      )
  
      anomaly_idx = np.random.choice(
          np.arange(0, sample_size, dtype=int),
          size=anomaly_num,
          replace=False,
      )
  
      anomaly_idx.sort()
  
      for idx in anomaly_idx:
          # Randomly introduces positive or negative anomalies
          p = np.random.uniform(low=0.0, high=1.0)
          if p > 0.5:
              y[idx] += np.random.normal(
                  loc=anomaly_magnitude, scale=1.0
              )
          else:
              y[idx] += -np.random.normal(
                  loc=anomaly_magnitude, scale=1.0
              )
  
          is_anomaly[idx] = True
  
      ts = range(sample_size)
      df = pd.DataFrame({"ts": ts, "y": y, "is_anomaly": is_anomaly})
  
      df0 = pd.DataFrame({"ts": ts, "y_pred": y_pred0})
  
      df1 = pd.DataFrame({"ts": ts, "y_pred": y_pred1})
  
      df_all = pd.DataFrame(
          {"ts": ts, "y": y, "y_pred0": y_pred0, "y_pred1": y_pred1}
      )
  
      forecast_dfs = {}
      forecast_dfs[0] = df0
      forecast_dfs[1] = df1
  
      fig = plot_lines_markers(
          df=df_all, x_col="ts", line_cols=["y", "y_pred0", "y_pred1"]
      )
  
      train_size = int(sample_size / 2)
      df_train = df[:train_size]
      forecast_dfs_train = {
          k: df[:train_size] for k, df in forecast_dfs.items()
      }
  
      df_test = df[train_size:]
      forecast_dfs_test = {
          k: df[train_size:] for k, df in forecast_dfs.items()
      }
  
      return {
          "df": df,
          "forecast_dfs": forecast_dfs,
          "df_train": df_train,
          "forecast_dfs_train": forecast_dfs_train,
          "df_test": df_test,
          "forecast_dfs_test": forecast_dfs_test,
          "fig": fig,
      }
  
file_path: greykite/greykite/detection/common/testing_utils.py
imports: import numpy
  import pandas
  from greykite.common.constants import ANOMALY_COL
  from greykite.common.constants import TIME_COL
  from greykite.common.constants import VALUE_COL
  from greykite.common.testing_utils import generate_df_for_tests
  from greykite.common.testing_utils_anomalies import contaminate_df_with_anomalies
  from greykite.common.viz.timeseries_annotate import plot_lines_markers
  from greykite.detection.detector.ad_utils import get_anomaly_df
label_desc: Use image node_id 5 for calling a global function with example usage: sim_anomalous_data_and_forecasts(sample_size, anomaly_num, anomaly_magnitude, seed) and returns: dict