diff --git a/NAMESPACE b/NAMESPACE index 8b507e17..cb56695c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -31,6 +31,7 @@ export(AestheticProperties) export(AestheticSelectionKeys) export(AggregationInput) export(AggregationSummary) +export(Alignments) export(AxisConfiguration) export(BackgroundConfiguration) export(BackgroundElement) @@ -43,6 +44,7 @@ export(DDIRatioDataMapping) export(DDIRatioPlotConfiguration) export(ExportConfiguration) export(Font) +export(FontFaces) export(GroupMapping) export(Grouping) export(HistogramDataMapping) diff --git a/R/font.R b/R/font.R index 4d27cf25..2cabf477 100644 --- a/R/font.R +++ b/R/font.R @@ -1,54 +1,106 @@ -#' @title Font -#' @description R6 class defining font properties -#' @field size numeric defining the size of font -#' @field color character defining the color of font -#' @field fontFamily character defining the family of font -#' @field fontFace character defining the face of font -#' @field angle numeric defining the angle of font -#' @export -Font <- R6::R6Class( - "Font", - public = list( - size = 12, - color = "black", - fontFamily = "", - fontFace = "plain", - angle = 0, - - #' @description Create a new `Font` object. - #' Default font properties are defined directly in the object field, - #' so `NULL` input is allowed will lead to default properties. - #' @param size numeric defining the size of font - #' @param color character defining the color of font - #' @param fontFamily character defining the family of font - #' @param fontFace character defining the face of font - #' @param angle numeric defining the angle of font - #' @return A new `Font` object - initialize = function(size = NULL, - color = NULL, - fontFamily = NULL, - fontFace = NULL, - angle = NULL) { - validateIsString(c(color, fontFamily, fontFace), nullAllowed = TRUE) - validateIsNumeric(c(size, angle), nullAllowed = TRUE) - eval(parseVariableToObject("self", c("size", "color", "fontFace", "fontFamily", "angle"), keepIfNull = TRUE)) - }, - - #' @description Create a `ggplot2::element_text` directly convertible by `ggplot2::theme`. - #' @return An `element_text` object. - createPlotFont = function() { - ggplot2::element_text( - colour = self$color, - size = self$size, - face = self$fontFace, - # TODO: check why I get the following error messages - # "font family not found in Windows font database" - # family = self$fontFamily, - angle = self$angle, - # Center the label even with angle - vjust = 0.5, - hjust = 0.5 - ) - } - ) -) +#' @title Font +#' @description R6 class defining font properties +#' @field size numeric defining the size of font +#' @field color character defining the color of font +#' @field fontFamily character defining the family of font +#' @field fontFace character defining the font face as defined in helper enum `FontFaces`. +#' @field angle numeric defining the angle of font +#' @field align character defining the alignment of font as defined in helper enum `Alignments`. +#' @export +Font <- R6::R6Class( + "Font", + public = list( + size = 12, + color = "black", + fontFamily = "", + fontFace = "plain", + angle = 0, + align = "center", + + #' @description Create a new `Font` object. + #' Default font properties are defined directly in the object field, + #' so `NULL` input is allowed will lead to default properties. + #' @param color character defining the color of font + #' @param size numeric defining the size of font + #' @param fontFamily character defining the family of font + #' @param fontFace character defining the font face as defined in helper enum `FontFaces`. + #' @param angle numeric defining the angle of font + #' @param align character defining the alignment of font as defined in helper enum `Alignments`. + #' @return A new `Font` object + initialize = function(color = NULL, + size = NULL, + fontFamily = NULL, + fontFace = NULL, + angle = NULL, + align = NULL) { + validateIsString(c(color, fontFamily), nullAllowed = TRUE) + validateIsNumeric(c(size, angle), nullAllowed = TRUE) + validateIsIncluded(fontFace, FontFaces, nullAllowed = TRUE) + validateIsIncluded(align, Alignments, nullAllowed = TRUE) + eval(parseVariableToObject("self", c("size", "color", "fontFace", "fontFamily", "angle", "align"), keepIfNull = TRUE)) + }, + + #' @description Create a `ggplot2::element_text` directly convertible by `ggplot2::theme`. + #' @param size numeric defining the size of font + #' @param color character defining the color of font + #' @param fontFamily character defining the family of font + #' @param fontFace character defining the font face as defined in helper enum `FontFaces`. + #' @param angle numeric defining the angle of font + #' @param align character defining the alignment of font as defined in helper enum `Alignments`. + #' @return An `element_text` object. + createPlotFont = function(size = NULL, + color = NULL, + fontFamily = NULL, + fontFace = NULL, + angle = NULL, + align = NULL) { + ggplot2::element_text( + colour = color %||% self$color, + size = size %||% self$size, + face = fontFace %||% self$fontFace, + # Use font family only if available in Windows font database database + family = checkPlotFontFamily(fontFamily %||% self$fontFamily), + angle = angle %||% self$angle, + vjust = 0.5, + hjust = switch(align %||% self$align, "left" = 0, "center" = 0.5, "right" = 1) + ) + } + ) +) + +#' @title Alignments +#' @import ospsuite.utils +#' @export +#' @description +#' List of all available alignments/justifications for fonts +#' @family enum helpers +Alignments <- enum(c("left", "center","right")) + +#' @title FontFaces +#' @import ospsuite.utils +#' @export +#' @description +#' List of all available font faces +#' @family enum helpers +FontFaces <- enum(c("plain", "bold", "italic", "bold.italic")) + + +#' @title checkPlotFontFamily +#' @description Check if font family is available in Windows font database. +#' Use function `grDevices::windowsFonts()` to get the list of font families available. +#' @param fontFamily character defining the family of font +#' @return Name of font family if available in Windows font database +#' `NULL` otherwise +#' @keywords internal +checkPlotFontFamily <- function(fontFamily){ + if(isEmpty(.Platform$OS.type)){ + return(NULL) + } + if(.Platform$OS.type != "windows"){ + return(NULL) + } + if(isIncluded(fontFamily, names(grDevices::windowsFonts()))){ + return(fontFamily) + } + return(NULL) +} diff --git a/R/label.R b/R/label.R index 1a798df1..1150bb0c 100644 --- a/R/label.R +++ b/R/label.R @@ -1,17 +1,18 @@ #' @title Label -#' @description R6 class defining `text` and `font` of label +#' @description R6 class defining `text` and `font` of labels #' @export Label <- R6::R6Class( "Label", public = list( #' @description Create a new `Label` object. - #' @param text character text of the `Label` object - #' @param font `Font` object defining the font of the `Label` object - #' @param size numeric defining the size of the `Label` object - #' @param color character defining the color of the `Label` object - #' @param fontFamily character defining the font family of the `Label` object - #' @param fontFace character defining the font face of the `Label` object - #' @param angle numeric defining the angle of the `Label` object + #' @param text character text of the label + #' @param font `Font` object defining the font of the label + #' @param size numeric defining the size of the label + #' @param color character defining the color of the label + #' @param fontFamily character defining the font family of the label + #' @param fontFace character defining the font face of the label as defined in helper enum `FontFaces`. + #' @param angle numeric defining the angle of the label + #' @param align character defining the alignment of the label as defined in helper enum `Alignments`. #' @return A new `Label` object initialize = function(text = "", font = NULL, @@ -19,24 +20,44 @@ Label <- R6::R6Class( size = NULL, fontFace = NULL, fontFamily = NULL, - angle = NULL) { + angle = NULL, + align = NULL) { validateIsNumeric(c(as.numeric(angle), as.numeric(size)), nullAllowed = TRUE) - validateIsString(c(color, fontFace, fontFamily), nullAllowed = TRUE) + validateIsString(c(color, fontFamily), nullAllowed = TRUE) validateIsOfType(font, "Font", nullAllowed = TRUE) + validateIsIncluded(fontFace, FontFaces, nullAllowed = TRUE) + validateIsIncluded(align, Alignments, nullAllowed = TRUE) self$text <- text self$font <- font %||% Font$new() # If font properties are explicitely written, they will overwrite the properties of input Font - eval(parseVariableToObject("self$font", c("size", "color", "fontFace", "fontFamily", "angle"), keepIfNull = TRUE)) + eval(parseVariableToObject("self$font", c("size", "color", "fontFace", "fontFamily", "angle", "align"), keepIfNull = TRUE)) }, #' @description Create a `ggplot2::element_text` directly convertible by `ggplot2::theme`. + #' @param size numeric defining the size of the label + #' @param color character defining the color of the label + #' @param fontFamily character defining the font family of the label + #' @param fontFace character defining the font face of the label as defined in helper enum `FontFaces`. + #' @param angle numeric defining the angle of the label + #' @param align character defining the alignment of the label as defined in helper enum `Alignments`. #' @return An `element_text` or `element_blank`object. - createPlotFont = function() { - if (isOfLength(self$text, 0)) { + createPlotFont = function(color = NULL, + size = NULL, + fontFace = NULL, + fontFamily = NULL, + angle = NULL, + align = NULL) { + if (isEmpty(self$text)) { return(ggplot2::element_blank()) } - return(self$font$createPlotFont()) + return(self$font$createPlotFont( + color = color, + size = size, + fontFace = fontFace, + fontFamily = fontFamily, + angle = angle, + align = align)) } ), active = list( diff --git a/R/plotconfiguration-label.R b/R/plotconfiguration-label.R index ac663e23..77132378 100644 --- a/R/plotconfiguration-label.R +++ b/R/plotconfiguration-label.R @@ -57,7 +57,10 @@ LabelConfiguration <- R6::R6Class( return(private$.title) } validateIsOfType(value, c("character", "Label"), nullAllowed = TRUE) - private$.title <- asLabel(value) + if(isOfType(value, "Label")){ + private$.title <- asLabel(value) + } + private$.title <- asLabel(value, font = private$.title$font) return(invisible()) }, #' @field subtitle `Label` object defining the subtitle of the plot @@ -66,7 +69,10 @@ LabelConfiguration <- R6::R6Class( return(private$.subtitle) } validateIsOfType(value, c("character", "Label"), nullAllowed = TRUE) - private$.subtitle <- asLabel(value) + if(isOfType(value, "Label")){ + private$.subtitle <- asLabel(value) + } + private$.subtitle <- asLabel(value, font = private$.subtitle$font) return(invisible()) }, #' @field xlabel `Label` object defining the xlabel of the plot @@ -75,7 +81,10 @@ LabelConfiguration <- R6::R6Class( return(private$.xlabel) } validateIsOfType(value, c("character", "Label"), nullAllowed = TRUE) - private$.xlabel <- asLabel(value) + if(isOfType(value, "Label")){ + private$.xlabel <- asLabel(value) + } + private$.xlabel <- asLabel(value, font = private$.xlabel$font) return(invisible()) }, #' @field ylabel `Label` object defining the ylabel of the plot @@ -84,7 +93,10 @@ LabelConfiguration <- R6::R6Class( return(private$.ylabel) } validateIsOfType(value, c("character", "Label"), nullAllowed = TRUE) - private$.ylabel <- asLabel(value) + if(isOfType(value, "Label")){ + private$.ylabel <- asLabel(value) + } + private$.ylabel <- asLabel(value, font = private$.ylabel$font) return(invisible()) } ), diff --git a/R/plotconfiguration.R b/R/plotconfiguration.R index 88ff51fd..c7936950 100644 --- a/R/plotconfiguration.R +++ b/R/plotconfiguration.R @@ -30,7 +30,7 @@ PlotConfiguration <- R6::R6Class( #' @param panelArea `BackgroundElement` object defining properties of panel area #' @param xGrid `LineElement` object defining properties of x-grid background #' @param yGrid `LineElement` object defining properties of y-grid background - #' @param watermark `Label` object defining watermark + #' @param watermark character or `Label` object defining watermark #' @param export R6 class `ExportConfiguration` defining properties for saving/exporting plota #' @param name character defining the name of the file to be saved (without extension) #' @param format character defining the format of the file to be saved. diff --git a/R/themes.R b/R/themes.R index 86bf4213..56a29c7b 100644 --- a/R/themes.R +++ b/R/themes.R @@ -31,15 +31,16 @@ ThemeFont <- R6::R6Class( #' @param xlabel `Font` object or list for font properties of xlabel #' @param ylabel `Font` object or list for font properties of ylabel #' @param watermark `Font` object or list for font properties of watermark - #' @param legendTitle `Font` object or list for font properties of legend + #' @param legendTitle `Font` object or list for font properties of legend title #' @param legend `Font` object or list for font properties of legend #' @param xAxis `Font` object or list for font properties of xAxis #' @param yAxis `Font` object or list for font properties of yAxis - #' @param baseColor name of base color of undefined fonts. Default is black. + #' @param baseColor name of base color of undefined fonts. Default is "black". #' @param baseSize base size of undefined fonts. Default is 12. #' @param baseFace name of base face of undefined fonts. Default is "plain". #' @param baseFamily name of base family of undefined fonts. Default is "". #' @param baseAngle base angle of undefined fonts. Default is 0 degree. + #' @param baseAlign base alignment of undefined fonts. Default is "center". #' @return A new `ThemeFont` object initialize = function(title = NULL, subtitle = NULL, @@ -54,22 +55,26 @@ ThemeFont <- R6::R6Class( baseSize = 12, baseFace = "plain", baseFamily = "", - baseAngle = 0) { + baseAngle = 0, + baseAlign = "center") { # Validate necessary input validateIsString(baseColor) - validateIsString(baseFace) validateIsString(baseFamily) validateIsNumeric(baseSize) validateIsNumeric(baseAngle) + validateIsIncluded(baseFace, FontFaces) + validateIsIncluded(baseAlign, Alignments) # Create all field properties by parsing and evaluating their expression fieldNames <- c("title", "subtitle", "xlabel", "ylabel", "watermark", "legendTitle", "legend", "xAxis", "yAxis") - setFontExpression <- parse(text = paste0("self$", fieldNames, " <- Font$new( - color = ", fieldNames, "$color %||% baseColor, - size = ", fieldNames, "$size %||% baseSize, - fontFace = ", fieldNames, "$fontFace %||% baseFace, - fontFamily = ", fieldNames, "$fontFamily %||% baseFamily, - angle = ", fieldNames, "$angle %||% baseAngle)")) + setFontExpression <- parse(text = paste0( + "self$", fieldNames, " <- Font$new(", + "color = ", fieldNames, "$color %||% baseColor,", + "size = ", fieldNames, "$size %||% baseSize,", + "fontFace = ", fieldNames, "$fontFace %||% baseFace,", + "fontFamily = ", fieldNames, "$fontFamily %||% baseFamily,", + "angle = ", fieldNames, "$angle %||% baseAngle,", + "align = ", fieldNames, "$align %||% baseAlign)")) eval(setFontExpression) }, @@ -78,12 +83,14 @@ ThemeFont <- R6::R6Class( toJson = function() { jsonObject <- list() fieldNames <- c("title", "subtitle", "xlabel", "ylabel", "watermark", "legendTitle", "legend", "xAxis", "yAxis") - setJsonExpression <- parse(text = paste0("jsonObject$", fieldNames, " <- list( - color = self$", fieldNames, "$color, - size = self$", fieldNames, "$size, - angle = self$", fieldNames, "$angle, - fontFace = self$", fieldNames, "$fontFace, - fontFamily = self$", fieldNames, "$fontFamily)")) + setJsonExpression <- parse(text = paste0( + "jsonObject$", fieldNames, " <- list(", + "color = self$", fieldNames, "$color,", + "size = self$", fieldNames, "$size,", + "angle = self$", fieldNames, "$angle,", + "align = self$", fieldNames, "$align,", + "fontFace = self$", fieldNames, "$fontFace,", + "fontFamily = self$", fieldNames, "$fontFamily)")) eval(setJsonExpression) return(jsonObject) } diff --git a/man/AestheticProperties.Rd b/man/AestheticProperties.Rd index 4420974c..05fe415a 100644 --- a/man/AestheticProperties.Rd +++ b/man/AestheticProperties.Rd @@ -15,6 +15,8 @@ Enum of aesthetic property names of \code{ggplot2} } \seealso{ Other enum helpers: +\code{\link{Alignments}}, +\code{\link{FontFaces}}, \code{\link{LegendPositions}}, \code{\link{Linetypes}}, \code{\link{Scaling}}, diff --git a/man/Alignments.Rd b/man/Alignments.Rd new file mode 100644 index 00000000..10eb87c8 --- /dev/null +++ b/man/Alignments.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/font.R +\docType{data} +\name{Alignments} +\alias{Alignments} +\title{Alignments} +\format{ +An object of class \code{list} of length 3. +} +\usage{ +Alignments +} +\description{ +List of all available alignments/justifications for fonts +} +\seealso{ +Other enum helpers: +\code{\link{AestheticProperties}}, +\code{\link{FontFaces}}, +\code{\link{LegendPositions}}, +\code{\link{Linetypes}}, +\code{\link{Scaling}}, +\code{\link{Shapes}}, +\code{\link{tlfStatFunctions}} +} +\concept{enum helpers} +\keyword{datasets} diff --git a/man/Font.Rd b/man/Font.Rd index 870e00b3..4a1a2ea9 100644 --- a/man/Font.Rd +++ b/man/Font.Rd @@ -15,9 +15,11 @@ R6 class defining font properties \item{\code{fontFamily}}{character defining the family of font} -\item{\code{fontFace}}{character defining the face of font} +\item{\code{fontFace}}{character defining the font face as defined in helper enum \code{FontFaces}.} \item{\code{angle}}{numeric defining the angle of font} + +\item{\code{align}}{character defining the alignment of font as defined in helper enum \code{Alignments}.} } \if{html}{\out{}} } @@ -38,26 +40,29 @@ Default font properties are defined directly in the object field, so \code{NULL} input is allowed will lead to default properties. \subsection{Usage}{ \if{html}{\out{