Передача имен переменных в функции и их использование для создания динамического графика и меток в R

#r #ggplot2 #tidyeval

#r #ggplot2 #tidyeval

Вопрос:

(Я новичок в R).

Я создал внешнюю функцию с 3 внутренними функциями, которые предварительно обрабатывают данные и отображают.

Проблемы, с которыми я сталкиваюсь, заключаются в динамическом использовании названия страны — в передаче их y axis , а также в использовании их внутри labs for titles/subtitles .

Добавление снимка проблемных областей ниже (это работает, когда я использую статическое название страны)

введите описание изображения здесь

Но когда я использую аргумент country names bench_country , например {bench_country} , или !!bench_country или !!enquo(bench_country) , тогда это не работает.

Добавление ниже снимка проблемных областей (это не работает с аргументом bench_country = India)

введите описание изображения здесь

Я использовал {} для других аргументов, которые работают, но {bench_country} в большинстве мест вызывают проблемы

Добавление кода ниже для репликации проблемы:

 library(tidyverse)
library(glue)
library(scales)

gapminder <- read.csv("https://raw.githubusercontent.com/swcarpentry/r-novice-gapminder/gh-pages/_episodes_rmd/data/gapminder-FiveYearData.csv")

gapminder <- gapminder %>% mutate_if(is.character, as.factor)

################ fn_benchmark_country ################


fn_benchmark_country_last  <- 
  function(bench_country = India){
  
      bench_country = enquo(bench_country) # <======================================= enquo used
    
      gapminder_benchmarked_wider <- gapminder %>% 
                                      select(country, year, gdpPercap) %>% 
                                      pivot_wider(names_from = country, values_from = gdpPercap) %>% 
                                      arrange(year) %>% 
                                      # map_dbl( ~{.x - India })
                                      mutate(across(-1, ~ . - !!bench_country))
                                      
      # Reshaping back to Longer
      gapminder_benchmarked_longer <- gapminder_benchmarked_wider %>% 
                                      pivot_longer(cols = !year, names_to = "country", values_to = "benchmarked") 
     
      # Joining tables
      gapminder_joined <- left_join(x = gapminder, y = gapminder_benchmarked_longer, by = c("year","country"))
    
      # converting to factor
      gapminder_joined$country <- as.factor(gapminder_joined$country)
      
      # gapminder_joined <<- gapminder_joined 
      # (this pushes it to Global evrn)
      
      return(gapminder_joined)
  
}  

################ ----------------------------- ################



################ fn_year_filter ################

# filtering years 

fn_year_filter_last  <- 
  function(gapminder_joined, year_start, year_end){

      gapminder_joined %>% 
      filter(year %in% c(year_start,year_end)) %>% 
      
      arrange(country, year) %>% 
      
      group_by(country) %>% 
      
      mutate(benchmark_diff = benchmarked[2] - benchmarked[1],
             max_pop = max(pop)) %>% 
      
      ungroup() %>% 
      
      arrange(benchmark_diff) %>% 
      
      filter(max_pop > 30000000) %>% 
      
      mutate(country = droplevels(country)) %>% 
      select(country, year, continent, benchmarked, benchmark_diff) %>% 
        
      # --- 
      mutate(country = fct_inorder(country)) %>% 
      
      group_by(country) %>% 
        
      mutate(benchmarked_end = benchmarked[2],
             benchmarked_start = benchmarked[1]  ) %>% 
      
      ungroup() 

  }

################ ----------------------------- ################



################ fn_create_plot ################
  
fn_create_plot_last <- 
  function(df, year_start, year_end, bench_country ){
    
    # plotting
        ggplot(df)   
        
        geom_segment(aes(x = benchmarked_start, xend = benchmarked_end,
                         y = country, yend = country,
                         col = continent), alpha = 0.5, size = 7)  
        
        geom_point(aes(x = benchmarked, y = country, col = continent), size = 9, alpha = .8)  
        
        geom_text(aes(x = benchmarked_start   8, y = country,
                      label = paste(round(benchmarked_start))),
                  col = "grey50", hjust = "right")  
        
        geom_text(aes(x = benchmarked_end - 4.0, y = country,
                      label = round(benchmarked_end)),
                  col = "grey50", hjust = "left")  
      
        # scale_x_continuous(limits = c(20,85))  
        
        scale_color_brewer(palette = "Pastel2")  
        
        labs(title = glue("Countries GdpPerCap at {year_start} amp; {year_end})"),
             subtitle = "Meaning Difference of gdpPerCap of countries taken wrt India n(Benchmarked India in blue line) nFor Countries with pop > 30000000 n(Chart created by ViSa)",
             col = "Continent", 
             x = glue("GdpPerCap Difference at {year_start} amp; {year_end} (w.r.t India)") )  

       
    # Adding benchmark line      
        geom_vline(xintercept = 0, col = "blue", alpha = 0.3)  
      
        geom_label( label="India- as Benchamrked line", x=8000, y= !!bench_country, # {bench_country} 
          label.padding = unit(0.35, "lines"), # Rectangle size around label
          label.size = 0.15, color = "black")    
      
        # background amp; theme settings
        theme_classic()  
    
    theme(legend.position = "top", 
          axis.line = element_blank(), # axis.text = element_blank() 
          axis.ticks = element_blank()
          )  
         
    # Adding $ to the axis (from scales lib)            <=========================
        scale_x_continuous(labels = label_dollar()) 
    
}

################ ----------------------------- ################



################  Calling functions  ################

fn_run_all_last <-function(bench_country = India, year_start = 1952, year_end = 2007){
  
  
  year_start = year_start
  year_end = year_end
  
  # Function1 for PreProcess Benchmarked Country
     gapminder_joined <- fn_benchmark_country_last({{bench_country}}) 

  # Function2 to PreProcess dates amp; pass df to function3 to plot  
      Plot_last <- fn_year_filter_last(gapminder_joined, year_start, year_end) %>% 
      
                      fn_create_plot_last(., year_start, year_end, {{bench_country}})

  
  # Pusing plot object to global
       Plot_last <<- Plot_last
  
  # Printing Plot
      Plot_last
  }

fn_run_all_last(India, 1952, 2007)
  

Ответ №1:

Чтобы заставить ваш код работать, используйте rlang::as_label(enquo(bench_country)) in geom_label вместо !!bench_country или другие варианты, которые вы пробовали. При enquo кавычках аргумент rlang::as_label преобразует аргумент или выражение в строку, которую затем можно использовать в качестве метки.

С этим изменением я получаю:

введите описание изображения здесь

РЕДАКТИРОВАТЬ Для справки вот полный код функции построения графика. Я также скорректировал код, чтобы сделать заголовок и метку оси «динамическими». Чтобы избежать дублирования кода, я добавляю новую переменную в начале функции, которой я присваиваю метку страны в качестве символа:

 fn_create_plot_last <-
  function(df, year_start, year_end, bench_country) {

    bench_country_str <- rlang::as_label(enquo(bench_country))
    
    # plotting
    ggplot(df)  
      geom_segment(aes(
        x = benchmarked_start, xend = benchmarked_end,
        y = country, yend = country,
        col = continent
      ), alpha = 0.5, size = 7)  
      geom_point(aes(x = benchmarked, y = country, col = continent), size = 9, alpha = .8)  
      geom_text(aes(
        x = benchmarked_start   8, y = country,
        label = paste(round(benchmarked_start))
      ),
      col = "grey50", hjust = "right"
      )  
      geom_text(aes(
        x = benchmarked_end - 4.0, y = country,
        label = round(benchmarked_end)
      ),
      col = "grey50", hjust = "left"
      )  

      # scale_x_continuous(limits = c(20,85))  

      scale_color_brewer(palette = "Pastel2")  
      labs(
        title = glue("Countries GdpPerCap at {year_start} amp; {year_end})"),
        subtitle = glue("Meaning Difference of gdpPerCap of countries taken wrt {bench_country_str} n(Benchmarked {bench_country_str} in blue line) nFor Countries with pop > 30000000 n(Chart created by ViSa)"),
        col = "Continent",
        x = glue("GdpPerCap Difference at {year_start} amp; {year_end} (w.r.t {bench_country_str})")
      )  


      # Adding benchmark line
      geom_vline(xintercept = 0, col = "blue", alpha = 0.3)  
      geom_label(
        label = glue("{bench_country_str} - as Benchamrked line"), x = 8000, y = bench_country_str, # {bench_country}
        label.padding = unit(0.35, "lines"), # Rectangle size around label
        label.size = 0.15, color = "black"
      )  

      # background amp; theme settings
      theme_classic()  
      theme(
        legend.position = "top",
        axis.line = element_blank(), # axis.text = element_blank()
        axis.ticks = element_blank()
      )  

      # Adding $ to the axis (from scales lib)            <=========================
      scale_x_continuous(labels = label_dollar())
  } 
  

Комментарии:

1. Спасибо @stefan, который работал, geom_label но я все еще не могу решить эту проблему в labs for title , subtitles .. я пробовал {!!bench_country} и многие другие комбинации, но ничего не помогло

2. Привет @ViSa. Я только что внес правку и включил полный код для вашей функции построения графика. Я проверил, используя «Germany» в качестве эталона, что все аннотации теперь получают правильную метку.

3. Большое спасибо @stefan за помощь!!

4. @ViSa К вашему сведению, сингл { делает что-то только внутри склеиваемых строк. В обычном коде это эквивалентно ( скобкам. Это { в коде может немного сбивать с толку, потому что из-за них кажется, что вы пытаетесь интерполировать аргументы данных {{ .

5. Спасибо @LionelHenry за объяснение { . Я сильно смущен { quos, enquous, rlang smb, as_label и многими другими подобными вещами и ищу хорошие ссылки для изучения, поскольку, не изучая их, я застреваю в каждой функции, которую я создаю.