diff --git a/.gitignore b/.gitignore
index 065f56108d9a9934746a7a4d890cdb3ff7ab55ef..eddaf3d24df4c6520b1ef99aa062c58441c54acb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@
 .Ruserdata
 
 Notizen.md
+*.png
diff --git a/.gitlab/merge_request_templates/merge_into_master.md b/.gitlab/merge_request_templates/merge_into_master.md
index 021f1edaab0642d0ad93098425c6951f99f151d8..670d525aab37918df1c66d7cd3c46122f9aa5e09 100644
--- a/.gitlab/merge_request_templates/merge_into_master.md
+++ b/.gitlab/merge_request_templates/merge_into_master.md
@@ -20,7 +20,7 @@ Comment on any notes that come up during devtools::check().
 <!-- Please check `[x]` the applicable boxes. -->
 * [ ] This merge includes bug fixes or changes in the functionality of the package (whether they are user-visible or not).
     * [ ]  update documentation including examples (if necessary)
-    * [ ]  update NEWS.md
+    * [ ]  update and polish NEWS.md
     * [ ]  update version in DESCRIPTION
     * [ ]  update date in DESCRIPTION
 * [ ]  This merge introduces new features.
@@ -35,5 +35,5 @@ If this merge introduces a new version (major, minor or patch) to the
 master branch do these steps after the branch has been successfully merged:
 - git tag
 - build binary and source package
-- gitlab release including the builds
+- gitlab release and upload the builds
 -->
diff --git a/DESCRIPTION b/DESCRIPTION
index ff3def4338af703ffda55cd527818ea844937aa5..86af1897ed88671bb33a486fb22337d35b85a230 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,8 +1,8 @@
 Package: stressaddition
 Type: Package
 Title: Modeling Tri-Phasic Concentration-Response Relationships
-Version: 2.0.0
-Date: 2020-02-17
+Version: 2.1.0
+Date: 2020-02-25
 Authors@R: person("Sebastian", "Henz", role = c("aut", "cre"), 
                   email = "sebastian.henz@ufz.de", 
                   comment = c(ORCID = "0000-0001-8299-8852"))
@@ -19,10 +19,7 @@ Depends:
     R (>= 3.5)
 Imports: 
     drc (>= 3.0),
-    plotrix,
-    stats,
-    graphics,
-    grDevices
+    plotrix
 Suggests: 
     testthat (>= 2.1.0)
 RoxygenNote: 7.0.2
diff --git a/NAMESPACE b/NAMESPACE
index 06741e7eab9a60266f9993496c37c8b444cd9238..58db063863ead9fe8cb2bc7ceebf64bc51392656 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -6,6 +6,7 @@ export(effect_to_stress)
 export(plot_effect)
 export(plot_stress)
 export(predict_ecxsys)
+export(predict_mixture)
 export(stress_to_effect)
 import(grDevices)
 import(graphics)
diff --git a/NEWS.md b/NEWS.md
index 76e2ec2ef128af6718962136f839c8ac760bcf9c..012fd68e8f66b0d08fb57dc73bc41c32a2487e0a 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,12 @@
+# stressaddition 2.1.0
+
+* The functions `plot_effect()` and `plot_stress()` gain a `which` argument that controls which curves are plotted. Consequently, the `show_LL5_model` argument of `plot_effect()` was removed.
+* Added arguments `xlab` and `ylab` to `plot_stress`.
+* Added argument `main` to both plot functions.
+* Changed some colors of the stress curves so they better match with the colors of related effect curves.
+* Added `predict_mixture()` for the prediction of the effects of mixtures of two toxicants.
+* Fixed documentation of `ecxsys()` and `predict_ecxsys()`.
+
 # stressaddition 2.0.0
 
 * Changed the order of arguments in `ecxsys()`.
diff --git a/R/ec.R b/R/ec.R
index de29753db77fea5338f70e4ccad1b632553a3008..66d25927c69b34c14f5e498baed86cd72e971461 100644
--- a/R/ec.R
+++ b/R/ec.R
@@ -25,9 +25,9 @@
 #' # below 90 % of the effect in the control.
 #'
 #' model <- ecxsys(
-#'     concentration = c(0, 0.03, 0.3, 3, 10),
-#'     effect_tox_observed = c(85, 76, 94, 35, 0),
-#'     hormesis_concentration = 0.3
+#'     concentration = c(0, 0.05, 0.5, 5, 30),
+#'     hormesis_concentration = 0.5,
+#'     effect_tox_observed = c(90, 81, 92, 28, 0)
 #' )
 #'
 #' # using the ecxsys() output or the curves therein directly:
diff --git a/R/ecxsys.R b/R/ecxsys.R
index 591912098baf039efdcc9aab4b868e7ff707c784..95e090d4362f864d1a4b15a6a50c08bf55e87f1f 100644
--- a/R/ecxsys.R
+++ b/R/ecxsys.R
@@ -8,8 +8,8 @@
 
 #' ECx-SyS
 #'
-#' The ECx-SyS model for modeling concentration-effect relationships which
-#' indicate signs of hormesis.
+#' The ECx-SyS model for modeling concentration-effect relationships whith
+#' hormesis.
 #'
 #' It is advised to complete the curve down to zero for optimal prediction.
 #' Therefore \code{effect_tox_observed} in the highest concentration should be
@@ -20,9 +20,8 @@
 #' \code{effect_tox_env_observed} (if provided) must be of equal length and
 #' sorted by increasing concentration.
 #'
-#' @param concentration A vector of concentrations, one of which must be 0 to
-#'   indicate the control. Should be sorted in ascending order, otherwise it
-#'   will be sorted automatically.
+#' @param concentration A vector of concentrations. Must be sorted in ascending
+#'   order and the first element must be 0 to indicate the control.
 #' @param hormesis_concentration The concentration where the hormesis occurs.
 #'   This is usually the concentration of the highest effect after the control.
 #' @param effect_tox_observed A vector of effect values observed at the given
@@ -34,28 +33,53 @@
 #'   survival data in percent this should be 100 (the default).
 #' @param p,q The shape parameters of the beta distribution. Default is 3.2.
 #'
-#' @return A list (of class ecxsys) containing many different objects with the
-#'   most important being \code{curves}, a data frame containing effect and
-#'   stress values at different concentrations. See \code{\link{predict_ecxsys}}
-#'   for details.
+#' @return A list (of class ecxsys) containing many different objects of which
+#'   the most important are listed below. The effect and stress vectors
+#'   correspond to the provided concentrations.
+#'   \describe{
+#'     \item{effect_tox}{Modeled effect resulting from toxicant stress.}
+#'     \item{effect_tox_sys}{Modeled effect resulting from toxicant and system
+#'     stress.}
+#'     \item{effect_tox_env}{Modeled effect resulting from toxicant and
+#'     environmental stress.}
+#'     \item{effect_tox_env_sys}{Modeled effect resulting from toxicant,
+#'     environmental and system stress.}
+#'     \item{effect_tox_LL5}{The effect predicted by the five-parameter
+#'     log-logistic model derived from the observations under toxicant stress
+#'     but without environmental stress.}
+#'     \item{effect_tox_env_LL5}{The effect predicted by the five-parameter
+#'     log-logistic model derived from the observations under toxicant stress
+#'     with environmental stress.}
+#'     \item{curves}{A data frame containing effect and stress values as
+#'     returned by \code{\link{predict_ecxsys}}. The concentrations are
+#'     regularly spaced on a logarithmic scale in the given concentration range.
+#'     The control is approximated by the lowest non-control concentration times
+#'     1e-7. The additional column \code{use_for_plotting} is used by the
+#'     plotting functions of this package to approximate the control and
+#'     generate a break in the concentration axis.}
+#'   }
 #'
 #' @examples model <- ecxsys(
-#'     concentration = c(0, 0.03, 0.3, 3, 10),
-#'     hormesis_concentration = 0.3,
-#'     effect_tox_observed = c(85, 76, 94, 35, 0),
-#'     effect_tox_env_observed = c(24, 23, 32, 0, 0)
+#'     concentration = c(0, 0.05, 0.5, 5, 30),
+#'     hormesis_concentration = 0.5,
+#'     effect_tox_observed = c(90, 81, 92, 28, 0),
+#'     effect_tox_env_observed = c(29, 27, 33, 5, 0)
 #' )
 #'
-#' # Use effect_max if for example the effect is given as the number of
-#' # surviving animals and the initial number of animals is 20:
+#' # Use effect_max if for example the effect is given as the average number of
+#' # surviving animals and the initial number of animals is 21:
 #' model <- ecxsys(
-#'     concentration = c(0, 0.03, 0.3, 3, 10),
+#'     concentration = c(0, 0.03, 0.3, 3, 30),
 #'     hormesis_concentration = 0.3,
 #'     effect_tox_observed = c(17, 15.2, 18.8, 7, 0),
 #'     effect_tox_env_observed = c(4.8, 4.6, 6.4, 0, 0),
-#'     effect_max = 20
+#'     effect_max = 21
 #' )
 #'
+#' @references \href{https://doi.org/10.1038/s41598-019-51645-4}{Liess, M.,
+#'   Henz, S. & Knillmann, S. Predicting low-concentration effects of
+#'   pesticides. Sci Rep 9, 15248 (2019).}
+#'
 #' @export
 ecxsys <- function(concentration,
                    hormesis_concentration,
@@ -111,8 +135,7 @@ ecxsys <- function(concentration,
     if (any(is.na(c(all_observations, concentration)))) {
         stop("Values containing NA are not supported.")
     }
-    if (any(all_observations > effect_max) ||
-        any(all_observations < 0)) {
+    if (any(all_observations > effect_max) || any(all_observations < 0)) {
         stop("Observed effect must be between 0 and effect_max.")
     }
     conc_shift <- 2  # Powers of ten to shift the control downwards from the
diff --git a/R/helpers.R b/R/helpers.R
index f13f0d09f1c7da52f091e498dda5960e0bb3ea95..1b9fea35ab1ac236d2b0d9d296a7d483263247dd 100644
--- a/R/helpers.R
+++ b/R/helpers.R
@@ -33,12 +33,12 @@ get_log_ticks <- function(x) {
 }
 
 
-adjust_smooth_concentrations <- function(curves, conc_adjust_factor) {
+adjust_smooth_concentrations <- function(model) {
     # Helper for the plot functions, not exported.
     # Deals with the concentrations which are unnecessary for plotting.
     # This means it removes the concentrations in the gap and scales the
     # concentrations left of the gap up.
-
+    curves <- model$curves
     gap_idx <- min(which(!curves$use_for_plotting))
 
     # Keep only the values to the left and right of the axis break:
@@ -50,7 +50,7 @@ adjust_smooth_concentrations <- function(curves, conc_adjust_factor) {
 
     # Shift the small concentrations upwards so the plot has a nice x-axis:
     curves$concentration[1:gap_idx] <-
-        curves$concentration[1:gap_idx] / conc_adjust_factor
+        curves$concentration[1:gap_idx] / model$conc_adjust_factor
 
     list(
         curves = curves,
diff --git a/R/plot_ecxsys.R b/R/plot_ecxsys.R
index 0ea5e493068b8d9d98eb359c181b357f546ef6ea..18a31e67edf2e11215e40f180023411f7498de84 100644
--- a/R/plot_ecxsys.R
+++ b/R/plot_ecxsys.R
@@ -3,24 +3,34 @@
 
 #' Plot the results of the ECx-SyS model
 #'
-#' Convenience functions to plot the observed and modeled effect and the
-#' system stress with and without environmental stress.
+#' Plot the observed and modeled effects and stresses.
 #'
 #' @name plot_ecxsys
 #'
 #' @param model The list returned from \code{\link{ecxsys}}.
-#' @param show_LL5_model Should the log-logistic models be plotted for
-#'   comparison? Defaults to \code{FALSE}.
-#' @param show_legend Should the plot include a legend? Defaults to FALSE
-#'   because it may cover some points or lines depending on the plot size.
-#' @param xlab,ylab Axis labels.
+#' @param which A vector of curve names to plot. Allowed values are the column
+#'   names of the \code{model$curves} data frame. The default \code{NULL} only
+#'   plots the most important curves. Use \code{which = "all"} to display all
+#'   curves.
+#' @param show_legend Should the plot include a legend? Defaults to \code{FALSE}
+#'   because it may cover some parts of the plot depending on the plot size and
+#'   the number of elements shown.
+#' @param xlab,ylab,main Axis labels and title.
 #'
 #' @examples model <- ecxsys(
-#'     concentration = c(0, 0.03, 0.3, 3, 10),
-#'     hormesis_concentration = 0.3,
-#'     effect_tox_observed = c(85, 76, 94, 35, 0),
-#'     effect_tox_env_observed = c(24, 23, 32, 0, 0)
+#'     concentration = c(0, 0.05, 0.5, 5, 30),
+#'     hormesis_concentration = 0.5,
+#'     effect_tox_observed = c(90, 81, 92, 28, 0),
+#'     effect_tox_env_observed = c(29, 27, 33, 5, 0)
 #' )
 #' plot_effect(model)
 #' plot_stress(model)
+#'
+#' # Plot all curves:
+#' plot_effect(model, which = "all")
+#' plot_stress(model, which = "all")
+#'
+#' # Plot only some selected curves:
+#' plot_effect(model, which = c("effect_tox", "effect_tox_env"))
+#' plot_stress(model, which = c("stress_tox", "stress_tox_env"))
 NULL
diff --git a/R/plot_effect.R b/R/plot_effect.R
index 6b944e3a46ab9ea9c3eccb9ba87317c5c3fac931..7fa995dd952e3042e9e0a95f07dde5bdaf64f19c 100644
--- a/R/plot_effect.R
+++ b/R/plot_effect.R
@@ -1,19 +1,49 @@
 #' @rdname plot_ecxsys
 #' @export
 plot_effect <- function(model,
-                        show_LL5_model = FALSE,
+                        which = NULL,
                         show_legend = FALSE,
                         xlab = "concentration",
-                        ylab = "effect") {
+                        ylab = "effect",
+                        main = NULL) {
     stopifnot(inherits(model, "ecxsys"))
-    temp <- adjust_smooth_concentrations(
-        model$curves,
-        model$conc_adjust_factor
-    )
+
+    curve_names <- names(model$curves)
+    valid_names <- curve_names[startsWith(curve_names, "effect")]
+    if (is.null(which)) {
+        which <- c("effect_tox_sys")
+        if (model$with_env) {
+            which <- c(which, "effect_tox_env_sys")
+        }
+    } else if ("all" %in% which) {
+        if (length(which) == 1) {
+            which <- valid_names
+        } else {
+            stop("'all' must not be combined with other curve names.")
+        }
+    } else if (!all(which %in% valid_names)) {
+        warning("Argument 'which' contains invalid names.")
+        if (!model$with_env && any(grepl("env", which, fixed = TRUE))) {
+            warning("'which' contains names with 'env' but the model was",
+                    " built without environmental effects.")
+        }
+        which <- which[which %in% valid_names]
+    }
+
+    temp <- adjust_smooth_concentrations(model)
     curves <- temp$curves
     log_ticks <- get_log_ticks(curves$concentration)
     concentration <- c(curves$concentration[1], model$args$concentration[-1])
 
+    legend_df <- data.frame(
+        text = character(),
+        pch = numeric(),
+        lty = numeric(),
+        col = character(),
+        order = numeric(),  # controls sorting of legend elements
+        stringsAsFactors = FALSE
+    )
+
     plot(
         NA,
         NA,
@@ -22,93 +52,103 @@ plot_effect <- function(model,
         log = "x",
         xlab = xlab,
         ylab = ylab,
+        main = main,
         xaxt = "n",
-        bty = "L",
-        las = 1
+        yaxt = "n",
+        bty = "L"
     )
 
-    lines(
-        curves$concentration,
-        curves$effect_tox_sys,
-        col = "blue"
-    )
-    lines(
-        curves$concentration,
-        curves$effect_tox,
-        col = "deepskyblue",
-        lty = 2
-    )
     points(
         concentration,
         model$args$effect_tox_observed,
         pch = 16,
         col = "blue"
     )
-
+    legend_df[nrow(legend_df) + 1, ] <- list("tox (observed)", 16, 0, "blue", 1)
     if (model$with_env) {
+        points(
+            concentration,
+            model$args$effect_tox_env_observed,
+            pch = 16,
+            col = "red"
+        )
+        legend_df[nrow(legend_df) + 1, ] <- list("tox + env (observed)", 16, 0, "red", 2)
+    }
+    # The lines are drawn in this order to ensure that dotted and dashed lines
+    # are on top of solid lines for better visibility.
+    if ("effect_tox_sys" %in% which) {
         lines(
             curves$concentration,
-            curves$effect_tox_env_sys,
-            col = "red"
+            curves$effect_tox_sys,
+            col = "blue"
         )
+        legend_df[nrow(legend_df) + 1, ] <- list("tox + sys", NA, 1, "blue", 5)
+    }
+    if ("effect_tox" %in% which) {
         lines(
             curves$concentration,
-            curves$effect_tox_env,
-            col = "orange",
+            curves$effect_tox,
+            col = "deepskyblue",
             lty = 2
         )
-        points(
-            concentration,
-            model$args$effect_tox_env_observed,
-            pch = 16,
-            col = "red"
-        )
+        legend_df[nrow(legend_df) + 1, ] <- list("tox", NA, 2, "deepskyblue", 4)
     }
-
-    if (show_LL5_model) {
+    if ("effect_tox_LL5" %in% which) {
         lines(
             curves$concentration,
             curves$effect_tox_LL5,
             col = "darkblue",
-            lty = 4
+            lty = 3
         )
-        if (model$with_env) {
+        legend_df[nrow(legend_df) + 1, ] <- list("tox (LL5)", NA, 3, "darkblue", 3)
+    }
+    if (model$with_env) {
+        if ("effect_tox_env_sys" %in% which) {
+            lines(
+                curves$concentration,
+                curves$effect_tox_env_sys,
+                col = "red"
+            )
+            legend_df[nrow(legend_df) + 1, ] <- list("tox + env + sys", NA, 1, "red", 8)
+        }
+        if ("effect_tox_env" %in% which) {
+            lines(
+                curves$concentration,
+                curves$effect_tox_env,
+                col = "orange",
+                lty = 2
+            )
+            legend_df[nrow(legend_df) + 1, ] <- list("tox + env", NA, 2, "orange", 7)
+        }
+        if ("effect_tox_env_LL5" %in% which) {
             lines(
                 curves$concentration,
                 curves$effect_tox_env_LL5,
                 col = "darkred",
-                lty = 4
+                lty = 3
             )
+            legend_df[nrow(legend_df) + 1, ] <- list("tox + env (LL5)", NA, 3, "darkred", 6)
         }
     }
 
-    axis(1, at = log_ticks$major, labels = log_ticks$major_labels)
-    axis(1, at = log_ticks$minor, labels = FALSE, tcl = -0.25)
+    # The setting of col = NA and col.ticks = par("fg") is to prevent ugly line
+    # thickness issues when plotting as a png with type = "cairo" and at a low
+    # resolution.
+    axis(1, at = log_ticks$major, labels = log_ticks$major_labels,
+         col = NA, col.ticks = par("fg"))
+    axis(1, at = log_ticks$minor, labels = FALSE, tcl = -0.25,
+         col = NA, col.ticks = par("fg"))
     plotrix::axis.break(1, breakpos = temp$axis_break_conc)
+    axis(2, col = NA, col.ticks = par("fg"), las = 1)
 
     if (show_legend) {
-        legend_text <- c("tox", "tox + sys")
-        legend_pch <- c(NA, 16)
-        legend_lty <- c(2, 1)
-        legend_col <- c("deepskyblue", "blue")
-        if (model$with_env) {
-            legend_text <- c(legend_text, "tox + env", "tox + env + sys")
-            legend_pch <- c(legend_pch, NA, 16)
-            legend_lty <- c(legend_lty, 2, 1)
-            legend_col <- c(legend_col, "orange", "red")
-        }
-        if (show_LL5_model) {
-            legend_text <- c(legend_text, "tox (LL5)", "tox + env (LL5)")
-            legend_pch <- c(legend_pch, NA, NA)
-            legend_lty <- c(legend_lty, 4, 4)
-            legend_col <- c(legend_col, "darkblue", "darkred")
-        }
+        legend_df <- legend_df[order(legend_df$order), ]
         legend(
             "topright",
-            legend = legend_text,
-            pch = legend_pch,
-            lty = legend_lty,
-            col = legend_col
+            legend = legend_df$text,
+            pch = legend_df$pch,
+            lty = legend_df$lty,
+            col = legend_df$col
         )
     }
 }
diff --git a/R/plot_stress.R b/R/plot_stress.R
index cccdcbcb0e7176262087fa331d74806514e90c63..7fc70f8f5e4970c0620c7ea15b87ab9a4be61fd3 100644
--- a/R/plot_stress.R
+++ b/R/plot_stress.R
@@ -1,72 +1,162 @@
 #' @rdname plot_ecxsys
 #' @export
-plot_stress <- function(model, show_legend = FALSE) {
+plot_stress <- function(model,
+                        which = NULL,
+                        show_legend = FALSE,
+                        xlab = "concentration",
+                        ylab = "stress",
+                        main = NULL) {
     stopifnot(inherits(model, "ecxsys"))
-    temp <- adjust_smooth_concentrations(
-        model$curves,
-        model$conc_adjust_factor
-    )
+
+    curve_names <- names(model$curves)
+    valid_names <- curve_names[
+        startsWith(curve_names, "stress") | startsWith(curve_names, "sys")
+    ]
+    if (is.null(which)) {
+        which <- c("sys_tox")
+        if (model$with_env) {
+            which <- c(which, "sys_tox_env")
+        }
+    } else if ("all" %in% which) {
+        if (length(which) == 1) {
+            which <- valid_names
+        } else {
+            stop("'all' must not be combined with other curve names.")
+        }
+    } else if (!all(which %in% valid_names)) {
+        warning("Argument 'which' contains invalid names.")
+        if (!model$with_env && any(grepl("env", which, fixed = TRUE))) {
+            warning("'which' contains names with 'env' but the model was",
+                    " built without environmental effects.")
+        }
+        which <- which[which %in% valid_names]
+        if (length(which) == 0) {
+            stop("No curves to display.")
+        }
+    }
+
+    temp <- adjust_smooth_concentrations(model)
     curves <- temp$curves
-    axis_break_conc <- temp$axis_break_conc
     log_ticks <- get_log_ticks(curves$concentration)
     concentration <- c(curves$concentration[1], model$args$concentration[-1])
 
+    legend_df <- data.frame(
+        text = character(),
+        pch = numeric(),
+        lty = numeric(),
+        col = character(),
+        order = numeric(),  # controls sorting of legend elements
+        stringsAsFactors = FALSE
+    )
+
     plot(
         NA,
         NA,
         xlim = range(curves$concentration, na.rm = TRUE),
-        ylim = c(0, 1),
+        ylim = c(0, max(curves[, which], 1, na.rm = TRUE)),
         log = "x",
-        xlab = "concentration",
-        ylab = "system stress",
+        xlab = xlab,
+        ylab = ylab,
+        main = main,
         xaxt = "n",
-        las = 1,
+        yaxt = "n",
         bty = "L"
     )
 
-    lines(
-        curves$concentration,
-        curves$sys_tox,
-        col = "blue"
-    )
-    points(
-        concentration,
-        model$sys_tox_not_fitted,
-        pch = 16,
-        col = "blue"
-    )
-
-    if (model$with_env) {
+    # The lines are drawn in this order to ensure that dotted and dashed lines
+    # are on top of solid lines for better visibility.
+    if ("stress_tox_sys" %in% which) {
+        lines(
+            curves$concentration,
+            curves$stress_tox_sys,
+            col = "blue"
+        )
+        legend_df[nrow(legend_df) + 1, ] <- list("tox + sys", NA, 1, "blue", 3)
+    }
+    if ("stress_tox" %in% which) {
         lines(
             curves$concentration,
-            curves$sys_tox_env,
-            col = "red"
+            curves$stress_tox,
+            col = "deepskyblue",
+            lty = 2
         )
+        legend_df[nrow(legend_df) + 1, ] <- list("tox", NA, 2, "deepskyblue", 1)
+    }
+    if ("sys_tox" %in% which) {
         points(
             concentration,
-            model$sys_tox_env_not_fitted,
+            model$sys_tox_not_fitted,
             pch = 16,
-            col = "red"
+            col = "steelblue3"
         )
+        lines(
+            curves$concentration,
+            curves$sys_tox,
+            col = "steelblue3"
+        )
+        legend_df[nrow(legend_df) + 1, ] <- list("sys (tox)", 16, 1, "steelblue3", 2)
+    }
+    if (model$with_env) {
+        if ("stress_tox_env_sys" %in% which) {
+            lines(
+                curves$concentration,
+                curves$stress_tox_env_sys,
+                col = "red"
+            )
+            legend_df[nrow(legend_df) + 1, ] <- list("tox + env + sys", NA, 1, "red", 7)
+        }
+        if ("stress_env" %in% which) {
+            lines(
+                curves$concentration,
+                curves$stress_env,
+                col = "forestgreen",
+                lty = 3
+            )
+            legend_df[nrow(legend_df) + 1, ] <- list("env", NA, 3, "forestgreen", 4)
+        }
+        if ("stress_tox_env" %in% which) {
+            lines(
+                curves$concentration,
+                curves$stress_tox_env,
+                col = "orange",
+                lty = 2
+            )
+            legend_df[nrow(legend_df) + 1, ] <- list("tox + env", NA, 2, "orange", 5)
+        }
+        if ("sys_tox_env" %in% which) {
+            points(
+                concentration,
+                model$sys_tox_env_not_fitted,
+                pch = 16,
+                col = "violetred"
+            )
+            lines(
+                curves$concentration,
+                curves$sys_tox_env,
+                col = "violetred"
+            )
+            legend_df[nrow(legend_df) + 1, ] <- list("sys (tox + env)", 16, 1, "violetred", 6)
+        }
     }
 
-    axis(1, at = log_ticks$major, labels = log_ticks$major_labels)
-    axis(1, at = log_ticks$minor, labels = FALSE, tcl = -0.25)
-    plotrix::axis.break(1, breakpos = axis_break_conc)
+    # The setting of col = NA and col.ticks = par("fg") is to prevent ugly line
+    # thickness issues when plotting as a png with type = "cairo" and at a low
+    # resolution.
+    axis(1, at = log_ticks$major, labels = log_ticks$major_labels,
+         col = NA, col.ticks = par("fg"))
+    axis(1, at = log_ticks$minor, labels = FALSE, tcl = -0.25,
+         col = NA, col.ticks = par("fg"))
+    plotrix::axis.break(1, breakpos = temp$axis_break_conc)
+    axis(2, col = NA, col.ticks = par("fg"), las = 1)
 
     if (show_legend) {
-        legend_text <- c("tox")
-        legend_col <- c("blue")
-        if (model$with_env) {
-            legend_text <- c(legend_text, "tox + env")
-            legend_col <- c(legend_col, "red")
-        }
+        legend_df <- legend_df[order(legend_df$order), ]
         legend(
             "topright",
-            legend = legend_text,
-            col = legend_col,
-            pch = 16,
-            lty = 1
+            legend = legend_df$text,
+            pch = legend_df$pch,
+            lty = legend_df$lty,
+            col = legend_df$col
         )
     }
 }
diff --git a/R/predict_ecxsys.R b/R/predict_ecxsys.R
index 604dce43729b25ca640cd239027df06e92c6167b..7d3d82a5a48eac83aff288cc68771a56ba007272 100644
--- a/R/predict_ecxsys.R
+++ b/R/predict_ecxsys.R
@@ -1,19 +1,19 @@
-#' Predict ECxSyS at various concentrations
+#' Predict effects and stresses
 #'
-#' @param model The output of a call to \code{\link{ecxsys}}.
+#' Calculate the effects and stresses of an ECx-SyS model at arbitrary
+#' concentrations.
+#'
+#' @param model An ECx-SyS model as returned by \code{\link{ecxsys}}.
 #' @param concentration A numeric vector of concentrations.
 #'
 #' @return A data frame (of class "ecxsys_predicted") with the following
 #'   columns:
 #'   \describe{
-#'     \item{concentration}{Concentrations regularly spaced on a logarithmic
-#'     scale in the given concentration range. The control is approximated by
-#'     the lowest non-control concentration times 1e-7.}
-#'     \item{effect_tox_LL5}{The five-parameter log-logistic model of the
-#'     effect derived from the observations under toxicant stress but without
-#'     environmental stress.}
-#'     \item{effect_tox}{Modeled effect resulting from toxicant and system
-#'     stress.}
+#'     \item{concentration}{The supplied concentrations.}
+#'     \item{effect_tox_LL5}{The effect predicted by the five-parameter
+#'     log-logistic model derived from the observations under toxicant stress
+#'     but without environmental stress.}
+#'     \item{effect_tox}{Modeled effect resulting from toxicant stress.}
 #'     \item{effect_tox_sys}{Modeled effect resulting from toxicant and system
 #'     stress.}
 #'     \item{stress_tox}{The toxicant stress.}
@@ -21,9 +21,9 @@
 #'     without environmental stress.}
 #'     \item{stress_tox_sys}{The sum of \code{stress_tox} and
 #'     \code{sys_tox}.}
-#'     \item{effect_tox_env_LL5}{The five-parameter log-logistic model of the
-#'     effect derived from the observations under toxicant stress with
-#'     environmental stress.}
+#'     \item{effect_tox_env_LL5}{The effect predicted by the five-parameter
+#'     log-logistic model derived from the observations under toxicant stress
+#'     with environmental stress.}
 #'     \item{effect_tox_env}{Modeled effect resulting from toxicant and
 #'     environmental stress.}
 #'     \item{effect_tox_env_sys}{Modeled effect resulting from toxicant,
@@ -37,9 +37,10 @@
 #'   }
 #'
 #' @examples model <- ecxsys(
-#'     concentration = c(0, 0.03, 0.3, 3, 10),
-#'     hormesis_concentration = 0.3,
-#'     effect_tox_observed = c(85, 76, 94, 35, 0)
+#'     concentration = c(0, 0.05, 0.5, 5, 30),
+#'     hormesis_concentration = 0.5,
+#'     effect_tox_observed = c(90, 81, 92, 28, 0),
+#'     effect_tox_env_observed = c(29, 27, 33, 5, 0)
 #' )
 #' p <- predict_ecxsys(model, c(0.001, 0.01, 0.1, 1, 10))
 #'
diff --git a/R/predict_mixture.R b/R/predict_mixture.R
new file mode 100644
index 0000000000000000000000000000000000000000..253503e9f7cbfa3f036508471a34493fd557e5c5
--- /dev/null
+++ b/R/predict_mixture.R
@@ -0,0 +1,98 @@
+#' Predict the effect of a mixture of two toxicants
+#'
+#' This method is only suitable for experiments without environmental stress.
+#' Any environmental stress in \code{model_1} or \code{model_2} is ignored.
+#'
+#' @param model_1 The ecxsys model of the toxicant that varies in concentration.
+#' @param model_2 The ecxsys model of the toxicant with a fixed concentration.
+#' @param concentration_1 The concentration of toxicant 1 in the mixture.
+#' @param concentration_2 The concentration of toxicant 2 in the mixture.
+#' @param proportion_ca How much of the combined toxicant stress is determined
+#'   by concentration addition. Must be between 0 and 1.
+#'
+#' @return A vector of the effects of the mixture, scaled to the effect_max
+#'   value of model_1.
+#'
+#' @examples toxicant_model_1 <- ecxsys(
+#'     concentration = c(0, 0.05, 0.5, 5, 30),
+#'     hormesis_concentration = 0.5,
+#'     effect_tox_observed = c(90, 81, 92, 28, 0),
+#' )
+#' toxicant_model_2 <- ecxsys(
+#'     concentration = c(0, 0.1, 1, 10, 100, 1000),
+#'     hormesis_concentration = 10,
+#'     effect_tox_observed = c(26, 25, 24, 27, 5, 0),
+#'     effect_max = 30
+#' )
+#' predict_mixture(
+#'     toxicant_model_1,
+#'     toxicant_model_2,
+#'     c(0, 0.02, 0.2, 2, 20),
+#'     3
+#' )
+#' @export
+predict_mixture <- function(model_1,
+                            model_2,
+                            concentration_1,
+                            concentration_2,
+                            proportion_ca = 0.5) {
+    stopifnot(
+        inherits(model_1, "ecxsys"),
+        inherits(model_2, "ecxsys"),
+        is.numeric(concentration_1),
+        is.numeric(concentration_2),
+        length(concentration_2) == 1,
+        !is.na(concentration_2),
+        proportion_ca >= 0,
+        proportion_ca <= 1
+    )
+
+    predicted_model_1 <- predict_ecxsys(model_1, concentration_1)
+    predicted_model_2 <- predict_ecxsys(model_2, concentration_2)
+
+    # tox stress ----------------------------------------------------------
+    stress_tox_sam <- predicted_model_1$stress_tox + predicted_model_2$stress_tox
+
+    # Convert the model_2 concentration into an equivalent model_1 concentration
+    # anc vice versa. Clamp the response levels because drc::ED can't deal with
+    # 0 and 100.
+    response_level_2 <- 100 - predicted_model_2$effect_tox / model_2$args$effect_max * 100
+    response_level_2 <- clamp(response_level_2, 1e-10, 100 - 1e-10)
+    concentration_2_equivalent <- drc::ED(
+        model_1$effect_tox_mod,
+        response_level_2,
+        display = FALSE
+    )[, "Estimate"]
+    effect_tox_ca_1 <- predict(
+        model_1$effect_tox_mod,
+        data.frame(concentration = concentration_1 + concentration_2_equivalent)
+    )
+
+    response_level_1 <- 100 - predicted_model_1$effect_tox / model_1$args$effect_max * 100
+    response_level_1 <- clamp(response_level_1, 1e-10, 100 - 1e-10)
+    concentration_1_equivalent <- drc::ED(
+        model_2$effect_tox_mod,
+        response_level_1,
+        display = FALSE
+    )[, "Estimate"]
+    effect_tox_ca_2 <- predict(
+        model_2$effect_tox_mod,
+        data.frame(concentration = concentration_2 + concentration_1_equivalent)
+    )
+
+    stress_tox_ca <- effect_to_stress(effect_tox_ca_1 * 0.5 + effect_tox_ca_2 * 0.5)
+
+    # sys -----------------------------------------------------------------
+    sys_1 <- predict(model_1$sys_tox_mod, data.frame(stress_tox = stress_tox_ca))
+    sys_2 <- predict(model_2$sys_tox_mod, data.frame(stress_tox = stress_tox_ca))
+    sys_total <- sys_1 * 0.5 + sys_2 * 0.5
+
+    # combined stress and result ------------------------------------------
+    proportion_sam <- 1 - proportion_ca
+    stress_tox_total <- stress_tox_ca * proportion_ca + stress_tox_sam * proportion_sam
+    stress_total <- stress_tox_total + sys_total
+    effect_total <- stress_to_effect(stress_total) * model_1$args$effect_max
+
+    # unname() to remove the name when concentration_1 is a single number.
+    unname(effect_total)
+}
diff --git a/man/ec.Rd b/man/ec.Rd
index 1a9c8289114d58707f4386f1edbbaddeb3da18a0..dea65818c30d40ae7981cfa4cc8ba61084de4267 100644
--- a/man/ec.Rd
+++ b/man/ec.Rd
@@ -38,9 +38,9 @@ smallest concentration is returned.
 # below 90 \% of the effect in the control.
 
 model <- ecxsys(
-    concentration = c(0, 0.03, 0.3, 3, 10),
-    effect_tox_observed = c(85, 76, 94, 35, 0),
-    hormesis_concentration = 0.3
+    concentration = c(0, 0.05, 0.5, 5, 30),
+    hormesis_concentration = 0.5,
+    effect_tox_observed = c(90, 81, 92, 28, 0)
 )
 
 # using the ecxsys() output or the curves therein directly:
diff --git a/man/ecxsys.Rd b/man/ecxsys.Rd
index ca2cabc4ec802efb1ca64fa7e8d25a6530c0d351..620adb3536863dfb892d7411497aa117e38ae0fa 100644
--- a/man/ecxsys.Rd
+++ b/man/ecxsys.Rd
@@ -15,9 +15,8 @@ ecxsys(
 )
 }
 \arguments{
-\item{concentration}{A vector of concentrations, one of which must be 0 to
-indicate the control. Should be sorted in ascending order, otherwise it
-will be sorted automatically.}
+\item{concentration}{A vector of concentrations. Must be sorted in ascending
+order and the first element must be 0 to indicate the control.}
 
 \item{hormesis_concentration}{The concentration where the hormesis occurs.
 This is usually the concentration of the highest effect after the control.}
@@ -35,14 +34,35 @@ survival data in percent this should be 100 (the default).}
 \item{p, q}{The shape parameters of the beta distribution. Default is 3.2.}
 }
 \value{
-A list (of class ecxsys) containing many different objects with the
-  most important being \code{curves}, a data frame containing effect and
-  stress values at different concentrations. See \code{\link{predict_ecxsys}}
-  for details.
+A list (of class ecxsys) containing many different objects of which
+  the most important are listed below. The effect and stress vectors
+  correspond to the provided concentrations.
+  \describe{
+    \item{effect_tox}{Modeled effect resulting from toxicant stress.}
+    \item{effect_tox_sys}{Modeled effect resulting from toxicant and system
+    stress.}
+    \item{effect_tox_env}{Modeled effect resulting from toxicant and
+    environmental stress.}
+    \item{effect_tox_env_sys}{Modeled effect resulting from toxicant,
+    environmental and system stress.}
+    \item{effect_tox_LL5}{The effect predicted by the five-parameter
+    log-logistic model derived from the observations under toxicant stress
+    but without environmental stress.}
+    \item{effect_tox_env_LL5}{The effect predicted by the five-parameter
+    log-logistic model derived from the observations under toxicant stress
+    with environmental stress.}
+    \item{curves}{A data frame containing effect and stress values as
+    returned by \code{\link{predict_ecxsys}}. The concentrations are
+    regularly spaced on a logarithmic scale in the given concentration range.
+    The control is approximated by the lowest non-control concentration times
+    1e-7. The additional column \code{use_for_plotting} is used by the
+    plotting functions of this package to approximate the control and
+    generate a break in the concentration axis.}
+  }
 }
 \description{
-The ECx-SyS model for modeling concentration-effect relationships which
-indicate signs of hormesis.
+The ECx-SyS model for modeling concentration-effect relationships whith
+hormesis.
 }
 \details{
 It is advised to complete the curve down to zero for optimal prediction.
@@ -56,20 +76,25 @@ sorted by increasing concentration.
 }
 \examples{
 model <- ecxsys(
-    concentration = c(0, 0.03, 0.3, 3, 10),
-    hormesis_concentration = 0.3,
-    effect_tox_observed = c(85, 76, 94, 35, 0),
-    effect_tox_env_observed = c(24, 23, 32, 0, 0)
+    concentration = c(0, 0.05, 0.5, 5, 30),
+    hormesis_concentration = 0.5,
+    effect_tox_observed = c(90, 81, 92, 28, 0),
+    effect_tox_env_observed = c(29, 27, 33, 5, 0)
 )
 
-# Use effect_max if for example the effect is given as the number of
-# surviving animals and the initial number of animals is 20:
+# Use effect_max if for example the effect is given as the average number of
+# surviving animals and the initial number of animals is 21:
 model <- ecxsys(
-    concentration = c(0, 0.03, 0.3, 3, 10),
+    concentration = c(0, 0.03, 0.3, 3, 30),
     hormesis_concentration = 0.3,
     effect_tox_observed = c(17, 15.2, 18.8, 7, 0),
     effect_tox_env_observed = c(4.8, 4.6, 6.4, 0, 0),
-    effect_max = 20
+    effect_max = 21
 )
 
 }
+\references{
+\href{https://doi.org/10.1038/s41598-019-51645-4}{Liess, M.,
+  Henz, S. & Knillmann, S. Predicting low-concentration effects of
+  pesticides. Sci Rep 9, 15248 (2019).}
+}
diff --git a/man/plot_ecxsys.Rd b/man/plot_ecxsys.Rd
index b5d862e04a97a426af65ef99066a053c7d4c27ac..19d5c61ed5b184d8a9d0dd157f877806c3c8b0b5 100644
--- a/man/plot_ecxsys.Rd
+++ b/man/plot_ecxsys.Rd
@@ -8,36 +8,54 @@
 \usage{
 plot_effect(
   model,
-  show_LL5_model = FALSE,
+  which = NULL,
   show_legend = FALSE,
   xlab = "concentration",
-  ylab = "effect"
+  ylab = "effect",
+  main = NULL
 )
 
-plot_stress(model, show_legend = FALSE)
+plot_stress(
+  model,
+  which = NULL,
+  show_legend = FALSE,
+  xlab = "concentration",
+  ylab = "stress",
+  main = NULL
+)
 }
 \arguments{
 \item{model}{The list returned from \code{\link{ecxsys}}.}
 
-\item{show_LL5_model}{Should the log-logistic models be plotted for
-comparison? Defaults to \code{FALSE}.}
+\item{which}{A vector of curve names to plot. Allowed values are the column
+names of the \code{model$curves} data frame. The default \code{NULL} only
+plots the most important curves. Use \code{which = "all"} to display all
+curves.}
 
-\item{show_legend}{Should the plot include a legend? Defaults to FALSE
-because it may cover some points or lines depending on the plot size.}
+\item{show_legend}{Should the plot include a legend? Defaults to \code{FALSE}
+because it may cover some parts of the plot depending on the plot size and
+the number of elements shown.}
 
-\item{xlab, ylab}{Axis labels.}
+\item{xlab, ylab, main}{Axis labels and title.}
 }
 \description{
-Convenience functions to plot the observed and modeled effect and the
-system stress with and without environmental stress.
+Plot the observed and modeled effects and stresses.
 }
 \examples{
 model <- ecxsys(
-    concentration = c(0, 0.03, 0.3, 3, 10),
-    hormesis_concentration = 0.3,
-    effect_tox_observed = c(85, 76, 94, 35, 0),
-    effect_tox_env_observed = c(24, 23, 32, 0, 0)
+    concentration = c(0, 0.05, 0.5, 5, 30),
+    hormesis_concentration = 0.5,
+    effect_tox_observed = c(90, 81, 92, 28, 0),
+    effect_tox_env_observed = c(29, 27, 33, 5, 0)
 )
 plot_effect(model)
 plot_stress(model)
+
+# Plot all curves:
+plot_effect(model, which = "all")
+plot_stress(model, which = "all")
+
+# Plot only some selected curves:
+plot_effect(model, which = c("effect_tox", "effect_tox_env"))
+plot_stress(model, which = c("stress_tox", "stress_tox_env"))
 }
diff --git a/man/predict_ecxsys.Rd b/man/predict_ecxsys.Rd
index 194496d1710b8c30498a83f92e7690adec1dcc6b..5e86de00b1dfa2f0a3fbc7f5bf0ad940391833aa 100644
--- a/man/predict_ecxsys.Rd
+++ b/man/predict_ecxsys.Rd
@@ -2,12 +2,12 @@
 % Please edit documentation in R/predict_ecxsys.R
 \name{predict_ecxsys}
 \alias{predict_ecxsys}
-\title{Predict ECxSyS at various concentrations}
+\title{Predict effects and stresses}
 \usage{
 predict_ecxsys(model, concentration)
 }
 \arguments{
-\item{model}{The output of a call to \code{\link{ecxsys}}.}
+\item{model}{An ECx-SyS model as returned by \code{\link{ecxsys}}.}
 
 \item{concentration}{A numeric vector of concentrations.}
 }
@@ -15,14 +15,11 @@ predict_ecxsys(model, concentration)
 A data frame (of class "ecxsys_predicted") with the following
   columns:
   \describe{
-    \item{concentration}{Concentrations regularly spaced on a logarithmic
-    scale in the given concentration range. The control is approximated by
-    the lowest non-control concentration times 1e-7.}
-    \item{effect_tox_LL5}{The five-parameter log-logistic model of the
-    effect derived from the observations under toxicant stress but without
-    environmental stress.}
-    \item{effect_tox}{Modeled effect resulting from toxicant and system
-    stress.}
+    \item{concentration}{The supplied concentrations.}
+    \item{effect_tox_LL5}{The effect predicted by the five-parameter
+    log-logistic model derived from the observations under toxicant stress
+    but without environmental stress.}
+    \item{effect_tox}{Modeled effect resulting from toxicant stress.}
     \item{effect_tox_sys}{Modeled effect resulting from toxicant and system
     stress.}
     \item{stress_tox}{The toxicant stress.}
@@ -30,9 +27,9 @@ A data frame (of class "ecxsys_predicted") with the following
     without environmental stress.}
     \item{stress_tox_sys}{The sum of \code{stress_tox} and
     \code{sys_tox}.}
-    \item{effect_tox_env_LL5}{The five-parameter log-logistic model of the
-    effect derived from the observations under toxicant stress with
-    environmental stress.}
+    \item{effect_tox_env_LL5}{The effect predicted by the five-parameter
+    log-logistic model derived from the observations under toxicant stress
+    with environmental stress.}
     \item{effect_tox_env}{Modeled effect resulting from toxicant and
     environmental stress.}
     \item{effect_tox_env_sys}{Modeled effect resulting from toxicant,
@@ -46,13 +43,15 @@ A data frame (of class "ecxsys_predicted") with the following
   }
 }
 \description{
-Predict ECxSyS at various concentrations
+Calculate the effects and stresses of an ECx-SyS model at arbitrary
+concentrations.
 }
 \examples{
 model <- ecxsys(
-    concentration = c(0, 0.03, 0.3, 3, 10),
-    hormesis_concentration = 0.3,
-    effect_tox_observed = c(85, 76, 94, 35, 0)
+    concentration = c(0, 0.05, 0.5, 5, 30),
+    hormesis_concentration = 0.5,
+    effect_tox_observed = c(90, 81, 92, 28, 0),
+    effect_tox_env_observed = c(29, 27, 33, 5, 0)
 )
 p <- predict_ecxsys(model, c(0.001, 0.01, 0.1, 1, 10))
 
diff --git a/man/predict_mixture.Rd b/man/predict_mixture.Rd
new file mode 100644
index 0000000000000000000000000000000000000000..bc43850edd096f54a6841cf3d35623ca6920fc86
--- /dev/null
+++ b/man/predict_mixture.Rd
@@ -0,0 +1,53 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/predict_mixture.R
+\name{predict_mixture}
+\alias{predict_mixture}
+\title{Predict the effect of a mixture of two toxicants}
+\usage{
+predict_mixture(
+  model_1,
+  model_2,
+  concentration_1,
+  concentration_2,
+  proportion_ca = 0.5
+)
+}
+\arguments{
+\item{model_1}{The ecxsys model of the toxicant that varies in concentration.}
+
+\item{model_2}{The ecxsys model of the toxicant with a fixed concentration.}
+
+\item{concentration_1}{The concentration of toxicant 1 in the mixture.}
+
+\item{concentration_2}{The concentration of toxicant 2 in the mixture.}
+
+\item{proportion_ca}{How much of the combined toxicant stress is determined
+by concentration addition. Must be between 0 and 1.}
+}
+\value{
+A vector of the effects of the mixture, scaled to the effect_max
+  value of model_1.
+}
+\description{
+This method is only suitable for experiments without environmental stress.
+Any environmental stress in \code{model_1} or \code{model_2} is ignored.
+}
+\examples{
+toxicant_model_1 <- ecxsys(
+    concentration = c(0, 0.05, 0.5, 5, 30),
+    hormesis_concentration = 0.5,
+    effect_tox_observed = c(90, 81, 92, 28, 0),
+)
+toxicant_model_2 <- ecxsys(
+    concentration = c(0, 0.1, 1, 10, 100, 1000),
+    hormesis_concentration = 10,
+    effect_tox_observed = c(26, 25, 24, 27, 5, 0),
+    effect_max = 30
+)
+predict_mixture(
+    toxicant_model_1,
+    toxicant_model_2,
+    c(0, 0.02, 0.2, 2, 20),
+    3
+)
+}
diff --git a/tests/testthat/test-ec.R b/tests/testthat/test-ec.R
index f5deb23002d3f9a41c442050332ee4c942af94cf..a4cb7402f2422f5d3d4001b4857def212c0f7a27 100644
--- a/tests/testthat/test-ec.R
+++ b/tests/testthat/test-ec.R
@@ -1,13 +1,9 @@
-context("effect concentration")
-
-
 test_that("all input formats produce identical models", {
     model <- ecxsys(
-        concentration = c(0, 0.03, 0.3, 3, 10),
-        hormesis_concentration = 0.3,
-        effect_tox_observed = c(85, 76, 94, 35, 0)
+        concentration = c(0, 0.05, 0.5, 5, 30),
+        hormesis_concentration = 0.5,
+        effect_tox_observed = c(90, 81, 92, 28, 0)
     )
-
     # using the ecxsys() output or the curves therein directly:
     ec10_a <- ec(model, "effect_tox_sys", 10)
     ec10_b <- ec(model$curves, "effect_tox_sys", 10)
@@ -24,57 +20,57 @@ test_that("all input formats produce identical models", {
     )
     ec10_d <- ec(df_custom, "foo", 10)
 
-    expect_identical(ec10_a, ec10_b)
-    expect_identical(ec10_b, ec10_c)
-    expect_identical(ec10_c, ec10_d)
+    expect_equal(ec10_a, ec10_b, tolerance = 1e-5)
+    expect_equal(ec10_b, ec10_c, tolerance = 1e-5)
+    expect_equal(ec10_c, ec10_d, tolerance = 1e-5)
 })
 
 
 test_that("ec values have not changed", {
     model <- ecxsys(
-        concentration = c(0, 0.03, 0.3, 3, 10),
-        hormesis_concentration = 0.3,
-        effect_tox_observed = c(85, 76, 94, 35, 0),
-        effect_tox_env_observed = c(24, 23, 32, 0, 0)
+        concentration = c(0, 0.05, 0.5, 5, 30),
+        hormesis_concentration = 0.5,
+        effect_tox_observed = c(90, 81, 92, 28, 0),
+        effect_tox_env_observed = c(29, 27, 33, 5, 0)
     )
     expect_equal(
         ec(model, "effect_tox_sys", 50),
-        list(response_value = 42.389844, concentration = 2.547712),
+        list(response_value = 44.95368, concentration = 3.375735),
         tolerance = 1e-4
     )
     expect_equal(
         ec(model, "effect_tox_sys", 10),
-        list(response_value = 76.301719, concentration = 1.015731),
+        list(response_value = 80.91662, concentration = 1.098648),
         tolerance = 1e-4
     )
     expect_equal(
         ec(model, "effect_tox_sys", 5),
-        list(response_value = 80.540705, concentration = 0.003173),
+        list(response_value = 85.41198, concentration = 0.005502182),
         tolerance = 1e-4
     )
     expect_equal(
         ec(model, "effect_tox_sys", 1),
-        list(response_value = 83.931891, concentration = 0.000057),
+        list(response_value = 89.00828, concentration = 8.53288e-05),
         tolerance = 1e-4
     )
     expect_equal(
         ec(model, "effect_tox_env_sys", 50),
-        list(response_value = 12.155592, concentration = 0.905848),
+        list(response_value = 14.67725, concentration = 1.299516),
         tolerance = 1e-4
     )
     expect_equal(
         ec(model, "effect_tox_env_sys", 10),
-        list(response_value = 21.880066, concentration = 0.0007604),
+        list(response_value = 26.41904, concentration = 0.0008571244),
         tolerance = 1e-4
     )
     expect_equal(
         ec(model, "effect_tox_env_sys", 5),
-        list(response_value = 23.095625, concentration = 0.00010044),
+        list(response_value = 27.88677, concentration = 0.0001044245),
         tolerance = 1e-4
     )
     expect_equal(
         ec(model, "effect_tox_env_sys", 1),
-        list(response_value = 24.068073, concentration = 0.000002),
+        list(response_value = 29.06095, concentration = 1.388112e-06),
         tolerance = 1e-4
     )
 })
diff --git a/tests/testthat/test-ecxsys.R b/tests/testthat/test-ecxsys.R
index 1469b4755e4f95cd966ee871feba1ac7510b22c4..0120163817762a933746afd5ef24f755108c76ab 100644
--- a/tests/testthat/test-ecxsys.R
+++ b/tests/testthat/test-ecxsys.R
@@ -1,12 +1,8 @@
-context("ecxsys")
-
-
-# Create model here for use in the various tests to save typing:
 mod <- ecxsys(
-    concentration = c(0, 0.03, 0.3, 3, 10),
-    hormesis_concentration = 0.3,
-    effect_tox_observed = c(85, 76, 94, 35, 0),
-    effect_tox_env_observed = c(24, 23, 32, 0, 0)
+    concentration = c(0, 0.05, 0.5, 5, 30),
+    hormesis_concentration = 0.5,
+    effect_tox_observed = c(90, 81, 92, 28, 0),
+    effect_tox_env_observed = c(29, 27, 33, 5, 0)
 )
 
 
@@ -14,18 +10,18 @@ test_that("error when hormesis_concentration not in concentration", {
     errorm <- "hormesis_concentration must equal one of the concentration values."
     expect_error(
         ecxsys(
-            concentration = c(0, 0.03, 0.3, 3, 10),
+            concentration = c(0, 0.05, 0.5, 5, 30),
             hormesis_concentration = 0.4,
-            effect_tox_observed = c(85, 76, 94, 35, 0)
+            effect_tox_observed = c(90, 81, 92, 28, 0)
         ),
         errorm,
         fixed = TRUE
     )
     expect_error(
         ecxsys(
-            concentration = c(0, 0.03, 0.3, 3, 10),
-            hormesis_concentration = 30,
-            effect_tox_observed = c(85, 76, 94, 35, 0)
+            concentration = c(0, 0.05, 0.5, 5, 30),
+            hormesis_concentration = 20,
+            effect_tox_observed = c(90, 81, 92, 28, 0)
         ),
         errorm,
         fixed = TRUE
@@ -40,7 +36,7 @@ test_that("error when hormesis_index <= 2 or >= (length(concentration))", {
     )
     expect_error(
         ecxsys(
-            concentration = c(0, 0.03, 0.3, 3, 10),
+            concentration = c(0, 0.05, 0.5, 5, 30),
             hormesis_concentration = 0,
             effect_tox_observed = c(85, 76, 94, 35, 0)
         ),
@@ -49,8 +45,8 @@ test_that("error when hormesis_index <= 2 or >= (length(concentration))", {
     )
     expect_error(
         ecxsys(
-            concentration = c(0, 0.03, 0.3, 3, 10),
-            hormesis_concentration = 0.03,
+            concentration = c(0, 0.05, 0.5, 5, 30),
+            hormesis_concentration = 0.05,
             effect_tox_observed = c(85, 76, 94, 35, 0)
         ),
         errorm,
@@ -58,8 +54,8 @@ test_that("error when hormesis_index <= 2 or >= (length(concentration))", {
     )
     expect_error(
         ecxsys(
-            concentration = c(0, 0.03, 0.3, 3, 10),
-            hormesis_concentration = 10,
+            concentration = c(0, 0.05, 0.5, 5, 30),
+            hormesis_concentration = 30,
             effect_tox_observed = c(85, 76, 94, 35, 0)
         ),
         errorm,
@@ -76,53 +72,53 @@ test_that("min(concentration) == 0 is shifted the correct amount", {
 test_that("the discrete results have not changed", {
     expect_equal(
         mod$effect_tox_LL5,
-        c(85, 84.5420, 78.9464, 31.9586, 2.6096),
+        c(90, 89.745092, 82.340325, 26.787104, 4.306868),
         tolerance = 1e-4
     )
     expect_equal(
         mod$effect_tox,
-        c(100, 99.6760, 94.3198, 34.8601, 0.8400),
+        c(100, 99.455327884, 92.000028403, 27.999995346, 0.002452598),
         tolerance = 1e-4
     )
     expect_equal(
         mod$stress_tox,
-        c(0, 0.0784, 0.2067, 0.5794, 0.8927),
+        c(0, 0.09296422, 0.23401450, 0.61804415, 0.98352101),
         tolerance = 1e-4
     )
     expect_equal(
         mod$sys_tox_not_fitted,
-        c(0.2965, 0.2795, 0, 0, 0),
+        c(0.2541156, 0.2324304, 0, 0, 0),
         tolerance = 1e-4
     )
     expect_equal(
         mod$effect_tox_sys,
-        c(84.7912, 77.4811, 93.1380, 34.8602, 0.8400),
+        c(89.920669034, 81.890300846, 90.863799559, 27.999995346, 0.002452598),
         tolerance = 1e-4
     )
-    expect_equal(mod$stress_env, 0.3885, tolerance = 1e-3)
+    expect_equal(mod$stress_env, 0.3556369, tolerance = 1e-4)
     expect_equal(
         mod$effect_tox_env_LL5,
-        c(26.3333, 26.3333, 26.0620, 0.7104, 0.0374),
+        c(29.6666667, 29.6666657, 29.5214959, 5.4076411, 0.7871201),
         tolerance = 1e-4
     )
     expect_equal(
         mod$stress_tox_env,
-        c(0.3884, 0.4669, 0.5952, 0.9679, 1.2812),
+        c(0.3556369, 0.4486011, 0.5896514, 0.9736810, 1.3391579),
         tolerance = 1e-4
     )
     expect_equal(
         mod$effect_tox_env,
-        c(70.8786, 56.4138, 32, 0.0202, 0),
+        c(76.36558967, 59.90195211, 33, 0.01079038, 0),
         tolerance = 1e-4
     )
     expect_equal(
         mod$sys_tox_env_not_fitted,
-        c(0.2537, 0.1815, 0, 0, 0),
+        c(0.2566005, 0.1753250, 0, 0, 0),
         tolerance = 1e-4
     )
     expect_equal(
         mod$effect_tox_env_sys,
-        c(24.3254, 22.3232, 29.3860, 0.0202, 0),
+        c(29.37633973, 25.99861674, 30.16676004, 0.01079038, 0),
         tolerance = 1e-4
     )
 })
@@ -132,20 +128,20 @@ test_that("the curves have not changed", {
     new_curves <- mod$curves[c(1, 714, 810, 905, 1000), ]  # random indices
     rownames(new_curves) <- NULL
     reference_curves <- data.frame(
-        concentration = c(0.0000, 0.0137, 0.1253, 1.1196, 10.0000),
-        effect_tox_LL5 = c(85.0000, 84.8116, 82.6996, 61.2882, 2.6096),
-        effect_tox_env_LL5 = c(26.3333, 26.3333, 26.3289, 7.5384, 0.0374),
-        effect_tox = c(100.0000, 99.8787, 98.0645, 73.6652, 0.8400),
-        stress_tox = c(0.0001, 0.0570, 0.1421, 0.3721, 0.8927),
-        sys_tox = c(0.2980, 0.2887, 0.1336, 0.0000, 0.0000),
-        stress_tox_sys = c(0.2981, 0.3457, 0.2757, 0.3721, 0.8927),
-        effect_tox_sys = c(84.7797, 77.9323, 87.5799, 73.6652, 0.8400),
-        stress_env = c(0.3885, 0.3885, 0.3885, 0.3885, 0.3885),
-        stress_tox_env = c(0.3886, 0.4455, 0.5306, 0.7606, 1.2812),
-        effect_tox_env = c(70.8634, 60.4957, 44.0834, 8.5137, 0.0000),
-        sys_tox_env = c(0.2516, 0.2175, 0.0762, 0.0000, 0.0000),
-        stress_tox_env_sys = c(0.6402, 0.6630, 0.6068, 0.7606, 1.2812),
-        effect_tox_env_sys = c(24.3112, 20.7272, 29.9481, 8.5133, 0.0000),
+        concentration = c(0.00000, 0.03004, 0.30512, 3.02551, 30.00000),
+        effect_tox_LL5 = c(90.00000, 89.88245, 86.18591, 40.42560, 4.30687),
+        effect_tox_env_LL5 = c(29.66667, 29.66667, 29.65530, 9.27616, 0.78712),
+        effect_tox = c(100.00000, 99.70167, 95.45944, 49.54173, 0.00245),
+        stress_tox = c(0.00013, 0.07631, 0.19093, 0.50236, 0.98352),
+        sys_tox = c(0.25487, 0.24017, 0.05667, 0.00000, 0.00000),
+        stress_tox_sys = c(0.25499, 0.31648, 0.24760, 0.50236, 0.98352),
+        effect_tox_sys = c(89.90735, 82.27932, 90.67515, 49.54173, 0.00245),
+        stress_env = c(0.35564, 0.35564, 0.35564, 0.35564, 0.35564),
+        stress_tox_env = c(0.35576, 0.43195, 0.54657, 0.85800, 1.33916),
+        effect_tox_env = c(76.34546, 63.03379, 41.01651, 1.93183, 0.00000),
+        sys_tox_env = c(0.25443, 0.20496, 0.04445, 0.00000, 0.00000),
+        stress_tox_env_sys = c(0.61020, 0.63691, 0.59102, 0.85800, 1.33916),
+        effect_tox_env_sys = c(29.35449, 24.84147, 32.75385, 1.93182, 0),
         use_for_plotting = c(TRUE, TRUE, TRUE, TRUE, TRUE)
     )
     class(new_curves) <- class(reference_curves)
@@ -163,10 +159,10 @@ test_that("the returned fn works the same way as internally", {
 
 test_that("function arguments are returned unchanged", {
     args_reference <- list(
-        concentration = c(0, 0.03, 0.3, 3, 10),
-        hormesis_concentration = 0.3,
-        effect_tox_observed = c(85, 76, 94, 35, 0),
-        effect_tox_env_observed = c(24, 23, 32, 0, 0),
+        concentration = c(0, 0.05, 0.5, 5, 30),
+        hormesis_concentration = 0.5,
+        effect_tox_observed = c(90, 81, 92, 28, 0),
+        effect_tox_env_observed = c(29, 27, 33, 5, 0),
         effect_max = 100,
         p = 3.2,
         q = 3.2
@@ -175,22 +171,29 @@ test_that("function arguments are returned unchanged", {
 })
 
 
+ecxsys(
+    concentration = c(0, 0.05, 0.5, 5, 30),
+    hormesis_concentration = 0.5,
+    effect_tox_observed = c(90, 81, 92, 28, 0),
+    effect_tox_env_observed = c(29, 27, 33, 5, 0)
+)
+
 test_that("results are independent of concentration shift", {
     mod_2 <- ecxsys(
-        concentration = c(0, 0.03, 0.3, 3, 10) * 2,
-        hormesis_concentration = 0.3 * 2,
-        effect_tox_observed = c(85, 76, 94, 35, 0),
-        effect_tox_env_observed = c(24, 23, 32, 0, 0)
+        concentration = c(0, 0.05, 0.5, 5, 30) * 2,
+        hormesis_concentration = 0.5 * 2,
+        effect_tox_observed = c(90, 81, 92, 28, 0),
+        effect_tox_env_observed = c(29, 27, 33, 5, 0)
     )
     expect_equal(mod$effect_tox_sys, mod_2$effect_tox_sys)
     expect_equal(mod$effect_tox_env_sys, mod_2$effect_tox_env_sys)
     mod_10 <- ecxsys(
-        concentration = c(0, 0.03, 0.3, 3, 10) * 10,
-        hormesis_concentration = 0.3 * 10,
-        effect_tox_observed = c(85, 76, 94, 35, 0),
-        effect_tox_env_observed = c(24, 23, 32, 0, 0)
+        concentration = c(0, 0.05, 0.5, 5, 30) * 10,
+        hormesis_concentration = 0.5 * 10,
+        effect_tox_observed = c(90, 81, 92, 28, 0),
+        effect_tox_env_observed = c(29, 27, 33, 5, 0)
     )
-    # Concentration shifts by factors other than powers of 10 will affect
+    # Concentration shifts by factors other than powers of 10 may affect
     # the result because of the way the zero concentration is "corrected".
     expect_equal(mod$curves$effect_tox,
                  mod_10$curves$effect_tox)
@@ -203,9 +206,9 @@ test_that("results are independent of concentration shift", {
 
 test_that("effect_tox_env_observed can be left out", {
     mod_without_env <- ecxsys(
-        concentration = c(0, 0.03, 0.3, 3, 10),
-        hormesis_concentration = 0.3,
-        effect_tox_observed = c(85, 76, 94, 35, 0)
+        concentration = c(0, 0.05, 0.5, 5, 30),
+        hormesis_concentration = 0.5,
+        effect_tox_observed = c(90, 81, 92, 28, 0)
     )
     expect_equal(mod$effect_tox_sys, mod_without_env$effect_tox_sys)
     expect_equal(mod$curves$effect_tox_sys,
@@ -226,4 +229,17 @@ test_that("sys model not converging produces a warning, not an error", {
         ),
         fixed = TRUE
     )
+    expect_warning(
+        ecxsys(
+            concentration = c(0, 0.1, 0.5, 1, 10, 33),
+            effect_tox_observed = c(90, 81, 92, 50, 18, 0),
+            effect_tox_env_observed = c(75, 89, 54, 7, 0, 0),
+            hormesis_concentration = 0.5
+        ),
+        paste(
+            "Using a horizontal linear model for sys_tox_env_mod because the",
+            "Weibull model did not converge."
+        ),
+        fixed = TRUE
+    )
 })
diff --git a/tests/testthat/test-options.R b/tests/testthat/test-options.R
index dc5945baeefcc9cf31aa32e387837fcba6f6bea3..6d7c85d1db31a21e9bd235a7c173fcb26fd6b8e1 100644
--- a/tests/testthat/test-options.R
+++ b/tests/testthat/test-options.R
@@ -1,6 +1,3 @@
-context("options")
-
-
 test_that("user options are not permanently changed by ecxsys()", {
     # drc::drm() messes with the options and fails to return them to their
     # previous values. And options are temporarily modified in ecxsys(). This
@@ -13,10 +10,10 @@ test_that("user options are not permanently changed by ecxsys()", {
 
     original_options <- options()
     model <- ecxsys(
-        concentration = c(0, 0.03, 0.3, 3, 10),
-        effect_tox_observed = c(85, 76, 94, 35, 0),
-        effect_tox_env_observed = c(24, 23, 32, 0, 0),
-        hormesis_concentration = 0.3
+        concentration = c(0, 0.05, 0.5, 5, 30),
+        hormesis_concentration = 0.5,
+        effect_tox_observed = c(90, 81, 92, 28, 0),
+        effect_tox_env_observed = c(29, 27, 33, 5, 0)
     )
     new_options <- options()
 
diff --git a/tests/testthat/test-plot_ecxsys.R b/tests/testthat/test-plot_ecxsys.R
index 541028b5a21b5770e6e417476fac6ffc6e3391b6..4a61b99d27c535b04eef909476a1bf6e128d6232 100644
--- a/tests/testthat/test-plot_ecxsys.R
+++ b/tests/testthat/test-plot_ecxsys.R
@@ -1,6 +1,3 @@
-context("plots")
-
-
 test_that("log ticks are correct", {
   x <- c(0.03, 0.3, 3, 30)
   ticks <- get_log_ticks(x)
diff --git a/tests/testthat/test-predict_mixture.R b/tests/testthat/test-predict_mixture.R
new file mode 100644
index 0000000000000000000000000000000000000000..3471aeb429a0e7cff5f1496d08445e36253eb99f
--- /dev/null
+++ b/tests/testthat/test-predict_mixture.R
@@ -0,0 +1,34 @@
+model_1 <- ecxsys(
+    concentration = c(0, 0.05, 0.5, 5, 30),
+    hormesis_concentration = 0.5,
+    effect_tox_observed = c(90, 81, 92, 28, 0),
+    effect_tox_env_observed = c(29, 27, 33, 5, 0),
+    effect_max = 101
+)
+model_2 <- ecxsys(
+    concentration = c(0, 0.1, 1, 10, 100, 1000),
+    hormesis_concentration = 10,
+    effect_tox_observed = c(26, 25, 24, 27, 5, 0),
+    effect_max = 30
+)
+
+
+test_that("results have not changed", {
+    new <- predict_mixture(model_1, model_2, c(0, 0.01, 0.1, 1, 7, 15), 5, 0.3)
+    reference <- c(89.460324, 85.205168, 81.440100, 57.297855, 2.911545, 0)
+    expect_equal(new, reference, tolerance = 1e-5)
+})
+
+
+test_that("predictions are symmetric", {
+    conc_1 <- c(0, 10^seq(log10(0.001), log10(40), length.out = 50))
+    conc_2 <- 3.5
+    prop_ca <- 0.8
+    effect_12 <- predict_mixture(model_1, model_2, conc_1, conc_2, prop_ca)
+    effect_21 <- sapply(
+        conc_1,
+        function(x) predict_mixture(model_2, model_1, conc_2, x, prop_ca)
+    )
+    effect_21 <- effect_21 / model_2$args$effect_max * model_1$args$effect_max
+    expect_equal(effect_12, effect_21)
+})
diff --git a/tests/testthat/test-stress_effect_conversion.R b/tests/testthat/test-stress_effect_conversion.R
index 506491d38c69d6d246d45c549ae8ab2d86b625b4..b583ece438293fb19df092d467a5b016054c6c98 100644
--- a/tests/testthat/test-stress_effect_conversion.R
+++ b/tests/testthat/test-stress_effect_conversion.R
@@ -1,6 +1,3 @@
-context("stress effect conversion")
-
-
 test_that("stress_to_effect handles bad input", {
     expect_equal(stress_to_effect(-3), 1)
     expect_equal(stress_to_effect(10), 0)