Skip to content

Solution to e_facet() #396

Closed
Closed
@robert-koetsier

Description

@robert-koetsier

Hi John,

I've been enjoying using echarts4r. Recently, I wanted to show multiple plots in a grid, essentially what facet_wrap() would do for ggplot2. I noticed the unfinished version of the e_facet() function, and decided to turn it into a working version. I used the system that you describe here: Grid & Axis. My solution for e_facet() is working, but I did not check how it interacts with all other options for customization that echarts4r has to offer. Additionally, some tweaking for robustness and ease of use (e.g. by adding more parameter options) may be required.

I'm yet unfamiliar with the pull requests system, so I'll share my solution here. For now, I'm discontinuing my efforts, I hope the code can be of use for someone else:

e_facet <- function(e, rows = 1, cols = 1, legend_pos="top", legend_space = 10) {

  # number of series
  nseries <- length(e$x$opts$series)
  

  # Spacing options ---------------------------------------------------------
  # Extra room for axis labels
  # Possibly interesting as additional parameters, maybe reformat as a single vector.
  lab_space_left <- 5      # Space for axis labels
  lab_space_top <- 2   
  lab_space_bottom <- 5   
  lab_space_right <- 2   
  

  # Calculate spacings ------------------------------------------------------

  # introduce some spacing between panels for low dimensional grids
  v_facet_space = if (rows < 10) 10 - rows else 0       
  h_facet_space = if (cols < 10) 10 - cols else 0       
  # an option to overwrite the space between panels with another parameter for 
  #   for the e_facet function may be interesting.
  
  
  # Maximum space for facets (depends on legend position, and space for axis labels)
  if(legend_pos %in% c("top", "bottom")){
    w_max <- 100 - lab_space_left - lab_space_right
    h_max <- 100 - legend_space - lab_space_bottom - lab_space_top
  }else if(legend_pos %in% c("left", "right")){
    w_max <- 100 - legend_space - lab_space_left - lab_space_right
    h_max <- 100 - lab_space_bottom -lab_space_top
  }else{
    w_max <- 100 - lab_space_left - lab_space_right
    h_max <- 100 - lab_space_bottom - lab_space_top
  }

  # Total space for facets, taking between-panel spacing, legend space, and
  #   extra space for axis labels into account
  rows_h_max <- h_max - (v_facet_space * (rows-1)) 
  cols_w_max <- w_max - (h_facet_space * (cols-1))
  
  # Dimensions of each panel
  height <- rows_h_max / rows
  width <- cols_w_max / cols
  

  # Panel positions ---------------------------------------------------------
  
  # Offset only when legend is left or top
  top_offset <- 0
  left_offset <- 0
  if (legend_pos == "top") {
    top_offset <- legend_space
  }
  if (legend_pos == "left") {
    left_offset <- legend_space
  }
  
  # Generate a vector for positions from the top
  top_pos_values <- sapply(1:rows, function(x){
    lab_space_top + top_offset + ((x-1) * (height + v_facet_space))
  })
  top_positions <- rep(top_pos_values, each=cols)[1:nseries]
  
  # Generate a vector for positions from the left
  left_pos_values <- sapply(1:cols, function(x){
    lab_space_left + left_offset + ((x-1) * (width + h_facet_space))
  })
  left_positions <- rep(left_pos_values, times=rows)[1:nseries]
  

  # Create grid -------------------------------------------------------------
  for (i in 1:nseries) {
    # Create new grid elements
    e <- e |>
      e_grid(
        height = paste0(height, "%"),
        width = paste0(width, "%"),
        top = paste0(top_positions[i], "%"),
        left = paste0(left_positions[i], "%")
      ) 
    
    # Create new axes for the series, that mimic the first axes
    e$x$opts$xAxis[[i]] <- e$x$opts$xAxis[[1]]
    e$x$opts$yAxis[[i]] <- e$x$opts$yAxis[[1]]
    
    # Assign the new axes to the new grid element
    e$x$opts$xAxis[[i]]$gridIndex <- i - 1
    e$x$opts$yAxis[[i]]$gridIndex <- i - 1
    
    # Dictate to which grid panel the series will be assigned
    e$x$opts$series[[i]]$yAxisIndex <- i - 1
    e$x$opts$series[[i]]$xAxisIndex <- i - 1 
    
  }
  
  e
}

# Example
group_size <- 20
n_groups <- 13
df <- data.frame("day" = rep(1:group_size, times=n_groups), 
                 "temperature" = runif(group_size * n_groups, 10, 40),
                 "location" = rep(LETTERS[1:n_groups], each=group_size))

df %>% 
  group_by(location) %>% 
  e_charts(day) %>% 
  e_line(temperature) %>% 
  e_facet(rows = 4, cols=4, legend_pos = "top", legend_space = 12)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions