Package 'tryx'

Title: MR-TRYX (treasure your exceptions)
Description: Heterogeneity in MR analyses can arise due to horizontal pleiotropy. This package uses MR-Base to identify possible traits that can explain the heterogeneity, with a view to identifying novel putative associations, and adjusting for their influences to reduce heterogeneity and improve power.
Authors: Gibran Hemani [aut, cre], Yoonsu Cho [aut]
Maintainer: Gibran Hemani <[email protected]>
License: MIT + file LICENSE
Version: 0.2.0
Built: 2024-10-03 04:44:55 UTC
Source: https://github.com/explodecomputer/tryx

Help Index


Cochran's Q statistic

Description

Cochran's Q statistic

Usage

cochrans_q(b, se)

Arguments

b

vector of effecti

se

vector of standard errors

Value

q values


MR Strategy 1

Description

How to choose the result for a set of different MR analysies? Simple strategy: Use Wald ratio if only one SNP Use IVW if more than one SNP and heterogeneity is low Use weighted mode if more than some minimum number of SNPs and heterogeneity is high

Usage

strategy1(dat, het_threshold = 0.05, ivw_max_snp = 1)

Arguments

dat

Output from harmonise_data function

het_threshold

The p-value threshold for Cochran's Q - if lower than this threshold then run weighted mode. Default p = 0.05

ivw_max_snp

Maximum SNPs to allow IVW result even if heterogeneity is high. Default = 1


Class for MR-TRYX analysis

Description

A simple wrapper function. Using a summary set, find outliers in the MR analysis between the pair of trais. Find other 'candidate traits' associated with those outliers. Perform MR of each of those candidate traits with the original exposure and outcome.

Methods

Public methods


Method new()

Create a new dataset and initialise an R interface

Usage
Tryx$new(dat)
Arguments
dat

Dataset from TwoSampleMR::harmonise_data


Method print()

Usage
Tryx$print(...)

Method get_outliers()

Detect outliers in exposure-outcome dataset.

Usage
Tryx$get_outliers(
  dat = self$output$dat,
  outliers = "RadialMR",
  outlier_correction = "none",
  outlier_threshold = ifelse(outlier_correction == "none", 0.05/nrow(dat), 0.05)
)
Arguments
dat

Output from TwoSampleMR::harmonise_data. Note - only the first id.exposure - id.outcome pair will be used.

outliers

Default is to use the RadialMR package to identify IVW outliers. Alternatively can providen an array of SNP names that are present in dat$SNP to use as outliers.

outlier_correction

Defualt = "none", but can select from ("holm", "hochberg", "hommel", "bonferroni", "BH", "BY", "fdr", "none").

outlier_threshold

If outlier_correction = "none" then the p-value threshold for detecting outliers is by default 0.05.


Method set_candidate_traits()

Set a list of GWAS IDs used.

Usage
Tryx$set_candidate_traits(id_list = NULL)
Arguments
id_list

The list of trait IDs to search through for candidate associations. The default is the high priority traits in available_outcomes().


Method scan()

Search for candidate traits associated with outliers.

Usage
Tryx$scan(
  dat = self$output$dat,
  search_correction = "none",
  search_threshold = ifelse(search_correction == "none", 5e-08, 0.05),
  use_proxies = FALSE
)
Arguments
dat

Output from TwoSampleMR::harmonise_data.

search_correction

Default = "none", but can select from ("holm", "hochberg", "hommel", "bonferroni", "BH", "BY", "fdr", "none.

search_threshold

If search_correction = "none" then the p-value threshold for detecting an association between an outlier and a candidate trait is by default 5e-8. Otherwise it is 0.05.

use_proxies

Whether to use proxies when looking up associations. FALSE by default for speed.


Method candidate_instruments()

Obtain instruments for the candidate traits.

Usage
Tryx$candidate_instruments(
  candidate_instruments = NULL,
  include_outliers = FALSE
)
Arguments
candidate_instruments

Instruments for candidate traits.

include_outliers

When performing MR of candidate traits against exposures or outcomes, whether to include the original outlier SNP. Default is FALSE.


Method outcome_instruments()

Extract instrument for candidate trait instruments for the original outcome.

Usage
Tryx$outcome_instruments(
  candidate_outcome = NULL,
  dat = self$output$dat,
  use_proxies = FALSE
)
Arguments
candidate_outcome

Extracted instrument SNPs from outcome.

dat

Output from TwoSampleMR::harmonise_data.

use_proxies

Whether to use proxies when looking up associations. FALSE by default for speed.


Method exposure_instruments()

Extract instrument for candidate trait instruments for the original exposure.

Usage
Tryx$exposure_instruments(
  candidate_exposure = NULL,
  dat = self$output$dat,
  use_proxies = FALSE
)
Arguments
candidate_exposure

Extracted instrument SNPs from exposure.

dat

Output from TwoSampleMR::harmonise_data.

use_proxies

Whether to use proxies when looking up associations. FALSE by default for speed.


Method exposure_candidate_instruments()

Extract instrument for the original exposure for the candidate traits.

Usage
Tryx$exposure_candidate_instruments(
  exposure_candidate = NULL,
  dat = self$output$dat,
  use_proxies = FALSE,
  include_outliers = FALSE
)
Arguments
exposure_candidate

Extracted instrument SNPs from exposure.

dat

Output from TwoSampleMR::harmonise_data.

use_proxies

Whether to use proxies when looking up associations. FALSE by default for speed.

include_outliers

When performing MR of candidate traits against exposures or outcomes, whether to include the original outlier SNP. Default is FALSE.


Method extractions()

Extract instruments for MR analyses.

Usage
Tryx$extractions(
  dat = self$output$dat,
  candidate_instruments = NULL,
  candidate_outcome = NULL,
  candidate_exposure = NULL,
  exposure_candidate = NULL,
  include_outliers = FALSE,
  use_proxies = FALSE
)
Arguments
dat

Output from TwoSampleMR::harmonise_data.

candidate_instruments

Instruments for candidate traits.

candidate_outcome

Extracted instrument SNPs from outcome.

candidate_exposure

Extracted instrument SNPs from exposure.

exposure_candidate

Extracted instrument SNPs from exposure.

include_outliers

When performing MR of candidate traits against exposures or outcomes, whether to include the original outlier SNP. Default is FALSE.

use_proxies

Whether to use proxies when looking up associations. FALSE by default for speed.


Method candidate_outcome_dat()

Make a dataset for the candidate traits and the original outcome.

Usage
Tryx$candidate_outcome_dat(dat = self$output$dat)
Arguments
dat

Output from TwoSampleMR::harmonise_data.


Method candidate_exposure_dat()

Make a dataset for the candidate traits and the original exposure.

Usage
Tryx$candidate_exposure_dat(dat = self$output$dat)
Arguments
dat

Output from TwoSampleMR::harmonise_data.


Method exposure_candidate_dat()

Make a dataset for the original exposure and the candidate traits.

Usage
Tryx$exposure_candidate_dat(dat = self$output$dat)
Arguments
dat

Output from TwoSampleMR::harmonise_data.


Method harmonise()

Harmonised exposure - outcome dataset.

Usage
Tryx$harmonise(dat = self$output$dat)
Arguments
dat

Output from TwoSampleMR::harmonise_data.


Method mr()

Perform MR anlayses of 1) candidate traits-outcome 2) candidate traits-exposure 3) exposure-candidate traits.

Usage
Tryx$mr(dat = self$output$dat, mr_method = "mr_ivw")
Arguments
dat

Output from TwoSampleMR::harmonise_data.

mr_method

Method to use for candidate trait - exposure/outcome analysis. Default is mr_ivw. Can also provide basic MR methods e.g. mr_weighted_mode, mr_weighted_median etc. Also possible to use "strategy1" which performs IVW in the first instance, but then weighted mode for associations with high heterogeneity.


Method mrtryx()

All-in-one: 1) Detect outlier 2) Search candidate traits 3) Perform MR of candidate traits and the outcome / exposure.

Usage
Tryx$mrtryx(
  dat = self$output$dat,
  outliers = "RadialMR",
  outlier_correction = "none",
  outlier_threshold = ifelse(outlier_correction == "none", 0.05/nrow(dat), 0.05),
  use_proxies = FALSE,
  search_correction = "none",
  search_threshold = ifelse(search_correction == "none", 5e-08, 0.05),
  include_outliers = FALSE,
  mr_method = "mr_ivw"
)
Arguments
dat

Output from harmonise_data. Note - only the first id.exposure - id.outcome pair will be used.

outliers

Default is to use the RadialMR package to identify IVW outliers. Alternatively can providen an array of SNP names that are present in dat$SNP to use as outliers.

outlier_correction

Defualt = "none", but can select from ("holm", "hochberg", "hommel", "bonferroni", "BH", "BY", "fdr", "none").

outlier_threshold

If outlier_correction = "none" then the p-value threshold for detecting outliers is by default 0.05.

use_proxies

Whether to use proxies when looking up associations. FALSE by default for speed.

search_correction

Default = "none", but can select from ("holm", "hochberg", "hommel", "bonferroni", "BH", "BY", "fdr", "none").

search_threshold

If search_correction = "none" then the p-value threshold for detecting an association between an outlier and a candidate trait is by default 5e-8. Otherwise it is 0.05.

include_outliers

When performing MR of candidate traits against exposures or outcomes, whether to include the original outlier SNP. Default is FALSE.

mr_method

Method to use for candidate trait - exposure/outcome analysis. Default is mr_ivw. Can also provide basic MR methods e.g. mr_weighted_mode, mr_weighted_median etc. Also possible to use "strategy1" which performs IVW in the first instance, but then weighted mode for associations with high heterogeneity.


Method tryx.sig()

Identify putatively significant associations in the outlier scan.

Usage
Tryx$tryx.sig(mr_threshold_method = "fdr", mr_threshold = 0.05)
Arguments
mr_threshold_method

This is the argument to be passed to p.adjust. Default is "fdr". If no p-value adjustment is to be applied then specify "unadjusted".

mr_threshold

Threshold to declare significance


Method adjustment()

Outlier adjustment estimation - How much of the heterogeneity due to the outlier can be explained by alternative pathways?

Usage
Tryx$adjustment(tryxscan = self$output, id_remove = NULL)
Arguments
tryxscan

Output from x$mrtryx()

id_remove

List of IDs to exclude from the adjustment analysis. It is possible that in the outlier search a candidate trait will come up which is essentially just a surrogate for the outcome trait (e.g. if you are analysing coronary heart disease as the outcome then a variable related to heart disease medication might come up as a candidate trait). Adjusting for a trait which is essentially the same as the outcome will erroneously nullify the result, so visually inspect the candidate trait list and remove those that are inappropriate.

dat

Output from harmonise_data. Note - only the first id.exposure - id.outcome pair will be used.


Method adjustment.mv()

Similar to adjusment, but when there are multiple traits associated with a single variant.

Usage
Tryx$adjustment.mv(
  tryxscan = self$output,
  lasso = TRUE,
  id_remove = NULL,
  proxies = FALSE
)
Arguments
tryxscan

Output from x$scan()

lasso

Whether to shrink the estimates of each trait within SNP. Default=TRUE.

id_remove

List of IDs to exclude from the adjustment analysis. It is possible that in the outlier search a candidate trait will come up which is essentially just a surrogate for the outcome trait (e.g. if you are analysing coronary heart disease as the outcome then a variable related to heart disease medication might come up as a candidate trait). Adjusting for a trait which is essentially the same as the outcome will erroneously nullify the result, so visually inspect the candidate trait list and remove those that are inappropriate.

proxies

Look for proxies in the MVMR methods. Default = FALSE.

dat

Output from harmonise_data. Note - only the first id.exposure - id.outcome pair will be used.


Method analyse()

This returns various heterogeneity statistics, IVW estimates for raw, adjusted and outlier removed datasets, and summary of peripheral traits detected etc.

Usage
Tryx$analyse(
  tryxscan = self$output,
  plot = TRUE,
  id_remove = NULL,
  filter_duplicate_outliers = TRUE
)
Arguments
tryxscan

Output from x$scan().

plot

Whether to plot or not. Default is TRUE.

id_remove

List of IDs to exclude from the adjustment analysis. It is possible that in the outlier search a candidate trait will come up which is essentially just a surrogate for the outcome trait (e.g. if you are analysing coronary heart disease as the outcome then a variable related to heart disease medication might come up as a candidate trait). Adjusting for a trait which is essentially the same as the outcome will erroneously nullify the result, so visually inspect the candidate trait list and remove those that are inappropriate.

duplicate_outliers_method

Sometimes more than one trait will associate with a particular outlier. TRUE = only keep the trait that has the biggest influence on heterogeneity.


Method analyse.mv()

Similar to analyse, but when there are multiple traits associated with a single variant.

Usage
Tryx$analyse.mv(
  tryxscan = self$output,
  lasso = TRUE,
  plot = TRUE,
  id_remove = NULL,
  proxies = FALSE
)
Arguments
tryxscan

Output from x$scan()

lasso

Whether to shrink the estimates of each trait within SNP. Default=TRUE.

id_remove

List of IDs to exclude from the adjustment analysis. It is possible that in the outlier search a candidate trait will come up which is essentially just a surrogate for the outcome trait (e.g. if you are analysing coronary heart disease as the outcome then a variable related to heart disease medication might come up as a candidate trait). Adjusting for a trait which is essentially the same as the outcome will erroneously nullify the result, so visually inspect the candidate trait list and remove those that are inappropriate.

proxies

Look for proxies in the MVMR methods. Default = FALSE.


Method manhattan_plot()

Draw a Manhattan style plot for candidate traits-outcome/exposure associations.

Usage
Tryx$manhattan_plot(
  what = "outcome",
  id_remove = NULL,
  y_scale = NULL,
  label = TRUE
)
Arguments
what

Analyse candidate-exposure ('exposure') or candidate-outcome ('outcome') associations

id_remove

List of IDs to exclude from the adjustment analysis. It is possible that in the outlier search a candidate trait will come up which is essentially just a surrogate for the outcome trait (e.g. if you are analysing coronary heart disease as the outcome then a variable related to heart disease medication might come up as a candidate trait). Adjusting for a trait which is essentially the same as the outcome will erroneously nullify the result, so visually inspect the candidate trait list and remove those that are inappropriate.

y_scale

The scaling function to be applied to y scale.

label

Display the names of the traits on the graph.


Method clone()

The objects of this class are cloneable with this method.

Usage
Tryx$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.


Outlier adjustment estimation

Description

How much of the heterogeneity due to the outlier can be explained by alternative pathways?

Usage

tryx.adjustment(tryxscan, id_remove = NULL)

Arguments

tryxscan

Output from tryx.scan

id_remove

List of IDs to exclude from the adjustment analysis. It is possible that in the outlier search a candidate trait will come up which is essentially just a surrogate for the outcome trait (e.g. if you are analysing coronary heart disease as the outcome then a variable related to heart disease medication might come up as a candidate trait). Adjusting for a trait which is essentially the same as the outcome will erroneously nullify the result, so visually inspect the candidate trait list and remove those that are inappropriate.

Value

data frame of adjusted effect estimates and heterogeneity stats


Analyse tryx results

Description

This returns various heterogeneity statistics, IVW estimates for raw, adjusted and outlier removed datasets, and summary of peripheral traits detected etc.

Usage

tryx.analyse(
  tryxscan,
  plot = TRUE,
  id_remove = NULL,
  filter_duplicate_outliers = TRUE
)

Arguments

tryxscan

Output from tryx.scan

plot

Whether to plot or not. Default is TRUE

id_remove

List of IDs to exclude from the adjustment analysis. It is possible that in the outlier search a candidate trait will come up which is essentially just a surrogate for the outcome trait (e.g. if you are analysing coronary heart disease as the outcome then a variable related to heart disease medication might come up as a candidate trait). Adjusting for a trait which is essentially the same as the outcome will erroneously nullify the result, so visually inspect the candidate trait list and remove those that are inappropriate.

duplicate_outliers_method

Sometimes more than one trait will associate with a particular outlier. TRUE = only keep the trait that has the biggest influence on heterogeneity

Value

List of - adj_full: data frame of SNP adjustments for all candidate traits - adj: The results from adj_full selected to adjust the exposure-outcome model - Q: Heterogeneity stats - estimates: Adjusted and unadjested exposure-outcome effects - plot: Radial plot showing the comparison of different methods and the changes in SNP effects ater adjustment


Analyse tryx results

Description

This returns various heterogeneity statistics, IVW estimates for raw, adjusted and outlier removed datasets, and summary of peripheral traits detected etc.

Usage

tryx.analyse.mv(
  tryxscan,
  lasso = TRUE,
  plot = TRUE,
  id_remove = NULL,
  proxies = FALSE
)

Arguments

tryxscan

Output from tryx.scan

lasso

Whether to shrink the estimates of each trait within SNP. Default=TRUE.

plot

Whether to plot or not. Default is TRUE

id_remove

List of IDs to exclude from the adjustment analysis. It is possible that in the outlier search a candidate trait will come up which is essentially just a surrogate for the outcome trait (e.g. if you are analysing coronary heart disease as the outcome then a variable related to heart disease medication might come up as a candidate trait). Adjusting for a trait which is essentially the same as the outcome will erroneously nullify the result, so visually inspect the candidate trait list and remove those that are inappropriate.

proxies

Look for proxies in the MVMR methods. Default = FALSE.

filter_duplicate_outliers

Whether to only allow each putative outlier to be adjusted by a single trait (in order of largest divergence). Default is TRUE.

Value

List of - adj_full: data frame of SNP adjustments for all candidate traits - adj: The results from adj_full selected to adjust the exposure-outcome model - Q: Heterogeneity stats - estimates: Adjusted and unadjested exposure-outcome effects - plot: Radial plot showing the comparison of different methods and the changes in SNP effects ater adjustment Adjust and analyse the tryx results

Similar to tryx.analyse, but when there are multiple traits associated with a single variant then we use a LASSO-based multivariable approach

List of - adj_full: data frame of SNP adjustments for all candidate traits - adj: The results from adj_full selected to adjust the exposure-outcome model - Q: Heterogeneity stats - estimates: Adjusted and unadjested exposure-outcome effects - plot: Radial plot showing the comparison of different methods and the changes in SNP effects ater adjustment


Plot results from outlier_scan in a network

Description

Creates a simple network depicting the connections between outlier instruments, the original exposure and outcome traits, and the detected candidate associations

Usage

tryx.network(tryxscan)

Arguments

tryxscan

Output from outlier_scan function

Value

Prints plot, and returns dataframe of the connections


Outlier scan

Description

A simple wrapper function. Using a summary set, find outliers in the MR analysis between the pair of trais. Find other 'candidate traits' associated with those outliers. Perform MR of each of those candidate traits with the original exposure and outcome

Usage

tryx.scan(
  dat,
  outliers = "RadialMR",
  outlier_correction = "none",
  outlier_threshold = ifelse(outlier_correction == "none", 0.05/nrow(dat), 0.05),
  use_proxies = FALSE,
  search_correction = "none",
  search_threshold = ifelse(search_correction == "none", 5e-08, 0.05),
  id_list = "default",
  include_outliers = FALSE,
  mr_method = "mr_ivw"
)

Arguments

dat

Output from harmonise_data. Note - only the first id.exposure - id.outcome pair will be used.

outliers

Default is to use the RadialMR package to identify IVW outliers. Alternatively can providen an array of SNP names that are present in dat$SNP to use as outliers.

outlier_correction

Defualt = "none", but can select from ("holm", "hochberg", "hommel", "bonferroni", "BH", "BY", "fdr", "none").

outlier_threshold

If outlier_correction = "none" then the p-value threshold for detecting outliers is by default 0.05.

use_proxies

Whether to use proxies when looking up associations. FALSE by default for speed.

search_correction

Default = "none", but can select from ("holm", "hochberg", "hommel", "bonferroni", "BH", "BY", "fdr", "none").

search_threshold

If search_correction = "none" then the p-value threshold for detecting an association between an outlier and a candidate trait is by default 5e-8. Otherwise it is 0.05.

id_list

The list of trait IDs to search through for candidate associations. The default is the high priority traits in available_outcomes().

include_outliers

When performing MR of candidate traits against exposures or outcomes, whether to include the original outlier SNP. Default is FALSE.

mr_method

Method to use for candidate trait - exposure/outcome analysis. Default is mr_ivw. Can also provide basic MR methods e.g. mr_weighted_mode, mr_weighted_median etc. Also possible to use "strategy1" which performs IVW in the first instance, but then weighted mode for associations with high heterogeneity.

Value

List dat Cleaned dat input radialmr Results from RadialMR analysis outliers List of outliers used id_list List of GWAS IDs used search Result from search of outliers against GWAS IDs candidate_instruments Instruments for candidate traits candidate_outcome Extracted instrument SNPs from outcome candidate_outcome_dat Harmonised candidate - outcome dataset candidate_outcome_mr MR analysis of candidates against outcome candidate_exposure Extracted instrument SNPs from exposure candidate_exposure_dat Harmonised candidate - exposure dataset candidate_exposure_mr MR analysis of candidates against exposure


Identify putatively significant associations in the outlier scan

Description

Identify putatively significant associations in the outlier scan

Usage

tryx.sig(tryxscan, mr_threshold_method = "fdr", mr_threshold = 0.05)

Arguments

mr_threshold_method

This is the argument to be passed to p.adjust. Default is "fdr". If no p-value adjustment is to be applied then specify "unadjusted"

mr_threshold

Threshold to declare significance

Value

Same as outlier_scan but the candidate_exposure_mr and candidate_outcome_mr objects have an extra pval_adj and sig column each


Simulate data to test tryx

Description

# Create data using model here: https://www.draw.io/#G1VqjTd4iH2de7sXI4PhUrxazBnYLduH_w. Create summary data for all necessary traits, then perform tryx scan x = exposure y = outcome u1 = confounder of x and y u2 = mediator of horizontal pleiotropy from gx to y. One for each gx u3 = mediator between x and y

Usage

tryx.simulate(
  nid = 10000,
  ngx = 30,
  ngu1 = 30,
  ngu2 = 30,
  nu2 = 2,
  ngu3 = 30,
  vgx = 0.2,
  vgu1 = 0.6,
  vgu2 = 0.2,
  vgu3 = 0.2,
  bxy = 0,
  bu1x = 0.6,
  bu1y = 0.4,
  bxu3 = 0.3,
  bu3y = 0,
  vgxu2 = 0.2,
  vu2y = 0.2,
  ngxu3 = 0,
  vgxu3 = 0,
  mininum_instruments = 10,
  instrument_threshold = "bonferroni",
  outlier_threshold = "bonferroni",
  outliers_known = "detected",
  directional_bias = FALSE
)

Arguments

nid

= 10000 Number of samples

ngx

= 30 Number of direct instruments to x

ngu1

= 30 Number of instruments influencing confounder of x and y

ngu2

= 30 Number of instruments per mediating

nu2

= 2 Number of gx that are pleiotropic

ngu3

= 30 Number of instruments for u3 mediator

vgx

= 0.2 Variance explained by gx instruments

vgu1

= 0.6 Variance explained by u1 instruments

vgu2

= 0.2 Variance explained by u2 instruments

vgu3

= 0.2 Variance explained by u3 instruments

bxy

= 0 Causal effect of x on y

bu1x

= 0.6 Effect of u1 on x

bu1y

= 0.4 Effect of u1 on y

bxu3

= 0.3 Effect of x on u3

bu3y

= 0 Effect of u3 on y

vgxu2

= 0.2 Variance explained by each gx instrument on each u2 mediator

vu2y

= 0.2 Variance explained by all u2 mediators on y

ngxu3

= 0 Number of gx instruments that pleiotropically associate with u3 mediator

mininum_instruments

= 10 Minimum number of instruments required to have been detected to run simulation

instrument_threshold

= "bonferroni" Threshold, either numeric or 'bonferroni'

outlier_threshold

= "bonferroni" Threshold, either numeric or 'bonferroni'

outliers_known

= "detected" Either detected = using radial mr to find heterogeneity outliers; known = adjust for all known invalid instruments; all = adjust for all instruments

directional_bias

= FALSE Is the pleiotropic effect randomly centered around 0 (FALSE) or does it have a non-0 mean (TRUE)

vgxu3y

= 0 Variance explained by all gx variants directly on u3 mediator

Value

list for tryx.analyse


Plot volcano plot of many MR analyses

Description

Plot volcano plot of many MR analyses

Usage

volcano_plot(res, what = "exposure")

Arguments

res

Dataframe similar to output from mr() function, requiring id.exposure, id.outcome. Ideally only provide one MR estimate for each exposure-outcome hypothesis. Also provide a sig column of TRUE/FALSE to determine if that association is to be labelled

what

Whether to plot many exposures against few outcomes (default: exposure) or few exposures against many outcomes (outcome). If e.g. 'exposure' and there are multiple outcomes then will facet by outcome

Value

ggplot of volcano plots