I am trying to create a spatial line for multiple individuals in my dataset to then extract raster values across the line.
I have tried a few things but unfortunately the code I am using is assigning all the line to one individual.
WD is the dataset which has 37 individuals in it. x and y are the coordinates.
line_obj <- sp::Line(cbind(WDm2$x,WDm2$y))
lines_obj <- sp::Lines(list(line_obj),ID=WDm2$DogName)
Error in sp::Lines(list(line_obj), ID = WDm2$DogName) :
Single ID required
firstLine <- sp::SpatialLines(list(lines_obj))
If anyone knows how to do this, I would appreciate the help. thanks!
I would like to be able to extract raster values along the lines.
Some example data
x1 <- rbind(c(-180,-20), c(-140,55), c(10, 0), c(-140,-60))
x2 <- rbind(c(-10,0), c(140,60), c(160,0), c(140,-55))
x3 <- rbind(c(-125,0), c(0,60), c(40,5), c(15,-45))
Use raster::spLines
library(raster)
a <- spLines(x1, x2, x3, crs="+proj=longlat")
a
#class : SpatialLines
#features : 3
#extent : -180, 160, -60, 60 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat
Related
Hi Everyone this is my first time posting a question. I am new to using R to generate figures. I am following a tutorial to add p values to a bar plot from datanovia. I am able to successfully compute adjusted p values for several comparisons and now I am trying to plot them on a grouped bar chart. However the values are plotting in the position they appear the in dataframe and not matching to the name of the variable across the data.
For example if the fourth line of the data frame containing the p values shows a significant value then the fourth group in the bar plot will display that value, even though the x axis variable name doesn't match between the dataframes at the fourth position.
How do I correct this an ensure that the p values are displaying with their corresponding comparison?
This is the code to establish the p values.
library(ggpubr)
library(rstatix)
stat.test <- gg_means %>%
group_by(lipid) %>%
t_test(cor ~ Genotype) %>%
adjust_pvalue(method = "BH") %>%
add_significance("p.adj")
This is the code to create the bar plot
bp <- ggbarplot(gg_means, x = "lipid", y = "cor", add = "mean_sd", color= "Genotype",
palette = c("#00AFBB", "#E7B800"),
position = position_dodge(0.8),
ylab = "nmol/mg protein") +
theme(axis.text.x=element_text(angle=90,hjust=1,vjust=0.5))
and finally to add the pvalues to the bar plot
stat.test <- stat.test %>%
add_xy_position(fun = "mean_sd", x = "lipid", dodge = 0.8)
bp + stat_pvalue_manual(stat.test, label = "p.adj.signif", tip.length = 0.01)
The plot produced looks like 2 The arrows indicate where the values should be mapping.
I am using the plot_grid() function of the cowplot package to draw ggplots in a grid and would like to know if there is a way to draw plots by column instead of by row?
library(ggplot2)
library(cowplot)
df <- data.frame(
x = c(3,1,5,5,1),
y = c(2,4,6,4,2)
)
# Create plots: say two each of path plot and polygon plot
p <- ggplot(df)
p1 <- p + geom_path(aes(x,y)) + ggtitle("Path 1")
p2 <- p + geom_polygon(aes(x,y)) + ggtitle("Polygon 1")
p3 <- p + geom_path(aes(y,x)) + ggtitle("Path 2")
p4 <- p + geom_polygon(aes(y,x)) + ggtitle("Polygon 2")
plots <- list(p1,p2,p3,p4)
plot_grid(plotlist=plots, ncol=2) # plots are drawn by row
I would like to have plots P1 and P2 in the first column and p3 and p4 in the second column, something like:
plots <- list(p1, p3, p2, p4) # plot sequence changed
plot_grid(plotlist=plots, ncol=2)
Actually I could have 4, 6, or 8 plots. The number of rows in the plot grid will vary but will always have 2 columns. In each case I would like to fill the plot grid by column (vertically) so my first 2, 3, or 4 plots, as the case maybe, appear over each other. I would like to avoid hardcode these different permutations if I can specify something like par(mfcol = c(n,2)).
As you have observed, plot_grid() draws plots by row. I don't believe there's any way to change that, so if you want to maintain using plot_grid() (which would be probably most convenient), then one approach could be to change the order of the items in your list of plots to match what you need for plot_grid(), given knowledge of the number of columns.
Here's a function I have written that does that. The basic idea is to:
create a list of indexes for number of items in your list (i.e. 1:length(your_list)),
put the index numbers into a matrix with the specified number of rows,
read back that matrix into another vector of indexes by column
reorder your list according to the newly ordered indexes
I've tried to build in a way to make this work even if the number of items in your list is not divisible by the intended number of columns (like a list of 8 items arranged in 3 columns).
reorder_by_col <- function(myData, col_num) {
x <- 1:length(myData) # create index vector
length(x) <- prod(dim(matrix(x, ncol=col_num))) # adds NAs as necessary
temp_matrix <- matrix(x, ncol=col_num, byrow = FALSE)
new_x <- unlist(split(temp_matrix, rep(1:ncol(temp_matrix), each=row(temp_matrix))))
names(new_x) <- NULL # not sure if we need this, but it forces an unnamed vector
return(myData[new_x])
}
This all was written with a little help from Google and specifically answers to questions posted here and here.
You can now see the difference without reordering:
plots <- list(p1,p2,p3,p4)
plot_grid(plotlist=plots, ncol=2)
... and with reordering using the new method:
newPlots <- reorder_by_col(myData=plots, col_num=2)
plot_grid(plotlist=newPlots, ncol=2)
The argument, byrow, has now been added to plot_grid.
In the case where you would like to have num_plots < nrow * ncol the remaining spots will be empty.
You can now call:
library(ggplot2)
df <- data.frame(
x = 1:10, y1 = 1:10, y2 = (1:10)^2, y3 = (1:10)^3, y4 = (1:10)^4
)
p1 <- ggplot(df, aes(x, y1)) + geom_point()
p2 <- ggplot(df, aes(x, y2)) + geom_point()
p3 <- ggplot(df, aes(x, y3)) + geom_point()
cowplot::plot_grid(p1, p2, p3, byrow = FALSE)
I am trying to create a graph based on matrix similar to one below... I am trying to group the Erosion values based on "Slope"...
library(ggplot2)
new_mat<-matrix(,nrow = 135, ncol = 7)
colnames(new_mat)<-c("Scenario","Runoff (mm)","Erosion (t/ac)","Slope","Soil","Tillage","Rotation")
for ( i in 1:nrow(new_mat)){
new_mat[i,2]<-sample(10:50, 1)
new_mat[i,3]<-sample(0.1:20, 1)
new_mat[i,4]<-sample(c("S2","S3","S4","S5","S1"),1)
new_mat[i,5]<-sample(c("Deep","Moderate","Shallow"),1)
new_mat[i,7]<-sample(c("WBP","WBF","WF"),1)
new_mat[i,6]<-sample(c("Intense","Reduced","Notill"),1)
new_mat[i,1]<-paste0(new_mat[i,4],"_",new_mat[i,5],"_",new_mat[i,6],"_",new_mat[i,7],"_")
}
#### Graph part ########
grphs_mat<-as.data.frame(new_mat)
grphs_mat$`Runoff (mm)`<-as.numeric(as.character(grphs_mat$`Runoff (mm)`))
grphs_mat$`Erosion (t/ac)`<-as.numeric(as.character(grphs_mat$`Erosion (t/ac)`))
ggplot(grphs_mat, aes(Scenario, `Erosion (t/ac)`,group=Slope, colour = Slope))+
scale_y_continuous(limits=c(0,max(as.numeric((grphs_mat$`Erosion (t/ac)`)))))+
geom_point()+geom_line()
But when i run this code.. The values are distributed in x-axis for all 135 scenarios. But what i want is grouping to be done in terms of slope but it also picks up the other common factors such as Soil+Rotation+Tillage and place it in x-axis. For example:
For these five scenarios:
S1_Deep_Intense_WBF_
S2_Deep_Intense_WBF_
S3_Deep_Intense_WBF_
S4_Deep_Intense_WBF_
S5_Deep_Intense_WBF_
It separates the S1, S2, S3,S4,S5 but also be able to know that other factors are same and put them in x-axis such that the slope lines are stacked on top of each other in 135/5 = 27 x-axis points. The final figure should look like this (Refer image). Apologies for not being able to explain it better.
I think i am making a mistake in grouping or assigning the x-axis values.
I will appreciate your suggestions.
In the example you give, I didn't get every possible factor combination represented so the plots looked a bit weird. What I did instead was start with the following:
set.seed(42)
new_mat <- matrix(,nrow = 1000, ncol = 7)
And then deduplicated this by summarising the values. A possible relevant step here for you analysis is that I made new variable with the interaction() function that is the combination of three other factors.
library(tidyverse)
df <- grphs_mat
df$x <- with(df, interaction(Rotation, Soil, Tillage))
# The simulation did not yield unique combinations
df <- df %>% group_by(x, Slope) %>%
summarise(n = sum(`Erosion (t/ac)`))
Next, I plotted this new x variable on the x-axis and used "stack" positions for the lines and points.
g <- ggplot(df, aes(x, y = n, colour = Slope, group = Slope)) +
geom_line(position = "stack") +
geom_point(position = "stack")
To make the x-axis slightly more readable, you can replace the . that the interaction() function placed by newlines.
g + scale_x_discrete(labels = function(x){gsub("\\.", "\n", x)})
Another option is to simply rotate the x axis labels:
g + theme(axis.text.x.bottom = element_text(angle = 90))
There are a few additional options for the x-axis if you go into ggplot2 extension packages.
I have plotted a heatmap in ggplot2. I want to add a curved line to the plot to show where z=0 (i.e. where the value of the data used for the fill is zero), how can I do this?
Thanks
Since no example data or code is provided, I'll illustrate with the volcano dataset, representing heights of a volcano in a matrix. Since the data doesn't contain a zero point, we'll draw the line at the arbitrarily chosen 125 mark.
library(ggplot2)
# Convert matrix to data.frame
df <- data.frame(
row = as.vector(row(volcano)),
col = as.vector(col(volcano)),
value = as.vector(volcano)
)
# Set contour breaks at desired level
ggplot(df, aes(col, row, fill = value)) +
geom_raster() +
geom_contour(aes(z = value),
breaks = 125, col = 'red')
Created on 2020-04-06 by the reprex package (v0.3.0)
If this isn't a good approximation of your problem, I'd suggest to include example data and code in your question.
I have the following two-part plot which are not aligned:
Side-by-side plots not aligned
These plots are produced by the following code:
require(ggplot2)
require(gridExtra)
set.seed(0)
data <- data.frame(x=rpois(30,5),y=rpois(30,11),z=rpois(300,25))
left.plot <- ggplot(data,aes(x,y))
+ geom_bin2d(binwidth=1)
margin.data <- as.data.frame( margin.table(table(data),1))
right.plot <- ggplot(margin.data, aes(x=x,y=Freq))
+ geom_bar(stat="identity")+coord_flip()
grid.arrange(left.plot, right.plot, ncol=2)
How can I align the rows in the left plot to the bars in the right plot?
Your issues are simple, albeit twofold.
Ultimately you need to use scale_y_continuous() and scale_x_continuous() to set your axis limits to match on eatch figure. That's impeded by the fact that the x value is a factor. Convert it to a numeric and throw in some scaling and you're good to go.
left.plot <- ggplot(data,aes(x,y)) +
geom_bin2d(binwidth=1) +
scale_y_continuous(limits = c(1, 16))
margin.data <- as.data.frame( margin.table(table(data),1))
right.plot <- ggplot(margin.data, aes(x=as.numeric(as.character(x)),y=Freq)) +
geom_bar(stat="identity") +
scale_x_continuous(limits = c(1, 16)) +
xlab("x") +
coord_flip()
Using package ggExtra I was able to get an almost solution
require(ggplot2)
require(ggExtra)
set.seed(0)
data <- data.frame(x=rpois(30,5),y=rpois(30,11),z=rpois(300,25))
left.plot <- ggplot(data,aes(x,y)) + geom_bin2d(binwidth=1)
ggMarginal(left.plot, margins="y", type = "histogram", size=2,bins=(max(data$y)-min(data$y)+1),binwidth=1.06)
I say almost because I had to set manually binwidth=1.06 to align bar and counts.
Manually aligned plots using ggExtra::ggMarginal