In R, I'm trying to plot multiple charts based on stored functions (I'm pretty new to programming with R, so that might not totally make sense). Basically, I've created some charts and stored them in a function that can be easily run with new data. I want to retain that functionality while adding the ability to render multiple charts in one render. I'd like it to end up something like this http://www.statmethods.net/advgraphs/images/layout1.jpg
I've run the code below, but it just produces multiple instances of each graph (or replaces each graph with the new rendering).
So my question is this: what am I doing wrong? Does anyone out there know how I can generate four graphs to be placed in one view (like the link above) using the following code and functions? Any help is greatly appreciated.
Note: the second bit of code has two siblings. I also have a pie chart I haven't included, but it's mentioned in the following code.
Here's the code I've been working with:
attach(ES)
par=(mfrow=c(2,2))
plot=(mapFunctionRead())
plot=(mapFunctionSkim())
plot=(mapFunctionDelete())
plot=(pieChart())
And Here's a sample function:
mapFunctionRead<-function(){
# draw world map
map(database="world", bg="#d4d5d1", fill = TRUE, col="#ffffff",myborder = 0)
################# For Read ####################
# Draw circles
symbols(mtReadLong, mtReadLat, circles=rep(1, length(mtReadLong)), inches=0.005, add=TRUE)
# assign numerical value that's based on the amount of time read
radiusRead<-sqrt(mtReadSec/pi)
# draw circles with fill and border
symbols(mtReadLong, mtReadLat, bg="#4173a5", fg="#5589c7", lwd=0.5, circles=radiusRead, inches=0.05, add=TRUE)
}
################# Displays data on world map for SKIM ######################
mapFunctionSkim<-function(){
# draw world map
map(database="world", bg="#d4d5d1", fill = TRUE, col="#ffffff",myborder = 0)
################# For Skim ####################
# Draw circles
symbols(mtSkimLong, mtSkimLat, circles=rep(1, length(mtSkimLong)), inches=0.005, add=TRUE)
# assign numerical value that's based on the amount of time read
radiusSkim<-sqrt(mtSkimSec/pi)
# draw circles with fill and border
symbols(mtSkimLong, mtSkimLat, bg="#ead57d", fg="#ead57d", lwd=0.5, circles=radiusSkim, inches=0.05, add=TRUE)
}
################# Displays data on world map for DELETE ######################
mapFunctionDelete<-function(){
# draw world map
map(database="world", bg="#d4d5d1", fill = TRUE, col="#ffffff",myborder = 0)
################# For Delete ####################
# Draw circles
symbols(mtDeleteLong, mtDeleteLat, circles=rep(1, length(mtDeleteLong)), inches=0.005, add=TRUE)
# assign numerical value that's based on the amount of time read
radiusDelete<-sqrt(mtDeleteSec/pi)
# draw circles with fill and border
symbols(mtDeleteLong, mtDeleteLat, bg="#77223c", fg="#9c1b3e", lwd=0.5, circles=radiusDelete, inches=0.05, add=TRUE)
}
Well I agree with #MrFlick. You might want to think of providing arguments to your map functions. For example.
library(maps)
mfunc <- function(x,y){
map(database = x, bg = y)
}
mfunc(x = "world", y = "#d4d5d1")
Then once all your map functions are defined you can use par(mfrow = c(a,b)). But just based on the info you have provided I'm not really sure what you want. Best of luck though.
Related
I am using the statspat package because I am working on spatial patterns.
I would like to do in ggplot and with colors instead of numbers (because it is not too readable),
the following graph, produced with the plot.quadratest function: Polygone
The numbers that interest me for the intensity of the colors are those at the bottom of each box.
The test object contains the following data:
Test object
I have looked at the help of the function, as well as the code of the function but I still cannot manage it.
Ideally I would like my final figure to look like this (maybe not with the same colors haha):
Final object
Thanks in advance for your help.
Please provide a reproducible example in the future.
The package reprex may be very helpful.
To use ggplot2 for this my best bet would be to convert
spatstat objects to sf and do the plotting that way,
but it may take some time. If you are willing to use base
graphics and spatstat you could do something like:
library(spatstat)
# Data (using a built-in dataset):
X <- unmark(chorley)
plot(X, main = "")
# Test:
test <- quadrat.test(X, nx = 4)
# Default plot:
plot(test, main = "")
# Extract the the `quadratcount` object (regions with observed counts):
counts <- attr(test, "quadratcount")
# Convert to `tess` (raw regions with no numbers)
regions <- as.tess(counts)
# Add residuals as marks to the tessellation:
marks(regions) <- test$residuals
# Plot regions with marks as colors:
plot(regions, do.col = TRUE, main = "")
I have some 16 plots. I want to plot all of these in grid manner with ggplot2. But, whenever I plot, I get a grid with all the plots same, i.e, last plot saved in a list gets plotted at all the 16 places of grid. To replicate the same issue, here I am providing a simple example with two files. Although data are entirely different, but plots drawn are similar.
library(ggplot2)
library(grid)
library(gridExtra)
library(scales)
set.seed(1006)
date1<- as.POSIXct(seq(from=1443709107,by=3600,to=1446214707),origin="1970-01-01")
power <- rnorm(length(date1),100,5)#with normal distribution
write.csv(data.frame(date1,power),"file1.csv",row.names = FALSE,quote = FALSE)
# Now another dataset with uniform distribution
write.csv(data.frame(date1,power=runif(length(date1))),"file2.csv",row.names = FALSE,quote = FALSE)
path=getwd()
files=list.files(path,pattern="*.csv")
plist<-list()# for saving intermediate ggplots
for(i in 1:length(files))
{
dframe<-read.csv(paste(path,"/",files[i],sep = ""),head=TRUE,sep=",")
dframe$date1= as.POSIXct(dframe$date1)
plist[[i]]<- ggplot(dframe)+aes(dframe$date1,dframe$power)+geom_line()
}
grid.arrange(plist[[1]],plist[[2]],ncol = 1,nrow=2)
You need to remove the dframe from your call to aes. You should do that anyway because you have provided a data-argument. In this case it's even more important because while you save the ggplot-object, things don't get evaluated until the call to plot/grid.arrange. When you do that, it looks at the current value of dframe, which is the last dataset in your iteration.
You need to plot with:
ggplot(dframe)+aes(date1,power)+geom_line()
I have the following example
data(diamonds, package="ggplot2")
diamonds.samp <- diamonds[sample(1:dim(diamonds)[1],200),]
ggpairs(diamonds.samp, columns=8:10,
upper=list(continuous='cor'),
lower=list(continuous = 'points'),
diag=list(continuous='density'),
axisLabels='show'
)
Resulting in a really nice figure:
But my problem is that in the real dataset I have to many points whereby I would like to change the parameters for the point geom. I want to reduce the dot size and use a lower alpha value. I can however not doe this with the "param" option it applies to all plot - not just the lower one:
ggpairs(diamonds.samp, columns=8:10,
upper=list(continuous='cor'),
lower=list(continuous = 'points'),
diag=list(continuous='density'),
params=c(alpha=1/10),
axisLabels='show'
)
resulting in this plot:
Is there a way to apply parameters to only "lower" plots - or do I have to use the ability to create custom plots as suggested in the topic How to adjust figure settings in plotmatrix?
In advance - thanks!
There doesn't seem to be any elegant way to do it, but you can bodge it by writing a function to get back the existing subchart calls from the ggally_pairs() object and then squeezing the params in before the last bracket. [not very robust, it'll only work for if the graphs are already valid]
diamonds.samp <- diamonds[sample(1:dim(diamonds)[1],200),]
g<-ggpairs(diamonds.samp, columns=8:10,
upper=list(continuous='cor'),
lower=list(continuous = 'points'),
diag=list(continuous='density'),
axisLabels='show'
)
add_p<-function(g,i,params){
side=length(g$columns) # get number of cells per side
lapply(i,function(i){
s<-as.character(g$plots[i]) # get existing call as a template
l<-nchar(s)
p<-paste0(substr(s,1,l-1),",",params,")") # append params before last bracket
r<-i%/%side+1 # work out the position on the grid
c<-i%%side
array(c(p,r,c)) # return the sub-plot and position data
})
}
rep_cells<-c(4,7,8)
add_params<-"alpha=0.3, size=0.1, color='red'"
ggally_data<-g$data # makes sure that the internal parameter picks up your data (it always calls it's data 'ggally_data'
calls<-add_p(g,rep_cells,params=add_params) #call the function
for(i in 1:length(calls)){g<-putPlot(g,calls[[i]][1],as.numeric(calls[[i]][2]),as.numeric(calls[[i]][3]))}
g # call the plot
I am trying to use the animation package to generate an "evolving" plot of points on a map. The map is generated from shapefiles (from the readShapeSpatial/readShapeLines functions).
The problem is when it's plotted in a for loop, the result is additive, whereas the ideal result is to have it evolve.
Are there ways of using par() that I am missing?
My question is: is there a way to clear just the points ploted from the points function
and not clearing the entire figure thus not having to regraph the shapefiles?
in case someone wants to see code:
# plotting underlying map
newyork <- readShapeSpatial('nycpolygon.shp')
routes <- readShapeLines('nyc.shp')
par(bg="grey25")
plot(newyork, lwd=2, col ="lightgray")
plot(routes,add=TRUE,lwd=0.1,col="lightslategrey")
# plotting points and save to GIF
ani.options(interval=.05)
saveGIF({
par(bg="grey25")
# Begin loop
for (i in 13:44){
infile <-paste("Week",i,".csv",sep='')
mydata <-read.csv(file = infile, header = TRUE, sep=",")
plotvar <- Var$Para
nclr <- 4
plotclr <-brewer.pal(nclr,"RdPu")
class<- classIntervals(plotvar,nclr,style = "pretty")
colcode <- findColours(class,plotclr)
points(Var$Lon,Var$Lat,col=colcode)
}
})
If you can accept a residual shadow or halo of ink, you can over-plot with color ="white" or == to your background choices. We cannot access your shape file but you can try it out by adding this line:
points(Var$Lon, Var$Lat, col="grey25")
It may leave gaps in other previously plotted figures or boundaries, because it's definitely not object-oriented. The lattice and ggplot2 graphics models are more object oriented, so if you want to post a reproducible example, that might be an alternate path to "moving" forward. I seem to remember that the rgl package has animation options in its repetoire.
I need to draw lines from the data stored in a text file.
So far I am able only to draw points on a graph and i would like to have them as lines (line graph).
Here's the code:
pupil_data <- read.table("C:/a1t_left_test.dat", header=T, sep="\t")
max_y <- max(pupil_data$PupilLeft)
plot(NA,NA,xlim=c(0,length(pupil_data$PupilLeft)), ylim=c(2,max_y));
for (i in 1:(length(pupil_data$PupilLeft) - 1))
{
points(i, y = pupil_data$PupilLeft[i], type = "o", col = "red", cex = 0.5, lwd = 2.0)
}
Please help me change this line of code:
points(i, y = pupil_data$PupilLeft[i], type = "o", col = "red")
to draw lines from the data.
Here is the data in the file:
PupilLeft
3.553479
3.539469
3.527239
3.613131
3.649437
3.632779
3.614373
3.605981
3.595985
3.630766
3.590724
3.626535
3.62386
3.619688
3.595711
3.627841
3.623596
3.650569
3.64876
By default, R will plot a single vector as the y coordinates, and use a sequence for the x coordinates. So to make the plot you are after, all you need is:
plot(pupil_data$PupilLeft, type = "o")
You haven't provided any example data, but you can see this with the built-in iris data set:
plot(iris[,1], type = "o")
This does in fact plot the points as lines. If you are actually getting points without lines, you'll need to provide a working example with your data to figure out why.
EDIT:
Your original code doesn't work because of the loop. You are in effect asking R to plot a line connecting a single point to itself each time through the loop. The next time through the loop R doesn't know that there are other points that you want connected; if it did, this would break the intended use of points, which is to add points/lines to an existing plot.
Of course, the line connecting a point to itself doesn't really make sense, and so it isn't plotted (or is plotted too small to see, same result).
Your example is most easily done without a loop:
PupilLeft <- c(3.553479 ,3.539469 ,3.527239 ,3.613131 ,3.649437 ,3.632779 ,3.614373
,3.605981 ,3.595985 ,3.630766 ,3.590724 ,3.626535 ,3.62386 ,3.619688
,3.595711 ,3.627841 ,3.623596 ,3.650569 ,3.64876)
plot(PupilLeft, type = 'o')
If you really do need to use a loop, then the coding becomes more involved. One approach would be to use a closure:
makeaddpoint <- function(firstpoint){
## firstpoint is the y value of the first point in the series
lastpt <- firstpoint
lastptind <- 1
addpoint <- function(nextpt, ...){
pts <- rbind(c(lastptind, lastpt), c(lastptind + 1, nextpt))
points(pts, ... )
lastpt <<- nextpt
lastptind <<- lastptind + 1
}
return(addpoint)
}
myaddpoint <- makeaddpoint(PupilLeft[1])
plot(NA,NA,xlim=c(0,length(PupilLeft)), ylim=c(2,max(PupilLeft)))
for (i in 2:(length(PupilLeft)))
{
myaddpoint(PupilLeft[i], type = "o")
}
You can then wrap the myaddpoint call in the for loop with whatever testing you need to decide whether or not you will actually plot that point. The function returned by makeaddpoint will keep track of the plot indexing for you.
This is normal programming for Lisp-like languages. If you find it confusing you can do this without a closure, but you'll need to handle incrementing the index and storing the previous point value 'manually' in your loop.
There is a strong aversion among experienced R coders to using for-loops when not really needed. This is an example of a loop-less use of a vectorized function named segments that takes 4 vectors as arguments: x0,y0, x1,y1
npups <-length(pupil_data$PupilLeft)
segments(1:(npups-1), pupil_data$PupilLeft[-npups], # the starting points
2:npups, pupil_data$PupilLeft[-1] ) # the ending points