Open nmpeterson opened 3 years ago
I was thinking about this recently. The vast majority of the code in the finalize_plot
function is related to vetting arguments, measuring and creating grobs, and doing the drawing and saving. With just a few exceptions, finalize spends most of it's time in the grid package and other related packages -- not in ggplot. Therefore, I think the best course of action here is going to be to integrate support for non-ggplot objects directly into finalize_plot
.
I believe only three sections of finalize currently presume the plot
object to be a ggplot:
Get last plot if plot = NULL
:
# Seek last plot if user did not specify one
if (is.null(plot)) {
plot <- ggplot2::last_plot()
}
Extract title and caption from underlying plot:
# If title/caption unspecified, try to extract from plot (unless the user has
# specified that this should not be inherited using the `inherit` argument)
input_title <- plot$labels$title
if (title == "" & !is.null(input_title) & inherit_t) {
title <- input_title
}
input_caption <- plot$labels$caption
if (caption == "" & !is.null(input_caption) & inherit_c) {
caption <- input_caption
}
Most significantly, the prepare_plot()
subfunction. At its most basic level, this function takes in a ggplot object, modifies it, and returns a grob via ggplotGrob()
.
#' Sub-fn to create plot grob, including legend-realignment
#' @noRd
prepare_plot <- function(plot,
consts,
overrides,
legend_shift,
debug,
use_cmap_aes,
...) {
Addressing the first two would be fairly trivial.
Seems to me that the best way to tackle this enhancement will to build other prepare_plot
-like subfunctions. This could involve a general prepare_map()
function, or might necessitate one function per object type, e.g. prepare_mapsf()
and prepare_tmap()
. Each function would perform any necessary modification (e.g. theme changes, legend adjustments) based on some TBD template before returning the plot as a grob.
In my mind, implementing support for other packages seems dependent on the ability to easily convert these objects to grobs for drawing with grid. This should be easy for tmaps due to tmap::tmap_grob()
. I'm not seeing anything obvious within the mapsf package, but I haven't explored yet. mapsf objects may already be grob-compatible, or there may be something we can borrow from the mapsf::mf_export()
function.
I am curious if we'll want map-equivalents of theme_cmap()
as well, in order to fully support these other packages.
Assuming we support tmap, I imagine at the very least it would be useful to create a tm_layout_cmap()
function, which could just be a wrapper of tmap::tm_layout()
that supplies CMAP-default values for several of the arguments.
right. Maybe it makes sense to start by supporting just one map package and implement both theming and a modified finalize_plot together. I wonder if there is interest in supporting ggplot2 maps, as you referenced in the OP? That would throw in a bit of a monkey wrench, as it might require an independent ggplot2 theme function distinct from the current theme_cmap
.
One of the longer-term goals for cmapplot is to support maps instead of just charts. While the
finalize_plot()
function can be used for ggplot-based maps as currently coded (see example PDF), this layout has not been reviewed by Comms, and certainly does not match the ON TO 2050 map design templates (which may or may not still be Comms' preferred layout). ON TO 2050 templates and documentation are located in S:\Library\edocuments\Communications\MAP templatesWhile the ability to support map packages beyond
ggplot2::geom_sf()
is an eventual goal, it seems like a near-term improvement would be to add either alayout="map"
parameter tofinalize_plot()
or to create a separatefinalize_map()
function. I have not given much thought yet to pros/cons either way. Whatever we do, we should be reasonably certain up front that it will play nicely with output from different map packages (ggplot, tmap, mapsf).