Here you will learn how to visualize the structure and the topology of many panicles with a loop.

There are many ways to achieve this, hereby we provide some ideas on how to do it. Feel free to modify and improve the workflow that we propose. Feel free also to suggest us how to improve this workflow, to do so, contact us through issues and pull requests.

setup

library(ptrapr)
library(magrittr)
library(stringr)
library(purrr)
library(ggraph)
library(ggplot2)
library(cowplot)

Place All files in one single folder

Place the structure files (.ricepr) and their corresponding grain files (ricegr) of all the panicles that you want to analyze in one single folder. For every single panicle the name of the .ricepr file and the name of the .ricegr file must be exactly the same (obviously beside the extension).

That folder must contain nothing else.

For all the files stored in one folder, we prepare their paths in a list in this way:

# First store the path to your folder
# in a variable called path_to_folder.
# substitute "path/to/folder", with the path to your folder!

path_to_folder <- "path/to/folder"
# First record the names of all the files,
panicle_paths <- 
  list.files(path_to_folder) %>%
  # remove the extension,
  # (each panicle has two files with different extension)
  str_remove(".ricegr|.ricepr") %>%
  # store the name of the files without the extension
  unique()

panicle_paths
## [1] "1_1_6307" "1_2_6308" "1_3_6309" "2_1_6310" "2_2_6311" "2_3_6312"
## [7] "3_1_6313" "3_2_6314" "3_3_6315"

We find it very useful to store the panicle names in a named object (such a named character vector). Because the function map, that we will use to loop over this object, maintains the names of the object in its output. In this way we keep track of the panicle IDs during the loops.

Here we create a named object using a magrittr trick: we use the curly brackets {} to pass the LHS (left hand side) argument to the RHS (right hand side) of the pipe anywhere we want it as a dot .. To do this, we enclose the RHS function in curly brackets and call the LHS with a dot “.”.

# Store file names in named object, to use them later
panicle_paths <-
  panicle_paths %>% 
  {set_names(x = paste(path_to_folder, ., sep = "/"), nm = .)}

Now the object panicle_paths stores the paths to all the panicles in a named object.

panicle_paths
## 1_1_6307 
## ptrapr/extdata/1_1_6307" 
## 1_2_6308 
## ptrapr/extdata/1_2_6308" 
## 1_3_6309 
## ptrapr/extdata/1_3_6309" 
## 2_1_6310 
## ptrapr/extdata/2_1_6310" 
## 2_2_6311 
## ptrapr/extdata/2_2_6311" 
## 2_3_6312 
## ptrapr/extdata/2_3_6312" 
## 3_1_6313 
## ptrapr/extdata/3_1_6313" 
## 3_2_6314 
## ptrapr/extdata/3_2_6314" 
## 3_3_6315 
## ptrapr/extdata/3_3_6315"

Parse All Panicles

Afterwards, you can loop the main workflow on the named object panicle_paths with map(). This function from the package purrr is convenient because it loops over r objects preserving their names.

Here we show you how build loops over the functions of ptrapr one by one.

First parse and load all the files with read_full_panicle().

# Parse them in a list, using file name as list names
panicle_list <- 
  panicle_paths %>%
  map(~read_full_panicle(.)) 

# alternative
# panicle_list <- 
#   panicle_paths %>%
#   map(~read_full_panicle(
#     pr_file = paste0(., ".ricepr"), 
#     gr_file = paste0(., ".ricegr"))
#     ) 

Then correct the edges on the main axis with invert_edges()

panicle_list <- 
  panicle_list %>% 
  map(~invert_edges(., check_before = TRUE))

As you can see, map() preserves the names of panicle_list.

names(panicle_list)
## [1] "1_1_6307" "1_2_6308" "1_3_6309" "2_1_6310" "2_2_6311" "2_3_6312"
## [7] "3_1_6313" "3_2_6314" "3_3_6315"

Plot All the Panicles

In this last part we show you how to combine two kind of plots:

  • a panicle_plot() that displays the architecture and structure of the panicle,
  • and a panicle_tileplot() that focuses on the topology of branching.

You can combine plots in many ways. Hereby we use the package cowplot.

Although we provide the plotting functions panicle_plot() and panicle_tileplot(), which are based on ggplot2 and ggraph, we suggest you that you design your own plotting functions, because only this way you’ll achieve the versatility required for exploratory data analysis. You can learn how to design your own plotting functions in the previous vignettes.

How to wrap iterate over multiple plot functions

So, we want to wrap panicle_plot() and panicle_tileplot()into another function, to plot together different panicle visualizations, and we want to loop that wrapper over a list of panicle using the name of the panicle file of as title of the plots.

To use the name as title, you will have to loop over the names of panicle_list instead of the list itself.

(If you want to master details and quirks of loops and iteration in R, you can learn about them in here).

This might be the most difficult part. We draft a the plot_both() function, that returns a plot (grob) list. and we feed that list to cowplot.

plot_both <- function(panicle_name,
                      p_list = panicle_list)
{
  # extract a panicle by name
  panicle <- p_list[[panicle_name]]
  
  # plot the structure
  panicle_structure_plot <-
    panicle %>%
    plot_panicle() + 
    # place the title over the first plot
    ggtitle(panicle_name)
  
  # plot the topology
  panicle_topology_plot <- 
    panicle %>% 
    panicle_tibble(.) %>%
    panicle_tileplot2() 
    
  panicle %>%
  {list(panicle_structure_plot %>%
          ggplotGrob(),
        panicle_topology_plot %>%
          ggplotGrob())}
}

This is the final loop, that plots everything directly in a multipage pdf object.

pdf("test-panicle-plots.pdf", width = 8, height = 12)

panicle_list %>%
  # loop over names, so that they can be used as plot titles
  names() %>%
  map(plot_both) %>% 
  map(~cowplot::plot_grid(plotlist = .,
                          nrow = 2)) %>%
    print()

dev.off()