code: def power_anova(
      eta_squared=None, k=None, n=None, power=None, alpha=0.05
  ):
      """
      Evaluate power, sample size, effect size or significance level of a one-way balanced ANOVA.
  
      Parameters
      ----------
      eta_squared : float
          ANOVA effect size (eta-squared, :math:`\\eta^2`).
      k : int
          Number of groups
      n : int
          Sample size per group. Groups are assumed to be balanced (i.e. same sample size).
      power : float
          Test power (= 1 - type II error).
      alpha : float
          Significance level :math:`\\alpha` (type I error probability). The default is 0.05.
  
      Notes
      -----
      Exactly ONE of the parameters ``eta_squared``, ``k``, ``n``, ``power`` and ``alpha``
      must be passed as None, and that parameter is determined from the others.
  
      ``alpha`` has a default value of 0.05 so None must be explicitly passed if you want to
      compute it.
  
      This function is a Python adaptation of the `pwr.anova.test` function implemented in the
      `pwr <https://cran.r-project.org/web/packages/pwr/pwr.pdf>`_ R package.
  
      Statistical power is the likelihood that a study will detect an effect when there is an
      effect there to be detected. A high statistical power means that there is a low probability of
      concluding that there is no effect when there is one. Statistical power is mainly affected by
      the effect size and the sample size.
  
      For one-way ANOVA, eta-squared is the same as partial eta-squared. It can be evaluated from the
      F-value (:math:`F^*`) and the degrees of freedom of the ANOVA (:math:`v_1, v_2`) using the
      following formula:
  
      .. math:: \\eta^2 = \\frac{v_1 F^*}{v_1 F^* + v_2}
  
      GPower uses the :math:`f` effect size instead of the :math:`\\eta^2`. The formula to convert
      from one to the other are given below:
  
      .. math:: f = \\sqrt{\\frac{\\eta^2}{1 - \\eta^2}}
  
      .. math:: \\eta^2 = \\frac{f^2}{1 + f^2}
  
      Using :math:`\\eta^2` and the total sample size :math:`N`, the non-centrality parameter is
      defined by:
  
      .. math:: \\delta = N * \\frac{\\eta^2}{1 - \\eta^2}
  
      Then the critical value of the non-central F-distribution is computed using the percentile
      point function of the F-distribution with:
  
      .. math:: q = 1 - \\alpha
      .. math:: v_1 = k - 1
      .. math:: v_2 = N - k
  
      where :math:`k` is the number of groups.
  
      Finally, the power of the ANOVA is calculated using the survival function of the non-central
      F-distribution using the previously computed critical value, non-centrality parameter, and
      degrees of freedom.
  
      :py:func:`scipy.optimize.brenth` is used to solve power equations for other variables (i.e.
      sample size, effect size, or significance level). If the solving fails, a nan value is
      returned.
  
      Results have been tested against GPower and the
      `pwr <https://cran.r-project.org/web/packages/pwr/pwr.pdf>`_ R package.
  
      Examples
      --------
      1. Compute achieved power
  
      >>> from pingouin import power_anova
      >>> print('power: %.4f' % power_anova(eta_squared=0.1, k=3, n=20))
      power: 0.6082
  
      2. Compute required number of groups
  
      >>> print('k: %.4f' % power_anova(eta_squared=0.1, n=20, power=0.80))
      k: 6.0944
  
      3. Compute required sample size
  
      >>> print('n: %.4f' % power_anova(eta_squared=0.1, k=3, power=0.80))
      n: 29.9256
  
      4. Compute achieved effect size
  
      >>> print('eta-squared: %.4f' % power_anova(n=20, k=4, power=0.80, alpha=0.05))
      eta-squared: 0.1255
  
      5. Compute achieved alpha (significance)
  
      >>> print('alpha: %.4f' % power_anova(eta_squared=0.1, n=20, k=4, power=0.80, alpha=None))
      alpha: 0.1085
      """
      # Check the number of arguments that are None
      n_none = sum(
          [v is None for v in [eta_squared, k, n, power, alpha]]
      )
      if n_none != 1:
          err = (
              "Exactly one of eta, k, n, power, and alpha must be None."
          )
          raise ValueError(err)
  
      # Safety checks
      if eta_squared is not None:
          eta_squared = abs(eta_squared)
          f_sq = eta_squared / (1 - eta_squared)
      if alpha is not None:
          assert 0 < alpha <= 1
      if power is not None:
          assert 0 < power <= 1
  
      def func(f_sq, k, n, power, alpha):
          nc = (n * k) * f_sq
          dof1 = k - 1
          dof2 = (n * k) - k
          fcrit = stats.f.ppf(1 - alpha, dof1, dof2)
          return stats.ncf.sf(fcrit, dof1, dof2, nc)
  
      # Evaluate missing variable
      if power is None:
          # Compute achieved power
          return func(f_sq, k, n, power, alpha)
  
      elif k is None:
          # Compute required number of groups
  
          def _eval_k(k, f_sq, n, power, alpha):
              return func(f_sq, k, n, power, alpha) - power
  
          try:
              return brenth(
                  _eval_k, 2, 100, args=(f_sq, n, power, alpha)
              )
          except ValueError:  # pragma: no cover
              return np.nan
  
      elif n is None:
          # Compute required sample size
  
          def _eval_n(n, f_sq, k, power, alpha):
              return func(f_sq, k, n, power, alpha) - power
  
          try:
              return brenth(
                  _eval_n, 2, 1e07, args=(f_sq, k, power, alpha)
              )
          except ValueError:  # pragma: no cover
              return np.nan
  
      elif eta_squared is None:
          # Compute achieved eta-squared
  
          def _eval_eta(f_sq, k, n, power, alpha):
              return func(f_sq, k, n, power, alpha) - power
  
          try:
              f_sq = brenth(
                  _eval_eta, 1e-10, 1 - 1e-10, args=(k, n, power, alpha)
              )
              return f_sq / (f_sq + 1)  # Return eta-square
          except ValueError:  # pragma: no cover
              return np.nan
  
      else:
          # Compute achieved alpha
  
          def _eval_alpha(alpha, f_sq, k, n, power):
              return func(f_sq, k, n, power, alpha) - power
  
          try:
              return brenth(
                  _eval_alpha,
                  1e-10,
                  1 - 1e-10,
                  args=(f_sq, k, n, power),
              )
          except ValueError:  # pragma: no cover
              return np.nan
  
file_path: pingouin/pingouin/power.py
imports: import warnings
  import numpy
  from scipy import stats
  from scipy.optimize import brenth
label_desc: Use image node_id 3 for calling a global function with example usage: power_anova(eta_squared, k, n, power, alpha) and returns: stats, func, unknown, brenth, np, unknown, brenth, np, unknown, unknown, unknown, brenth, np, np