Git Product home page Git Product logo

Comments (10)

clauswilke avatar clauswilke commented on May 25, 2024 1

You need to learn how to make minimal reproducible examples. Here, I'll give you a starting point, but you'll have to take it from here. I'm not going to read your package code or install your package or look at an example that is more than maybe 30-40 lines of code total.

library(tidyverse) 

data <- tibble(
  x = 1:3,
  y = 3:1,
  a = factor(c("A", "A", "B"), levels = c("A", "B", "C"))
)

# green dot is missing from legend
ggplot(data, aes(x, y, color = a)) +
  geom_point() +
  scale_color_manual(
    values = c(A = "red", B = "blue", C = "green")
  )

# green dot is present
ggplot(data, aes(x, y, color = a)) +
  geom_point(show.legend = TRUE) +
  scale_color_manual(
    values = c(A = "red", B = "blue", C = "green"),
    drop = FALSE
  )

Created on 2024-03-27 with reprex v2.0.2

from ggplot2.

clauswilke avatar clauswilke commented on May 25, 2024 1

Would it be a problem to just set show.legend = TRUE in the functions that generate p1 and p2?

Alternatively, you could possibly code something like the following. You may have to iterate over all layers and make sure you're actually modifying geom_point() layers only.

library(tidyverse) 

data <- tibble(
  x = 1:3,
  y = 3:1,
  a = factor(c("A", "A", "B"), levels = c("A", "B", "C"))
)

# green dot is missing from legend
p <- ggplot(data, aes(x, y, color = a)) +
  geom_point() +
  scale_color_manual(
    values = c(A = "red", B = "blue", C = "green"),
    drop = FALSE
  )
p

# turn on green dot after the fact
p$layers[[1]]$show.legend <- TRUE
p

Created on 2024-03-27 with reprex v2.0.2

from ggplot2.

clauswilke avatar clauswilke commented on May 25, 2024

Could you please create a minimal reproducible example of the exact behavior that is causing you problems? Just draw up a simple plot with one or more legends that don't look the way you'd think they should.

from ggplot2.

teunbrand avatar teunbrand commented on May 25, 2024

This all sounds very similar to #5728. TL;DR: Dropping key glyphs is intended, to include a layer's key glyph in the legend without the data being present, use show.legend = TRUE.

from ggplot2.

samuel-marsh avatar samuel-marsh commented on May 25, 2024

@teunbrand @clauswilke
Thanks both for quick replies!!

Indeed it does sound like that previous issue. However, in my case the base plot is being returned from another package as ggplot2 object. So can't pass the show.legend = TRUE in original geom_point call. What is the best (or least hacky maybe) was to pass this parameter when modifying that original plot?

Best,
Sam

from ggplot2.

clauswilke avatar clauswilke commented on May 25, 2024

Again, please provide a minimal example that accurately represents your situation (maybe with a function that takes the plot object as input) so we can look into it and explore approaches.

from ggplot2.

samuel-marsh avatar samuel-marsh commented on May 25, 2024

Hi @clauswilke,

Working on re-creating essential aspects of functions without such heavy package dependencies. Working on recreating all the modifications that the original package does to the plot correctly and then how my function modifies that returned plot. Might be tomorrow before I can complete that but working on it.

I realize this isn't exactly minimal example because it's dependency heavy but in case it's help the full issue below does show the issue (requires Seurat; heavy dep).

Uses these two Seurat functions:
DimPlot
SingleDimPlot

Then modified by function in my package scCustomize:
DimPlot_scCustom

This section in particular is modifying the color levels of the plot generated by Seurat:
https://github.com/samuel-marsh/scCustomize/blob/fc7a282af3bef6e1cb816fac3b9229f536159238/R/Seurat_Plotting.R#L1892-L1935

# ggplot 3.5.0
install.packages("Seurat")
install.packages("scCustomize")

# plot with all levels present in both plots
DimPlot_scCustom(seurat_object = pbmc, split.by = "treatment")

# create subset without one level
data <- FetchData(object = pbmc, vars = c("treatment", "seurat_annotations"))

cells_remove <- data %>% 
  filter(treatment == "Treatment1" & seurat_annotations == "Naive CD4 T") %>% 
  rownames()


pbmc_subbed <- subset(pbmc, cells = cells_remove, invert = TRUE)

DimPlot_scCustom(seurat_object = pbmc_subbed, split.by = "treatment")

image

Running same thing with ggplot2 3.4.4 results in:
image

Again I realize this is the heavy version for sure and working on more minimal example that maintains plots correctly.

Thanks so much again for the quick replies!!
Best,
Sam

from ggplot2.

teunbrand avatar teunbrand commented on May 25, 2024

I'd also like to note that using facetting instead of plot composition might circumvent the issue altoghether. From my reading of the problem, both plots share the same layers, coordinates and colour scales so that should lend itself to facetting.

Another solution might be to 'cut the middleman' and construct plots de novo instead of wrapping plotting functions that wrap ggplot2. I'd find it very strange if Seurat doesn't provide accessors to wrangle the relevant data out of their data structures.

from ggplot2.

samuel-marsh avatar samuel-marsh commented on May 25, 2024

Hi @clauswilke,

Yes, I know how to make reproducible example, but as I mentioned was trying to ensure that example mirrored what was happening in original function in terms of how plot is output and was providing the heavy version in case it was helpful while I was working on reprex. I will need to check this vs. original function, ut the simplest version would be this:

library(ggplot2)
library(patchwork)

# Dummy data
data_plot <- data.frame(
  UMAP1 = c(-4.232792, -4.892886, -5.508639, 11.332233, -7.450703),
  UMAP2 = c(-4.152139, 10.985685, -7.211088, 3.161727, 1.092022),
  group = factor(c("Group1", "Group2", "Group1", "Group1", "Group2")),
  treatment = factor(c("treat1", "treat1", "treat1", "treat1", "treat2"))
)

rownames(data_plot) <- paste0("A", seq_len(5))

# colors to use
colors <- c("blue", "red")
names(colors) <- unique(data_plot$group)

# plot without subsetting data by treatment
ggplot(data_plot, aes(x = UMAP1, y = UMAP2, color = group)) + 
  geom_point() +
  scale_color_manual(values = colors, drop = FALSE)

# get rownames of subsets
treat1_cells <- paste0("A", seq_len(4))
treat2_cells <- "A5"

# subset the data
data_plot_treat1 <- data_plot[treat1_cells, ]
data_plot_treat2 <- data_plot[treat2_cells, ]


# plot the subsets
p1 <- ggplot(data_plot_treat1, aes(x = UMAP1, y = UMAP2, color = group)) + 
  geom_point()

p2 <- ggplot(data_plot_treat2, aes(x = UMAP1, y = UMAP2, color = group)) + 
  geom_point() 

# HERE is where my package comes in
# p1 nd p2 are returned from Seurat
# Then modified and wrapped by my package

p1_mod <- p1 + scale_color_manual(values = colors, drop = FALSE)
p2_mod <- p2 + scale_color_manual(values = colors, drop = FALSE)

plots <- wrap_plots(p1_mod, p2_mod) + plot_layout(guides = "collect")
plots

Created on 2024-03-27 with reprex v2.1.0

@teunbrand Seurat does have accessors to pull the required data out and make plot de novo. However, as goal of this particular is to extend the functionality of a Seurat function it was easier to use the output of that function. That way if there are changes in Seurat that effect function (structure of Seurat object changes, new parameters, bug fixes, etc) they are already present without having to keep as close an eye on the codebase if I was plotting de novo. Using patchwork for assembly worked best at time but I can see if faceting them could work here.

Best,
Sam

from ggplot2.

samuel-marsh avatar samuel-marsh commented on May 25, 2024

Hi @clauswilke,

Yes, I think I will put PR in to Seurat to add that to the base code for the function in question.

Thanks for the example with modifying the layers in output. I'll play around with that and faceting in the short-term until PR can be approved.

Thank you both @clauswilke and @teunbrand again for your help with this, I really appreciate it!!

Best,
Sam

from ggplot2.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.