code: def ancova(
      data=None, dv=None, between=None, covar=None, effsize="np2"
  ):
      """ANCOVA with one or more covariate(s).
  
      Parameters
      ----------
      data : :py:class:`pandas.DataFrame`
          DataFrame. Note that this function can also directly be used as a
          Pandas method, in which case this argument is no longer needed.
      dv : string
          Name of column in data with the dependent variable.
      between : string
          Name of column in data with the between factor.
      covar : string or list
          Name(s) of column(s) in data with the covariate.
      effsize : str
          Effect size. Must be 'np2' (partial eta-squared) or 'n2'
          (eta-squared).
  
      Returns
      -------
      aov : :py:class:`pandas.DataFrame`
          ANCOVA summary:
  
          * ``'Source'``: Names of the factor considered
          * ``'SS'``: Sums of squares
          * ``'DF'``: Degrees of freedom
          * ``'F'``: F-values
          * ``'p-unc'``: Uncorrected p-values
          * ``'np2'``: Partial eta-squared
  
      Notes
      -----
      Analysis of covariance (ANCOVA) is a general linear model which blends
      ANOVA and regression. ANCOVA evaluates whether the means of a dependent
      variable (dv) are equal across levels of a categorical independent
      variable (between) often called a treatment, while statistically
      controlling for the effects of other continuous variables that are not
      of primary interest, known as covariates or nuisance variables (covar).
  
      Pingouin uses :py:class:`statsmodels.regression.linear_model.OLS` to
      compute the ANCOVA.
  
      .. important:: Rows with missing values are automatically removed
          (listwise deletion).
  
      See Also
      --------
      anova : One-way and N-way ANOVA
  
      Examples
      --------
      1. Evaluate the reading scores of students with different teaching method
      and family income as a covariate.
  
      >>> from pingouin import ancova, read_dataset
      >>> df = read_dataset('ancova')
      >>> ancova(data=df, dv='Scores', covar='Income', between='Method')
           Source           SS  DF          F     p-unc       np2
      0    Method   571.029883   3   3.336482  0.031940  0.244077
      1    Income  1678.352687   1  29.419438  0.000006  0.486920
      2  Residual  1768.522313  31        NaN       NaN       NaN
  
      2. Evaluate the reading scores of students with different teaching method
      and family income + BMI as a covariate.
  
      >>> ancova(data=df, dv='Scores', covar=['Income', 'BMI'], between='Method',
      ...        effsize="n2")
           Source           SS  DF          F     p-unc        n2
      0    Method   552.284043   3   3.232550  0.036113  0.141802
      1    Income  1573.952434   1  27.637304  0.000011  0.404121
      2       BMI    60.013656   1   1.053790  0.312842  0.015409
      3  Residual  1708.508657  30        NaN       NaN       NaN
      """
      # Import
      from pingouin.utils import _is_statsmodels_installed
  
      _is_statsmodels_installed(raise_error=True)
      from statsmodels.api import stats
      from statsmodels.formula.api import ols
  
      # Safety checks
      assert effsize in ["np2", "n2"], "effsize must be 'np2' or 'n2'."
      assert isinstance(
          data, pd.DataFrame
      ), "data must be a pandas dataframe."
      assert isinstance(between, str), (
          "between must be a string. Pingouin does not support multiple "
          "between factors. For more details, please see "
          "https://github.com/raphaelvallat/pingouin/issues/173."
      )
      assert dv in data.columns, "%s is not in data." % dv
      assert between in data.columns, "%s is not in data." % between
      assert isinstance(
          covar, (str, list)
      ), "covar must be a str or a list."
      if isinstance(covar, str):
          covar = [covar]
      for c in covar:
          assert c in data.columns, "covariate %s is not in data" % c
          assert data[c].dtype.kind in "bfi", (
              "covariate %s is not numeric" % c
          )
  
      # Drop missing values
      data = data[_flatten_list([dv, between, covar])].dropna()
  
      # Fit ANCOVA model
      # formula = dv ~ 1 + between + covar1 + covar2 + ...
      assert dv not in ["C", "Q"], "`dv` must not be 'C' or 'Q'."
      assert between not in [
          "C",
          "Q",
      ], "`between` must not be 'C' or 'Q'."
      assert all(
          c not in ["C", "Q"] for c in covar
      ), "`covar` must not contain 'C' or 'Q'."
      formula = f"Q('{dv}') ~ C(Q('{between}'))"
      for c in covar:
          formula += " + Q('%s')" % (c)
      model = ols(formula, data=data).fit()
  
      # Create output dataframe
      aov = stats.anova_lm(model, typ=2).reset_index()
      aov.rename(
          columns={
              "index": "Source",
              "sum_sq": "SS",
              "df": "DF",
              "PR(>F)": "p-unc",
          },
          inplace=True,
      )
      aov.at[0, "Source"] = between
      for i in range(len(covar)):
          aov.at[i + 1, "Source"] = covar[i]
      aov["DF"] = aov["DF"].astype(int)
  
      # Add effect sizes
      if effsize == "n2":
          all_effsize = (aov["SS"] / aov["SS"].sum()).to_numpy()
          all_effsize[-1] = np.nan
      else:
          ss_resid = aov["SS"].iloc[-1]
          all_effsize = (
              aov["SS"].apply(lambda x: x / (x + ss_resid)).to_numpy()
          )
          all_effsize[-1] = np.nan
      aov[effsize] = all_effsize
  
      # Add bw as an attribute (for rm_corr function)
      aov = _postprocess_dataframe(aov)
      aov.bw_ = model.params.iloc[-1]
      return aov
  
file_path: pingouin/pingouin/parametric.py
imports: import warnings
  from collections.abc import Iterable
  import numpy
  import pandas
  from scipy.stats import f
  import pandas_flavor
  from pingouin import _check_dataframe, remove_na, _flatten_list, bayesfactor_ttest, epsilon, sphericity, _postprocess_dataframe
label_desc: Use image node_id 9 for calling a global function with example usage: ancova(data, dv, between, covar, effsize) and returns: aov