Skip to content

Commit

Permalink
Fixes Open-Systems-Pharmacology#249 allow data expansion to axes (Ope…
Browse files Browse the repository at this point in the history
…n-Systems-Pharmacology#251)

* Fixes Open-Systems-Pharmacology#249 allow data expansion to axes

Default value for ddi ratio is TRUE

* Default axes scales and expand are managed using constants

* Remove usage of enum Scaling for constants to prevent build crash
  • Loading branch information
pchelle authored May 2, 2022
1 parent aa82c2e commit 2cbd8ad
Show file tree
Hide file tree
Showing 17 changed files with 162 additions and 145 deletions.
3 changes: 3 additions & 0 deletions R/boxwhisker-plotconfiguration.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ BoxWhiskerPlotConfiguration <- R6::R6Class(
"BoxWhiskerPlotConfiguration",
inherit = PlotConfiguration,
public = list(
#' @field defaultXScale Default xAxis scale value when creating a `BoxWhiskerPlotConfiguration` object
defaultXScale = "discrete",

#' @description Create a new `BoxWhiskerPlotConfiguration` object
#' @param outliers logical defining if outliers should be included in boxplot
#' @param ... parameters inherited from `PlotConfiguration`
Expand Down
58 changes: 51 additions & 7 deletions R/plotconfiguration-axis.R
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ createPlotTicks <- function(ticks) {
return(ticks)
}


#' @title AxisConfiguration
#' @description R6 class defining the configuration of axis
#' @export
Expand All @@ -52,20 +51,26 @@ AxisConfiguration <- R6::R6Class(
#' @param ticks numeric vector or function defining where to position axis ticks
#' @param ticklabels character vector or function defining what to print on axis ticks
#' @param font `Font` object defining the font of ticklabels
#' @param expand logical defining if data is expanded until axis.
#' If `TRUE`, data is expanded until axis
#' If `FALSE`, some space between data and axis is kept
#' @return A new `AxisConfiguration` object
initialize = function(limits = NULL,
scale = Scaling$lin,
ticks = NULL,
ticklabels = NULL,
font = NULL) {
font = NULL,
expand = FALSE) {
validateIsNumeric(limits, nullAllowed = TRUE)
validateIsOfType(font, "Font", nullAllowed = TRUE)
validateIsLogical(expand)
private$.limits <- limits

scale <- scale %||% Scaling$lin
private$.scale <- createPlotScale(scale)
private$.ticks <- createPlotTicks(ticks)
private$.ticklabels <- createPlotTicks(ticklabels)
private$.expand <- expand

# Default axis font will use theme
defaultFont <- Font$new()
Expand All @@ -90,6 +95,15 @@ AxisConfiguration <- R6::R6Class(
)
},

#' @description Get the `ggplot2` actual function for expansion
#' @return A `ggplot2` function
ggplotExpansion = function() {
if (private$.expand) {
return(ggplot2::expansion())
}
return(ggplot2::waiver())
},

#' @description Get tick values for pretty default log plots
#' @return User defined tick values or tlf default ticks
prettyTicks = function() {
Expand Down Expand Up @@ -185,14 +199,26 @@ AxisConfiguration <- R6::R6Class(
}
private$.font <- value %||% defaultFont
return(invisible())
},
#' @field expand logical defining if data is expanded until axis.
#' If `TRUE`, data is expanded until axis
#' If `FALSE`, some space between data and axis is kept
expand = function(value) {
if (missing(value)) {
return(private$.expand)
}
validateIsLogical(value)
private$.expand <- value
return(invisible())
}
),
private = list(
.limits = NULL,
.scale = NULL,
.ticks = NULL,
.ticklabels = NULL,
.font = NULL
.font = NULL,
.expand = NULL
)
)

Expand All @@ -219,15 +245,24 @@ XAxisConfiguration <- R6::R6Class(
if (isIncluded(private$.scale, Scaling$discrete)) {
suppressMessages(
plotObject <- plotObject +
ggplot2::scale_x_discrete(breaks = private$.ticks, labels = private$.ticklabels)
ggplot2::scale_x_discrete(
breaks = private$.ticks,
labels = private$.ticklabels,
expand = self$ggplotExpansion()
)
)
return(plotObject)
}
# Most of ggplot2 scales lead to unwanted warning messages
# `try` should be added in cases of scale breaking because all the ggplot object elements are not yet in place
suppressMessages(
plotObject <- plotObject +
ggplot2::scale_x_continuous(trans = self$ggplotScale(), breaks = self$prettyTicks(), labels = self$prettyTickLabels())
ggplot2::scale_x_continuous(
trans = self$ggplotScale(),
breaks = self$prettyTicks(),
labels = self$prettyTickLabels(),
expand = self$ggplotExpansion()
)
)
# Add special tick lines for pretty log plots
suppressMessages(
Expand Down Expand Up @@ -268,15 +303,24 @@ YAxisConfiguration <- R6::R6Class(
if (isIncluded(private$.scale, Scaling$discrete)) {
suppressMessages(
plotObject <- plotObject +
ggplot2::scale_y_discrete(breaks = private$.ticks, labels = private$.ticklabels)
ggplot2::scale_y_discrete(
breaks = private$.ticks,
labels = private$.ticklabels,
expand = self$ggplotExpansion()
)
)
return(plotObject)
}
# Most of ggplot2 scales lead to unwanted warning messages
# `try` should be added in cases of scale breaking because all the ggplot object elements are not yet in place
suppressMessages(
plotObject <- plotObject +
ggplot2::scale_y_continuous(trans = self$ggplotScale(), breaks = self$prettyTicks(), labels = self$prettyTickLabels())
ggplot2::scale_y_continuous(
trans = self$ggplotScale(),
breaks = self$prettyTicks(),
labels = self$prettyTickLabels(),
expand = self$ggplotExpansion()
)
)
# Add special tick lines for pretty log plots
suppressMessages(
Expand Down
34 changes: 30 additions & 4 deletions R/plotconfiguration.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#' @title PlotConfiguration
#' @description R6 class defining the configuration of a `ggplot` object
#' @field export R6 class `ExportConfiguration` defining properties for saving/exporting plota
#' @field defaultXScale Default xAxis scale value when creating a `PlotConfiguration` object
#' @field defaultYScale Default yAxis scale value when creating a `PlotConfiguration` object
#' @field defaultExpand Default expand value when creating a `PlotConfiguration` object
#' @family PlotConfiguration classes
#' @references For examples, see:
#' <https://www.open-systems-pharmacology.org/TLF-Library/articles/plot-configuration.html>
Expand All @@ -9,6 +12,11 @@ PlotConfiguration <- R6::R6Class(
"PlotConfiguration",
public = list(
export = NULL,
# Caution, helper enum Scaling doesn't work here
# (even using @include to collate and define the variable beforehand)
defaultXScale = "lin",
defaultYScale = "lin",
defaultExpand = FALSE,

#' @description Create a new `PlotConfiguration` object
#' @param title character or `Label` object defining plot title
Expand Down Expand Up @@ -122,13 +130,19 @@ PlotConfiguration <- R6::R6Class(

# X-Axis Configuration, overwrite some properties only if they are defined
validateIsOfType(xAxis, "XAxisConfiguration", nullAllowed = TRUE)
private$.xAxis <- xAxis %||% XAxisConfiguration$new(scale = xAxisDefaultScale(self))
private$.xAxis <- xAxis %||% XAxisConfiguration$new(
scale = self$defaultXScale,
expand = self$defaultExpand
)
private$.xAxis$limits <- xLimits %||% private$.xAxis$limits
private$.xAxis$scale <- xScale %||% private$.xAxis$scale

# Y-Axis configuration, overwrite some properties only if they are defined
validateIsOfType(yAxis, "YAxisConfiguration", nullAllowed = TRUE)
private$.yAxis <- yAxis %||% YAxisConfiguration$new(scale = yAxisDefaultScale(self))
private$.yAxis <- yAxis %||% YAxisConfiguration$new(
scale = self$defaultYScale,
expand = self$defaultExpand
)
private$.yAxis$limits <- yLimits %||% private$.yAxis$limits
private$.yAxis$scale <- yScale %||% private$.yAxis$scale

Expand Down Expand Up @@ -272,20 +286,32 @@ TimeProfilePlotConfiguration <- R6::R6Class(

#' @title PKRatioPlotConfiguration
#' @description R6 class defining the configuration of a `ggplot` object for PK ratio plots
#' @field defaultYScale Default yAxis scale value when creating a `PKRatioPlotConfiguration` object
#' @export
#' @family PlotConfiguration classes
PKRatioPlotConfiguration <- R6::R6Class(
"PKRatioPlotConfiguration",
inherit = PlotConfiguration
inherit = PlotConfiguration,
public = list(
defaultYScale = "log"
)
)

#' @title DDIRatioPlotConfiguration
#' @description R6 class defining the configuration of a `ggplot` object for DDI ratio plots
#' @field defaultXScale Default xAxis scale value when creating a `DDIRatioPlotConfiguration` object
#' @field defaultYScale Default yAxis scale value when creating a `DDIRatioPlotConfiguration` object
#' @field defaultExpand Default expand value when creating a `DDIRatioPlotConfiguration` object
#' @export
#' @family PlotConfiguration classes
DDIRatioPlotConfiguration <- R6::R6Class(
"DDIRatioPlotConfiguration",
inherit = PlotConfiguration
inherit = PlotConfiguration,
public = list(
defaultXScale = "log",
defaultYScale = "log",
defaultExpand = TRUE
)
)

#' @title ObsVsPredPlotConfiguration
Expand Down
2 changes: 2 additions & 0 deletions R/tornado-plotconfiguration.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ TornadoPlotConfiguration <- R6::R6Class(
colorPalette = NULL,
#' @field dodge space between the bars/points
dodge = NULL,
#' @field defaultYScale Default yAxis scale value when creating a `TornadoPlotConfiguration` object
defaultYScale = "discrete",

#' @description Create a new `TornadoPlotConfiguration` object
#' @param bar logical setting if tornado is uses a bar plot instead of regular points
Expand Down
72 changes: 9 additions & 63 deletions R/utilities-axis.R
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Scaling <- enum(c(
#' @param ticks Optional values or function for axis ticks
#' @param ticklabels Optional values or function for axis ticklabels
#' @param font A `Font` object defining font of ticklabels
#' @param expand Logical defining if data is expanded until axis
#' @return A `ggplot` object
#' @export
#' @examples
Expand All @@ -64,11 +65,13 @@ setXAxis <- function(plotObject,
limits = NULL,
ticks = NULL,
ticklabels = NULL,
font = NULL) {
font = NULL,
expand = NULL) {
validateIsOfType(plotObject, "ggplot")
validateIsIncluded(scale, Scaling, nullAllowed = TRUE)
validateIsNumeric(limits, nullAllowed = TRUE)
validateIsOfType(font, "Font", nullAllowed = TRUE)
validateIsLogical(expand, nullAllowed = TRUE)

# Clone plotConfiguration into a new plot object
# Prevents update of R6 class being spread to plotObject
Expand All @@ -77,7 +80,7 @@ setXAxis <- function(plotObject,

# R6 class not cloned will spread modifications into newPlotObject$plotConfiguration$xAxis
xAxis <- newPlotObject$plotConfiguration$xAxis
eval(parseVariableToObject("xAxis", c("limits", "scale", "ticks", "ticklabels", "font"), keepIfNull = TRUE))
eval(parseVariableToObject("xAxis", c("limits", "scale", "ticks", "ticklabels", "font", "expand"), keepIfNull = TRUE))
newPlotObject <- xAxis$updatePlot(newPlotObject, ylim = newPlotObject$plotConfiguration$yAxis$limits)
return(newPlotObject)
}
Expand Down Expand Up @@ -106,11 +109,13 @@ setYAxis <- function(plotObject,
limits = NULL,
ticks = NULL,
ticklabels = NULL,
font = NULL) {
font = NULL,
expand = NULL) {
validateIsOfType(plotObject, "ggplot")
validateIsIncluded(scale, Scaling, nullAllowed = TRUE)
validateIsNumeric(limits, nullAllowed = TRUE)
validateIsOfType(font, "Font", nullAllowed = TRUE)
validateIsLogical(expand, nullAllowed = TRUE)

# Clone plotConfiguration into a new plot object
# Prevents update of R6 class being spread to plotObject
Expand All @@ -119,70 +124,11 @@ setYAxis <- function(plotObject,

# R6 class not cloned will spread modifications into newPlotObject$plotConfiguration$yAxis
yAxis <- newPlotObject$plotConfiguration$yAxis
eval(parseVariableToObject("yAxis", c("limits", "scale", "ticks", "ticklabels", "font"), keepIfNull = TRUE))
eval(parseVariableToObject("yAxis", c("limits", "scale", "ticks", "ticklabels", "font", "expand"), keepIfNull = TRUE))
newPlotObject <- yAxis$updatePlot(newPlotObject, xlim = newPlotObject$plotConfiguration$xAxis$limits)
return(newPlotObject)
}

#' @title xAxisDefaultScale
#' @description Return x-axis default scale from a plot configuration
#' @param plotConfiguration A `PlotConfiguration` object
#' @return The default scale.
#' The enum `Scaling` provides a list of available scales.
#' @examples
#' \dontrun{
#' # Regular plots use continuous linear scale for x-axis
#' plotConfiguration <- PlotConfiguration$new()
#' xAxisDefaultScale(plotConfiguration)
#'
#' # DDI plots use log scale for x-axis
#' ddiPlotConfiguration <- DDIRatioPlotConfiguration$new()
#' xAxisDefaultScale(ddiPlotConfiguration)
#'
#' # Boxplots use discrete scale for x-axis
#' boxPlotConfiguration <- BoxWhiskerPlotConfiguration$new()
#' xAxisDefaultScale(boxPlotConfiguration)
#' }
#' @keywords internal
xAxisDefaultScale <- function(plotConfiguration) {
if (isOfType(plotConfiguration, c("DDIRatioPlotConfiguration"))) {
return(Scaling$log)
}
if (isOfType(plotConfiguration, c("BoxWhiskerPlotConfiguration"))) {
return(Scaling$discrete)
}
return(Scaling$lin)
}

#' @title yAxisDefaultScale
#' @description Return y-axis default scale from a plot configuration
#' @param plotConfiguration A `PlotConfiguration` object
#' @return The default scale.
#' The enum `Scaling` provides a list of available scales.
#' @examples
#' \dontrun{
#' # Regular plots use continuous linear scale for x-axis
#' plotConfiguration <- PlotConfiguration$new()
#' yAxisDefaultScale(plotConfiguration)
#'
#' # DDI plots use log scale for y-axis
#' ddiPlotConfiguration <- DDIRatioPlotConfiguration$new()
#' yAxisDefaultScale(ddiPlotConfiguration)
#'
#' # Tornado plots use discrete scale for y-axis
#' tornadoPlotConfiguration <- TornadoPlotConfiguration$new()
#' yAxisDefaultScale(tornadoPlotConfiguration)
#' }
#' @keywords internal
yAxisDefaultScale <- function(plotConfiguration) {
if (isOfType(plotConfiguration, c("PKRatioPlotConfiguration", "DDIRatioPlotConfiguration"))) {
return(Scaling$log)
}
if (isOfType(plotConfiguration, c("TornadoPlotConfiguration"))) {
return(Scaling$discrete)
}
return(Scaling$lin)
}

#' @title getLogTickLabels
#' @description Get ticklabels expressions for log scale plots
Expand Down
Loading

0 comments on commit 2cbd8ad

Please sign in to comment.