0

I have a function provided to do a PCA plot which is shown below. I want to pass the names of the principal components(variables a and b) but have not figured a way to do this. I have tried using aes_string. Error received is Error in eval(expr, envir, enclos) : object '.names' not found

Per suggestion below, I have put a concrete example. One where the function works and another where it does not. Goal is to pass variables to this function.

 #data
  d = iris[1:4]
  #########################################################################
  # PCA_Plot functions
  #########################################################################

  PCA_Plot = function(pcaData)
  {
    library(ggplot2)

    theta = seq(0,2*pi,length.out = 100)
    circle = data.frame(x = cos(theta), y = sin(theta))
    p = ggplot(circle,aes(x,y)) + geom_path()

    loadings = data.frame(pcaData$rotation, .names = row.names(pcaData$rotation))
    p + geom_text(data=loadings, mapping=aes(x = PC1, y = PC2, label = .names, colour = .names, fontface="bold")) +
      coord_fixed(ratio=1) + labs(x = "PC1", y = "PC2")
  }
  # non-working function with two extra variables
  PCA_Plot2 = function(pcaData, var1, var2)
  {
    library(ggplot2)

    theta = seq(0,2*pi,length.out = 100)
    circle = data.frame(x = cos(theta), y = sin(theta))
    p = ggplot(circle,aes(x,y)) + geom_path()

    loadings = data.frame(pcaData$rotation, .names = row.names(pcaData$rotation))
    p + geom_text(data=loadings, mapping=aes(x = var1, y = var2, label = .names, colour = .names, fontface="bold")) +
      coord_fixed(ratio=1) + labs(x = var1, y = var2)
  }


  #pca
  library(stats)
  p = prcomp(d)

  PCA_Plot(p) #works

  PCA_Plot2(p, "PC1", "PC2") # ERROR Error: Discrete value supplied to 
  continuous scale
Ubba
  • 3
  • 2
  • 4
    you should provide a reproducible example. – MLavoie Apr 20 '18 at 15:57
  • 2
    To further @MLavoie's comment about a reproducible example, if you could provide us with an easy to load into R sample of `data`, using `dput(data)` or `dput(head(data,50))` it will go a long way in helping us help you. – Jake Kaupp Apr 20 '18 at 16:12

2 Answers2

2

You were almost there with aes_string! You are providing var1 and var2 as strings, but not the label aesthetic .names. If you change that to ".names", your function will work.

I altered your function a bit:

  1. Return the ggplot object directly instead of assigning an intermediate variable
  2. Merged the plotting calls
  3. Moved the library call outside of the function (no need to load the library every time you call the function).

    library(stats)
    library(ggplot2)
    
    PCA_Plot2 = function(pcaData, var1, var2)
    {
    
      theta = seq(0,2*pi,length.out = 100)
    
       circle = data.frame(x = cos(theta), y = sin(theta))
    
       loadings = data.frame(pcaData$rotation,  .names = row.names(pcaData$rotation))
    
      ggplot(circle, aes(x,y)) +
        geom_path() +
        geom_text(aes_string(x = var1, y = var2, label = ".names"), inherit.aes = FALSE, data = loadings) +
        coord_fixed(ratio=1) +
        labs(x = var1, y = var2)
    }
    
    PCA_Plot2(p, "PC1", "PC2")
    

enter image description here

Jake Kaupp
  • 7,892
  • 2
  • 26
  • 36
1

Without having your data, here's a simplified example of your function using some base R datasets. I think you're having a quosure problem: you can't directly access columns just by using the string that corresponds to a column name. Instead, you want to use something like q_var <- quo(var), and then !!q_var in referring to the column by its bare name. I have a fair amount of trouble with writing functions like this, but see the "Programming with dplyr" vignette for more explanation.

library(tidyverse)

make_plot <- function(full_df, var1, var2) {
    # use quo to access the values in the strings var1, var2
    quo_var1 <- quo(var1)
    quo_var2 <- quo(var2)

    df <- full_df %>% rownames_to_column("name") %>% select(name, x = !!quo_var1, y = !!quo_var2)

    ggplot(df, aes(x = x, y = y)) +
        geom_text(aes(label = name), size = 2.5) +
        # still have var1, var2 strings--can use as labels
        labs(x = var1, y = var2)
}

make_plot(mtcars, "mpg", "disp")

make_plot(mtcars, "hp", "qsec")

make_plot(as.data.frame(state.x77), "Income", "Life Exp")

Created on 2018-04-20 by the reprex package (v0.2.0).

camille
  • 16,432
  • 18
  • 38
  • 60