Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #249 allow data expansion to axes #251

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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