saezlab / MetaProViz

R-package to perform metabolomics pre-processing, differential metabolite analysis, metabolite clustering and custom visualisations.
https://saezlab.github.io/MetaProViz/
GNU General Public License v3.0
8 stars 0 forks source link

Pre-3.5.0 ggplot2 has its `draw_key_text` method overridden and attempts to call a non-available function `replace_null` #81

Open ChristinaSchmidt1 opened 1 month ago

ChristinaSchmidt1 commented 1 month ago

It seems we somehow have a dependency on roomba. Users with R version 4.4.1 get the Error message:

Error in replace_null(unclass(data), label = "a", angle = 0) : 
 unused arguments (label = "a", angle = 0)

This happens in EstimatePool function and PreProcessing function, both located in Processing.R file

ChristinaSchmidt1 commented 2 weeks ago

@deeenes this is what we just discussed in regard to the version issue.

deeenes commented 6 days ago

The replace_null function has been introduced in ggplot2 3.5.0 (23 Feb 2024). ggplot2 3.4.4 calls the draw_key_* functions (each geom has its own) in its guide_gengrob.legend function. Printing the code of the called draw_key_* functions there, we know that the offending line is

data <- replace_null(unclass(data), label = "a", angle = 0)

Searching for the pattern replace_null(unclass(data) in GitHub, it finds only ggpp. Searching for replace_null in GitHub, it finds many packages, because apparently this is a popular name for mostly internal helper functions. However, none of these results seem relevant. Searching the code of all functions from all loaded packages in the R session where the error is reproduced results finds nothing, meaning that none of these contain "replace_null" in their code. The draw_key_* functions are selected in the ggplot2:::set_draw_key function (layer.R). This function uses match.fun to access the draw_key_* function by its name, however, if no name is available, it simply returns the geom. When the error is observed, no such selection happens, hence the draw_key_* functions are added to the geoms earlier or later than the ggplot2:::set_draw_key function, and possibly by another package.

The error itself might be related to other packages operating on ggplot internals, one candidate is factoextra, however, this package hasn't been updated in the past 4 years (https://github.com/cran/factoextra), and I couldn't find any related code in it. There are very few posts about the same error, this one points to factoextra https://stackoverflow.com/questions/78233888/problems-with-repel-in-fviz-cluster-in-factoextra-package-in-r but ggrepel is also a candidate. But that one too, doesn't have a release since ggplot2 3.5.0 (https://cran.r-project.org/src/contrib/Archive/ggrepel/). The answer suggests changing the geom, which addresses the error by not calling the draw_key_* function for geom_text. Another report of this error is here https://md.vern.cc/@mihelac.lorena/ok-created-the-variable-766274ea1fa7, it is from a code block using geom_text_repel (which is supposed to use draw_key_text for its legend).

Traceback of the original error:

[ins] r$> PoolData <- MetaProViz::ToyData(name="IntraCells_Raw")

[ins] r$> Pool_Estimation_result <- MetaProViz::PoolEstimation(
    InputData = PoolData[,-c(1:3)],
    SettingsFile_Sample = PoolData[,c(1:3)],
    SettingsInfo = c(PoolSamples = 'Pool', Conditions = 'Conditions'),
    CutoffCV = 100
)

Error in replace_null(unclass(data), label = "a", angle = 0) :
  could not find function "replace_null"

[ins] r$> traceback()

18: draw_key(...)
17: g$draw_key(g$data[i, , drop = FALSE], g$params, key_size)
16: FUN(X[[i]], ...)
15: lapply(guide$geoms, function(g) {
        g$draw_key(g$data[i, , drop = FALSE], g$params, key_size)
    })
14: FUN(X[[i]], ...)
13: lapply(seq_len(nbreak), draw_key)
12: unlist(lapply(seq_len(nbreak), draw_key), recursive = FALSE)
11: guide_gengrob.legend(X[[i]], ...)
10: FUN(X[[i]], ...)
9: lapply(gdefs, guide_gengrob, theme)
8: guides_gengrob(gdefs, theme)
7: build_guides(plot$scales, plot$layers, plot$mapping, position,
       theme, plot$guides, plot$labels)
6: ggplot_gtable.ggplot_built(ggplot_build(x))
5: ggplot_gtable(ggplot_build(x))
4: ggplot2::ggplotGrob(InputPlot) at VizPCA.R#288
3: MetaProViz:::PlotGrob_PCA(InputPlot = PCA, SettingsInfo = SettingsInfo,
       PlotName = PlotName) at VizPCA.R#246
2: MetaProViz::VizPCA(InputData = pca_data %>% select(-all_of(SettingsInfo[["Conditions"]]),
       -Sample_type), SettingsInfo = c(color = "Sample_type"), SettingsFile_Sample = pca_data,
       PlotName = "QC Pool samples", SaveAs_Plot = NULL) at Processing.R#489
1: MetaProViz::PoolEstimation(InputData = PoolData[, -c(1:3)], SettingsFile_Sample = PoolData[,
       c(1:3)], SettingsInfo = c(PoolSamples = "Pool", Conditions = "Conditions"),
       CutoffCV = 100)

Top of the above traceback (which means bottom of the stack), the draw_key(...) function looks like this:

[1] "Call to draw_key:"
<ggproto method>
  <Wrapper function>
    function (...)
draw_key(...)

  <Inner function (f)>
    function (data, params, size)
{
    data <- replace_null(unclass(data), label = "a", angle = 0)
    hjust <- compute_just(data$hjust %||% 0.5)
    vjust <- compute_just(data$vjust %||% 0.5)
    just <- rotate_just(data$angle, hjust, vjust)
    grob <- titleGrob(data$label, x = unit(just$hjust, "npc"),
        y = unit(just$vjust, "npc"), angle = data$angle, hjust = hjust,
        vjust = vjust, gp = gpar(col = alpha(data$colour %||%
            data$fill %||% "black", data$alpha), fontfamily = data$family %||%
            "", fontface = data$fontface %||% 1, fontsize = (data$size %||%
            3.88) * .pt), margin = margin(0.1, 0.1, 0.1, 0.1,
            unit = "lines"), margin_x = TRUE, margin_y = TRUE)
    attr(grob, "width") <- convertWidth(grobWidth(grob), "cm",
        valueOnly = TRUE)
    attr(grob, "height") <- convertHeight(grobHeight(grob), "cm",
        valueOnly = TRUE)
    grob
}<environment: 0x71c674f9ee8>

The code actually fully identical to draw_key_text in ggplot2 3.5.0. At the same time, ggplot2:::draw_key_text still has the old code (ggplot2 3.4.4 loaded). It means the code has to come from another package.

I searched the code of all functions and S3/S4 methods in all loaded packages using this snippet, and could not find the name replace_null (except tidyr:::list_replace_null, which is not relevant here).