I discovered few weeks ago ggforce, which has a great features to plot ellipse. But I don't manage to use it in log plots. Here is an example:
I would like to use the ellipse to circle this group
library(ggforce)
library(ggplot2)
ggplot(mtcars)+
geom_point(aes(hp,disp))+
geom_ellipse(aes(x0 = 230, y0 = 450, a = 80, b = 30, angle = -10))
But I would like to do this in a log plot. If I naively do
ggplot(mtcars)+
geom_point(aes(hp,disp))+
geom_ellipse(aes(x0 = 230, y0 = 450, a = 80, b = 30, angle = -10))+
scale_y_log10()
I obtain a giant ellipse:
It looks like the ellipse parameters are not log transformed. I could try to reduce the parameter axis to get the good size on the log axis, something like:
ggplot(mtcars)+
geom_point(aes(hp,disp))+
scale_y_log10()+
geom_ellipse(aes(x0 = 230, y0 = 450, a = 80, b = 0.05, angle =0))
which works:
But only if the angle is 0. If not, the two wxis are mixed and I can't get the ellipse I want:
ggplot(mtcars)+
geom_point(aes(hp,disp))+
scale_y_log10()+
geom_ellipse(aes(x0 = 230, y0 = 450, a = 80, b = 0.05, angle = -10))
How can I plot an ellipse in a log or log-log plot in ggplot ? Is there any feasible workaround with ggforce ? Is there any other "simple" solution (other than coding the ellipse in semi-log coordinates) ?
What actually works for me is to transform the coordinate system instead of the y scale.
ggplot(mtcars) +
geom_point(aes(hp,disp)) +
geom_ellipse(aes(x0 = 230, y0 = 450, a = 80, b = 30, angle = -10)) +
coord_trans(y = "log10")
To be honest it intuitively makes sense to me to use the coord transformation - it resembles coord_map where you're also transforming the coordinates when plotting polygons in different shapes - but I don't know enough internals to explain why scale transformation does not work.
Related
I have a dataframe df which has a column called Roll with values of angles that ranges between -180 to 180. As an example:
set.seed(123)
Roll<-sample(seq(from = -180, to = 180, by = 10), size = 200, replace = TRUE)
df<- data.frame(Roll)
head(df$Roll)
[1] 120 -40 -50 -160 180 -50
I want to create a circular histogram with the next aesthetic:
Does anyone know how to create a plot like this? I don't know how to transform axes to get this.
You can use coord_polar to transform a histogram into polar coordinates, and adjust the start value in radians (here we want 90 degrees in radians to match your drawing).
library(ggplot2)
ggplot(df) +
geom_histogram(aes(x = Roll)) +
scale_x_continuous(breaks = c(-180, -90, 0, 90, 180)) +
coord_polar(start = pi/2)
I am using ´persp´ to generate 3D-Plot. it is the result:
persp(TestMatrix ,theta = 30, phi = 30, expand = 0.19,scale=FALSE,shade=0.4,border=NA,box=FALSE)
in my diagram. I would like to change the color continuous from blue to red.
what should I do?
UPDATE
I would like generate a diagram like this:
If you just need a shaded red curve, try to add a colparameter in your persp function :
persp(TestMatrix,
theta = 30, phi = 30, expand = 0.19, scale=FALSE,
shade=0.4, col="red", border="blue",
box=FALSE)
Edit :
Thanks for your edit, I wasn't sure you needed a two-colors plot. There is an question on this problem here : Create 3D Plot Colored According to the Z-axis. You need a color matrix to specify the colors of each facet of the surface. The subtil point is to calculate the height (z) in the middle of each facet, ie the mean of the four summit of the grid (which correspond to z values).
Adapting the answer for your graph, the solution can be something like that :
# Color palette (100 colors)
col.pal<-colorRampPalette(c("blue", "red"))
colors<-col.pal(100)
# height of facets
z.facet.center <- (z[-1, -1] + z[-1, -ncol(z)] + z[-nrow(z), -1] + z[-nrow(z), -ncol(z)])/4
# Range of the facet center on a 100-scale (number of colors)
z.facet.range<-cut(z.facet.center, 100)
persp(x, y, z,
theta = 30, phi = 30, expand = 0.19, scale=FALSE,
shade=NA, col=colors[z.facet.range], border="grey80",
box=FALSE)
I have some longitude position data and I want to show its variation over time for each of the several different individuals of study. I also want to do a marginal tile-like density plot on top of it but I need it to show where this density is on a map so I need a geographical map overlaid on top of it.
My data looks something like this:
SO <- data.frame(date = rep(seq(as.Date("2000/1/1"), by = "day", length.out = 365), 3),
julian = rep(seq(1,365,1),3),
ind = c(rep(1,365), rep(2,365), rep(3,365)),
longitude = c(rnorm(365, mean = 90, sd =5), rnorm(365, mean = 85, sd =2), rnorm(365, mean = 92, sd =3)))
So far I have managed to plot the longitudes fitted with smoothed lines and flip coordinates to leave longitude in the x-axis. My code currently looks like this:
ggplot(SO, aes(x = julian, y = longitude)) +
geom_point(aes(color=factor(ind)), size = 0.1) +
stat_smooth(aes(group= factor(ind)), se = FALSE)+
stat_smooth(aes(color=factor(ind))) +
coord_flip() + scale_x_reverse()
However I have got stuck with plotting the tile density and overlaying a map to it. The result should look like this.
If you can just come up with how to overlay the map to the density plot that would already be of great help. Thank you very much.
I have the following kind of data: on a rectangular piece of land (120x50 yards), there are 6 (also rectabgular) smaller areas each with a different kind of plant. The idea is to study the attractiveness of the various kinds of plant to birds. Each time a bird sits down somewhere on the land, I have the exact coordinates of where the bird sits down.
I don't care exactly where the bird sits down, but only care which of the six areas it is. To show the relative preference of birds for the various plants, I want to make a heatmap that makes the areas that are frequented most the darkest.
So, I need to convert the coordinates to code which area the bird visits, and then create a heatmap that shows the differential preference for each land area.
(the research is a bit more involved than this, but this is the general idea.)
How would I do this in R? Is there a R function that takes a vector of coordinates and turns that in such a heatmap? If not, do you have some hints for more on how to do this?
Not meant to be the answer you are looking for, but might give you some inspiration.
# Simulate some data
birdieLandingSimulator <- data.frame(t(sapply(1:100, function(x) c(runif(1, -10,10), runif(1, -10,10)))))
# Assign some coordinates, which ended up not really being used much at all, except for the point colors
assignCoord <- function(x)
{
# Assign the four coordinates clockwise: 1, 2, 3, 4
ifelse(all(x>0), 1, ifelse(!sum(x>0), 3, ifelse(x[1]>0, 2, 4)))
}
birdieLandingSimulator <- cbind(birdieLandingSimulator, Q = apply(birdieLandingSimulator, 1, assignCoord))
# Plot
require(ggplot2)
ggplot(birdieLandingSimulator, aes(x = X1, y = X2)) +
stat_density2d(geom="tile", aes(fill = 1/..density..), contour = FALSE) +
geom_point(aes(color = factor(Q))) + theme_classic() +
theme(axis.title = element_blank(),
axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank()) +
scale_color_discrete(guide = FALSE, h=c(180, 270)) +
scale_fill_continuous(name = "Birdie Landing Location")
Use ggplot2. Take a look at the examples for geom_bin2d. It's pretty simple to get 2d bins. Notice that you pass in binwidth for both x and y:
> df = data.frame(x=c(1,2,4,6,3,2,4,2,1,7,4,4),y=c(2,1,4,2,4,4,1,4,2,3,1,1))
> ggplot(df,aes(x=x, y=y,alpha=0.5)) + geom_bin2d(binwidth=c(2,2))
If you don't want to use ggplot, you can use the cut function to separate your data into bins.
# Test data.
x <- sample(1:120, 100, replace=T)
y <- sample(1:50, 100, replace=T)
# Separate the data into bins.
x <- cut(x, c(0, 40, 80, 120))
y <- cut(y, c(0, 25, 50))
# Now plot it, suppressing reordering.
heatmap(table(y, x), Colv=NA, Rowv=NA)
Alternatively, to actually plot the regions in their true geographic location, you could draw the boxes yourself with rect. You would have to count the number of points in each region.
# Test data.
x <- sample(1:120, 100, replace=T)
y <- sample(1:50, 100, replace=T)
regions <- data.frame(xleft=c(0, 40, 40, 80, 0, 80),
ybottom=c(0, 0, 15, 15, 30, 40),
xright=c(40, 120, 80, 120, 80, 120),
ytop=c(30, 15, 30, 40, 50, 50))
# Color gradient.
col <- colorRampPalette(c("white", "red"))(30)
# Make the plot.
plot(NULL, xlim=c(0, 120), ylim=c(0, 50), xlab="x", ylab="y")
apply(regions, 1, function (r) {
count <- sum(x >= r["xleft"] & x < r["xright"] & y >= r["ybottom"] & y < r["ytop"])
rect(r["xleft"], r["ybottom"], r["xright"], r["ytop"], col=col[count])
text( (r["xright"]+r["xleft"])/2, (r["ytop"]+r["ybottom"])/2, count)
})
I have 3D matrix of floating point numbers and I would like to produce a smoothed 3D surface of this matrix using R. Any suggestions are welcome. Thanks
Now I am using scatterplot3d ... But this function did not produce a smoothed surface
x<-read.table("/Users/me/Desktop/data.txt")
scatterplot3d(x$V1, x$V2, x$V3, highlight.3d = TRUE, angle = 30, col.axis = "blue", col.grid = "lightblue", cex.axis = 1.3, cex.lab = 1.1, pch = 20)
I think that mba.surf from the MBA package would be a good choice for the smoothing, and as larrydag above suggests, persp would be good to image it. The code below is from the help page for the mba.surf function (swap LIDAR for your 3 column dataframe):
data(LIDAR)
mba.int <- mba.surf(LIDAR, 300, 300, extend=TRUE)$xyz.est
# Two ways of imaging....
image(mba.int, xaxs="r", yaxs="r")
persp(mba.int, theta = 135, phi = 30, col = "green3", scale = FALSE,
ltheta = -120, shade = 0.75, expand = 10, border = NA, box = FALSE)
If you are able to create a 2D matrix (x,y) with the value being the z-axis value you could use the following
persp
Here is an example from R Graph Gallery. persp example
require(misc3d)
a <- 2/5
wsqr <- 1 - a^2
w <- sqrt(wsqr)
denom <- function(a,w,u,v) a*((w*cosh(a*u))^2 + (a*sin(w*v))^2)
fx <- function(u,v) -u + (2*wsqr*cosh(a*u)*sinh(a*u)/denom(a,w,u,v))
fy <- function(u,v) 2*w*cosh(a*u)*(-(w*cos(v)*cos(w*v)) - (sin(v)*sin(w*v)))/denom(a,w,u,v)
fz = function(u,v) 2*w*cosh(a*u)*(-(w*sin(v)*cos(w*v)) + (cos(v)*sin(w*v)))/denom(a,w,u,v)
parametric3d(fx = fx, fy = fy, fz = fz,
umin = -17,
umax = 17,
vmin = -77,
vmax = 77,
n = 100,
color = c("grey17","grey21","red4","darkred","red4","grey21","grey17"),
engine = "rgl")