davidgohel / rvg

https://davidgohel.github.io/rvg/
132 stars 15 forks source link

transparent holes #50

Closed davidgohel closed 1 year ago

davidgohel commented 1 year ago
    Hey  

I'm not sure if this is the same bug brought by @MRMHmdeleeuw, but dml seems to do an excellent job creating forms for transparent holes on imported SVG, but seems to be ignoring 'bg' color when filling these transparent spaces. I tried with no success reviewing your C++ magic.

Here's a not-so-minimal reprex based on this question.

library(tidyverse)
library(tools)
library(rsvg)
library(grImport2)
library(grid)
library(rvg)
library(officer)

streaming <- tibble::tribble(
  ~service, ~`2020`, ~`2021`,
  "netflix",    29, 20,
  "prime",      21, 16,
  "hulu",       16, 13,
  "disney",     12, 11,
  "apple",       4,  5,
  "peacock",     0,  5,
  "hbo",         3, 12) %>%
  tidyr::pivot_longer(cols = -service, 
                      names_to = "year", 
                      values_to = "share")

## plot the years side-by-side in the original order
p <- ggplot(streaming) + 
  geom_col(aes(factor(service, levels = unique(service)), 
               share, fill = year), position = position_dodge(width = 0.9)) + 
  ## add a hidden set of points to make the legend circles easily
  geom_point(aes(x = service, y = -1, color = year, fill = year), size = 4) + 
  ## add the percentages just above each bar
  geom_text(aes(service, share + 1, label = paste0(share, "%"), group = year),
            position = position_dodge(width = 0.9), size = 3) +
  ## use similar colours to the original
  scale_fill_manual(values = c(`2020` = "red3", `2021` = "black")) +
  scale_color_manual(values = c(`2020` = "red3", `2021` = "black")) + 
  ## hide the fill legend and make the color legend horizontal
  guides(fill = "none", color = guide_legend(direction = "horizontal")) +
  scale_y_continuous(labels = scales::percent_format(scale = 1), 
                     limits = c(0, 35)
                     ) +
  labs(x = NULL, y = NULL) +
  theme_minimal() + 
  theme(plot.background = element_rect(fill = "white", size = 0),
        legend.title = element_blank(),
        legend.text= element_text(size = 12),
        panel.grid = element_blank(),
        ## move the color legend to an inset 
        legend.position = c(0.85, 0.8))

# Convert Chart to Grob
p_grob <- ggplotGrob(p)

# Find X-Axis labels Position
p_grob_xpos <- p_grob$grobs[[grep("axis-b", p_grob$layout$name)]]$children$axis$grobs$`1`$children[[1]]$x
rm(p_grob)

# Logos Location
tmpdir <- tempdir()
wiki <- "https://upload.wikimedia.org/wikipedia/commons/"
logos <- tibble::tribble(
  ~service, ~logo,
  "netflix", paste0(wiki, "0/08/Netflix_2015_logo.svg"),
  "prime", paste0(wiki, "1/11/Amazon_Prime_Video_logo.svg"),
  "hulu", paste0(wiki, "e/e4/Hulu_Logo.svg"),
  "disney", paste0(wiki, "3/3e/Disney%2B_logo.svg"),
  "apple",  paste0(wiki, "2/28/Apple_TV_Plus_Logo.svg"),
  "peacock", paste0(wiki, "d/d3/NBCUniversal_Peacock_Logo.svg"),
  "hbo", paste0(wiki, "d/de/HBO_logo.svg")) %>% 
  mutate(path = file.path(tmpdir, paste(service, tools::file_ext(logo), sep = ".")))

# Download svg files and convert to Cairo SVG
purrr::map2(logos$logo, logos$path,
            ~rsvg::rsvg_svg(.x, file = .y, width = 512))

# Load Cairo SVG as Picture objects
logos <- map(logos$path, grImport2::readPicture)

# Import Labels as Grob and convert to grobTree
logos <- do.call("grobTree", Map(grImport2::symbolsGrob, logos, x=p_grob_xpos, y=0, size = unit(0.2, "snpc")))

# Replace text labels by logos
p_labelled <-  p + annotation_custom(logos) + 
  coord_cartesian(clip = 'off') +
  theme(axis.text.x = element_blank(),
        plot.margin=unit(c(0.01,0.01,0.05,0.01), "npc"),
        plot.background = element_rect(fill="white", color = NA))

# Transform chart into DrawingML so it is loaded as vectors
p_labelled_dml <- rvg::dml(ggobj = p_labelled, bg="white")

# Create PPT
read_pptx() %>% 
  add_slide(layout = "Title and Content", master = "Office Theme") %>% 
  ph_with(value = "US Streaming Market Share", location = ph_location_type(type = "title")) %>% 
  ph_with(value = p_labelled_dml, location = ph_location_type(type = "body")) %>%
  ph_with(value = "Source: Ampere Analytics via The Wrap", location = ph_location_type(type = "ftr")) %>% 
  print(target = "test.pptx")

_Originally posted by @flaviorbs in https://github.com/davidgohel/officedown/issues/95

davidgohel commented 1 year ago

Hello @flaviorbs

The problem here is geometries provided by MS does not allow transparent holes. This is not SVG unfortunately and this is out of my control (I may be wrong but I can't find anything about polygons with holes).