code: def test_osrt(
      data: Union[List, np.ndarray, DataFrame],
      val_col: str = None,
      group_col: str = None,
      sort: bool = False,
  ) -> Tuple[float, float, int]:
      """Hayter's one-sided studentised range test (OSRT)
  
      Tests a hypothesis against an ordered alternative for normal data with
      equal variances [1]_.
  
      Parameters
      ----------
      data : Union[List, numpy.ndarray, DataFrame]
          An array, any object exposing the array interface or a pandas
          DataFrame with data values.
  
      val_col : str = None
          Name of a DataFrame column that contains dependent variable values
          (test or response variable). Values should have a non-nominal scale.
          Must be specified if ``a`` is a pandas DataFrame object.
  
      group_col : str = None
          Name of a DataFrame column that contains independent variable values
          (grouping or predictor variable). Values should have a nominal scale
          (categorical). Must be specified if `a` is a pandas DataFrame object.
  
      sort : bool = False
          If True, sort data by block and group columns.
  
      Returns
      -------
      Tuple[float, float, int]
          P value, statistic, and number of degrees of freedom.
  
      Notes
      -----
      P values are computed from the Tukey distribution.
  
      References
      ----------
      .. [1] Hayter, A.J.(1990) A One-Sided Studentised Range Test for Testing
          Against a Simple Ordered Alternative, Journal of the American
          Statistical Association, 85, 778-785.
  
      Examples
      --------
      >>> import scikit_posthocs as sp
      >>> import pandas as pd
      >>> x = pd.DataFrame({"a": [1,2,3,5,1], "b": [12,31,54,62,12], "c": [10,12,6,74,11]})
      >>> x = x.melt(var_name='groups', value_name='values')
      >>> sp.test_osrt(x, val_col='values', group_col='groups')
      """
      x, _val_col, _group_col = __convert_to_df(
          data, val_col, group_col
      )
  
      if not sort:
          x[_group_col] = Categorical(
              x[_group_col],
              categories=x[_group_col].unique(),
              ordered=True,
          )
  
      x.sort_values(by=[_group_col], ascending=True, inplace=True)
      groups = np.unique(x[_group_col])
      x_grouped = x.groupby(_group_col)[_val_col]
  
      xi = x_grouped.mean()
      ni = x_grouped.count()
      k = groups.size
      n = len(x.index)
      df = n - k
  
      sigma2 = 0
      c = -1
  
      for i in range(k):
          for j in range(ni.iloc[i]):
              c += 1
              sigma2 += (x[_val_col].iat[c] - xi[i]) ** 2.0 / df
  
      sigma = np.sqrt(sigma2)
  
      def compare(i, j):
          dif = xi.loc[groups[j]] - xi.loc[groups[i]]
          A = (
              sigma
              / np.sqrt(2.0)
              * np.sqrt(1.0 / ni[groups[j]] + 1.0 / ni[groups[i]])
          )
          qval = np.abs(dif) / A
          return qval
  
      vs = np.zeros((k, k), dtype=float)
      combs = it.combinations(range(k), 2)
  
      for i, j in combs:
          vs[i, j] = compare(i, j)
  
      stat = np.max(vs)
      pval = psturng(stat, k, df)
      return pval, stat, df
  
file_path: scikit-posthocs/scikit_posthocs/_omnibus.py
imports: from typing import Union, List, Tuple
  import itertools
  import numpy
  import scipy.stats
  from statsmodels.stats.libqsturng import psturng
  from pandas import DataFrame, Categorical, Series
  from scikit_posthocs._posthocs import __convert_to_df, __convert_to_block_df
label_desc: Use image node_id 2 for calling a global function with example usage: test_osrt(data, val_col, group_col, sort) and returns: pval,  stat,  df, qval