--- title: "Create an svg file with benjamini leaves" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Create an svg file with benjamini leaves} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", message = FALSE ) ``` Let's have a look how we can be generate svg files with benjamini leaves. First we'll load some libraries. ```{r setup, message=FALSE} library(ggbenjamini) library(dplyr) library(purrr) library(tidyr) library(ggplot2) library(stringr) library(minisvg) library(prismatic) set.seed(21) ``` We'll use the package example dataframe `df_bezier_skeleton` with the bezier paths of a "hand drawn" (with inkscape) svg file ressembling the skeleton a of a plant like structure (see `vignette("import_svg_bezier")` if you're interested how to import svg file beziers) and directly grow leaves on these "branches": ```{r} df_branches_and_leaves <- df_bezier_skeleton %>% group_by(i_branch) %>% summarise(benjamini_branch( df_branch = tibble(x, y), leaf_size_multiplicator = 0.5, leaf_mean_dist_approx = 20, leaf_angle_dist = spark_norm(mean = 0, sd = 15) )) ``` Now we can add columns `path_str` with this "d" element and furthermore, we'll define different `fill_color`s for the varyous types of `element`s and transform these to svg path strings: ```{r} get_svg_bezier_string <- function(bezier_df) { bezier_df %>% group_by(i_part) %>% slice(-1) %>% summarise(cb = paste(x, y, sep = ",", collapse = " ")) %>% pull(cb) %>% paste("C", ., collapse = " ") %>% # paste("Z") %>% paste0("M ", bezier_df$x[1], ",", bezier_df$y[1], " ", .) } ``` ```{r} size <- 640 pal <- c( "#faff5a", "#b65151", "#de9602", "#ff980b", "#fdd021", "#5c9e3f", "#fef266", "#925e16" ) palhex <- scales::gradient_n_pal(colours = pal) coord_intervals_lengths <- df_branches_and_leaves %>% ungroup()%>% summarise( x = range(x) %>% {.[2] - .[1]}, y = range(y) %>% {.[2] - .[1]} ) df_svg <- df_branches_and_leaves %>% mutate( x = x * size / coord_intervals_lengths[["x"]], y = y * size / coord_intervals_lengths[["y"]] ) %>% group_by(i_branch, i_leaf, element) %>% summarise(path_str = get_svg_bezier_string(tibble(x, y, i_part))) %>% mutate(fill_color = case_when( element == "half 1" ~ "url(#RadialGradient3)", element == "half 2" ~ "url(#RadialGradient4)", element == "stalk" ~ "sandybrown", element == "branch" ~ "brown" )) %>% group_by(i_branch, i_leaf) %>% # We'll define some alchemist random distribution for the color scale later: mutate( fill_var = 6 * as.numeric(i_branch) + i_leaf + sample(1:10, 1, TRUE) ) %>% ungroup() %>% mutate(hex = palhex(fill_var / max(fill_var))) %>% mutate( fill_gradient = factor(hex) %>% as.numeric() %>% paste0("url(#gradient", ., ")") ) df_svg ``` ```{r} # define gradients range_of_values <- range(df_svg$fill_var) hex_needed <- df_svg %>% transmute( fill_var = fill_var - min(fill_var), fill_var = fill_var / max(fill_var), hex = palhex(fill_var) ) %>% pull(hex) %>% unique() ``` We're ready to create our minisvg document: ```{r} doc <- SVGDocument$new(width = size, height = size) ``` In order to have some more realistic texture, we'll define gradients for the leaves: ```{r} append_gradient_def <- function( doc, id, col1 = "#00FF00", col2 = "#008000" ) { doc$append( stag$radialGradient( id = id, cx="0.35", cy="0.63", r="0.7", stag$stop(offset = "0%", stop_color = col1), stag$stop(offset = "100%", stop_color = col2) ) ) doc } hex_needed %>% iwalk( ~append_gradient_def( doc, paste0("gradient", .y), .x, clr_darken(.x) ) ) ``` ...and append them to the document: ```{r} # doc$append(gradients) ``` Here we define helper functions to append pathes as polygons or lines to the svg: ```{r} append_polygon <- function(doc, path_str, fill_color) { doc$append( stag$path( d = path_str, fill=fill_color, # stroke_width = "0.5", stroke="none", fill_opacity="1" ) ) } append_line <- function(doc, path_str, fill_color) { doc$append( stag$path( d = path_str, stroke_width = "2", fill = "none", stroke_linecap="round", stroke=fill_color ) ) } append_element <- function(type, path_str, fill_color) { switch ( type, "half 1" = , "half 2" = append_polygon(doc, path_str, fill_color), "branch" = , "stalk" = append_line(doc, path_str, fill_color) ) } ``` Now we can finally append the branches with leaves to the svg: ```{r} pwalk(list( df_svg$element, df_svg$path_str, df_svg$fill_gradient ), function(x, y, z) append_element(x, y, z) ) ``` Et voilĂ  ```{r, eval=FALSE} doc$show() ``` ```{r, echo=FALSE} doc$save("svg_vignette_output.svg") rsvg::rsvg_png("svg_vignette_output.svg", "svg_vignette_output.png") knitr::include_graphics("svg_vignette_output.png") ```