I'd like to make a true heat map in R, much like a weather map, except my data is much more simple.
Consider this 3d data:
x <- c(1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4)
y <- c(1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5)
z <- rnorm(20)
The z would be color.
Here is what a discrete looking heatmap would like for this data:
How can I make a heatmap such that the colors are smooth and the full 2d space is filled with smoothed out colors based on the z values.
Please include sample code, not just a link that will probably confuse me even more, and I've probably already visited that site anyhow. Thanks :)
Use the following:
interp in the akima package
image.plot in the fields package
x <- c(1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4)
y <- c(1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5)
z <- rnorm(20)
library(fields)
library(akima)
s <- interp(x,y,z)
image.plot(s)
smooth.2d in the fields package does a good job (and it is much faster than interp from akima package for larger number of input points.
library(fields)
x <- c(1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4)
y <- c(1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5)
z <- rnorm(20)
s = smooth.2d(z, x=cbind(x,y), theta=0.5)
image.plot(s)
Related
I have a dataframe in which values c are specified for Cartesian coordinates (x, y). I use plot() and the result has too much space in Y-axis. Is there a way to edit that?
library(raster)
x <- c(1:60)
y <- c(2:5)
c <- rnorm(60)
Data1 <- data.frame(x, y, c)
raster1 <- rasterFromXYZ(Data1)
plot(raster1)
While not a fix, it helps to note that in plot(), xlim and ylim end up providing the max and min.
Obviously, it's handled differently in the raster library. When I use plot(raster1, ylim=c(2,5)), the axis isn't adjusted at all. However, if you use plot(raster1, xlim=c(0,20)) clearly affects the x-axis.
I'm not sure why it won't affect the y-axis.
I am trying to construct a graph consisting of 2-3 filled.contour plots next to each other. The color scale is the same for all plots, and I would like only one z value key plot. I am having difficulties to do this with par(mfrow=c(1,3))
Example code:
x <- 1:5
y <- 1:5
z <- matrix(outer(x,y,"+"),nrow=5)
filled.contour(x,y,z)
filled.contour(x,y,z,color.palette=rainbow)
z2 <- z
z2[5,5] <- Inf
filled.contour(x,y,z2,col=rainbow(200),nlevels=200)
Is it possible to stack 2-3 of these plots next to each other with only one z value color key? I can do this in GIMP but I was wondering if it is natively in R possible.
No I do not think this is possible in filled.contour.
Although extensions have been written for you already. To be found here, here and here and a legend code here.
[If you are using the filled.contour3 function referred to on those sites, and using a more recent version, then you need to use the upgrade fix referred to in this SO post].
Using those codes I produced:
It can be solved with cowplot.
The clue is the cowplot::draw_plot function which successfully represent the plot (cowplot::draw_grob(~filled.contour(x,y,z))).
Later the grob representations can be binded.
The possible problem is that each plot will have own legend.
x <- 1:5
y <- 1:5
z <- matrix(outer(x,y,"+"),nrow=5)
z2 <- z
z2[5,5] <- Inf
cowplot::plot_grid(~filled.contour(x,y,z), ~filled.contour(x,y,z,color.palette=rainbow), ~filled.contour(x,y,z2,col=rainbow(200),nlevels=200))
Created on 2023-02-14 with reprex v2.0.2
I want to create a 3d plot with densities.
I use the function density to first create a 2d dimensional plot for specific x values, the function then creates the density and puts them into a y variable. Now I have a second set of x values and put it again into the density function and I get a second set of y variables and so on....
I want to put those sets into a 3d plot, I hope you know what I mean. So I have a surface of densities....
E.g. I have:
x1<-c(1:10)
x2<-c(2:11)
y1<-c(1,1,2,1,3,4,2,3,2,2)
y2<-c(1,2,3,1,3,6,2,8,2,2)
.
.
.
.
Now I want to put on the x axis for the first value 1 the first set , on the y axis the corresponding x values and on the z axis the densities. So I have a "disk" for x=1, for x=2 I have the second "disk" and so on, so I get a density "mountain".
I hope I am understandable, if you have a better idea to realize it then you are welcome!
I want to do it with the persp function, would be nice if you make an example with that function,
Thanks a lot for your help.
I'm afraid I can't make head or tail out of your question. But here is how you draw a plot of the sort I think you are looking for from a two dimensional dataset for which you first estimate the bivariate density:
x <- rnorm(1000)
y <- 2 + x*rnorm(1000,1,.1) + rnorm(1000)
library(MASS)
den3d <- kde2d(x, y)
persp(den3d, box=FALSE)
Then there are many options for persp, check out
?persp
Building on Peter answer. The plot can now be more interesting, prettier and interactive with the plotly library.
x <- rnorm(1000)
y <- 2 + x*rnorm(1000,1,.1) + rnorm(1000)
library(MASS)
den3d <- kde2d(x, y)
# the new part:
library(plotly)
plot_ly(x=den3d$x, y=den3d$y, z=den3d$z) %>% add_surface()
which gives:
I have this problem. I got a heatmap, (but i suppose this applies to every plot) but I need to mirror my y-axis.
I got here some example code:
library(gstat)
x <- seq(1,50,length=50)
y <- seq(1,50,length=50)
z <- rnorm(1000)
df <- data.frame(x=x,y=y,z=z)
image(df,col=heat.colors(256))
This will generate the following heatmap
But I need the y-axis mirrored. Starting with 0 on the top and 50 on the bottom. Does anybody has a clue as to what I must do to change this?
See the help page for ?plot.default, which specifies
xlim: the x limits (x1, x2) of the plot. Note that ‘x1 > x2’ is
allowed and leads to a ‘reversed axis’.
library(gstat)
x <- seq(1,50,length=50)
y <- seq(1,50,length=50)
z <- rnorm(1000)
df <- data.frame(x=x,y=y,z=z)
So
image(df,col=heat.colors(256), ylim = rev(range(y)))
Does this work for you (it's a bit of a hack, though)?
df2<-df
df2$y<-50-df2$y #reverse oredr
image(df2,col=heat.colors(256),yaxt="n") #avoid y axis
axis(2, at=c(0,10,20,30,40,50), labels=c(50,40,30,20,10,0)) #draw y axis manually
The revaxis function in the plotrix package "reverses the sense of either or both the ‘x’ and ‘y’ axes". It doesn't solve your problem (Nick's solution is the correct one) but can be useful when you need to plot a scatterplot with reversed axes.
I would use rev like so:
df <- data.frame(x=x,y=rev(y),z=z)
In case you were not aware, notice that df is actually a function. You might want to be careful when overwriting. If you rm(df), things will go back to normal.
Don't forget to relabel the y axis as Nick suggests.
For the vertical axis increasing in the downward direction, I provided two ways (two different answers) for the following question:
R - image of a pixel matrix?
I have come across a number of situations where I want to plot more points than I really ought to be -- the main holdup is that when I share my plots with people or embed them in papers, they occupy too much space. It's very straightforward to randomly sample rows in a dataframe.
if I want a truly random sample for a point plot, it's easy to say:
ggplot(x,y,data=myDf[sample(1:nrow(myDf),1000),])
However, I was wondering if there were more effective (ideally canned) ways to specify the number of plot points such that your actual data is accurately reflected in the plot. So here is an example.
Suppose I am plotting something like the CCDF of a heavy tailed distribution, e.g.
ccdf <- function(myList,density=FALSE)
{
# generates the CCDF of a list or vector
freqs = table(myList)
X = rev(as.numeric(names(freqs)))
Y =cumsum(rev(as.list(freqs)));
data.frame(x=X,count=Y)
}
qplot(x,count,data=ccdf(rlnorm(10000,3,2.4)),log='xy')
This will produce a plot where the x & y axis become increasingly dense. Here it would be ideal to have fewer samples plotted for large x or y values.
Does anybody have any tips or suggestions for dealing with similar issues?
Thanks,
-e
I tend to use png files rather than vector based graphics such as pdf or eps for this situation. The files are much smaller, although you lose resolution.
If it's a more conventional scatterplot, then using semi-transparent colours also helps, as well as solving the over-plotting problem. For example,
x <- rnorm(10000); y <- rnorm(10000)
qplot(x, y, colour=I(alpha("blue",1/25)))
Beyond Rob's suggestions, one plot function I like as it does the 'thinning' for you is hexbin; an example is at the R Graph Gallery.
Here is one possible solution for downsampling plot with respect to the x-axis, if it is log transformed. It log transforms the x-axis, rounds that quantity, and picks the median x value in that bin:
downsampled_qplot <- function(x,y,data,rounding=0, ...) {
# assumes we are doing log=xy or log=x
group = factor(round(log(data$x),rounding))
d <- do.call(rbind, by(data, group,
function(X) X[order(X$x)[floor(length(X)/2)],]))
qplot(x,count,data=d, ...)
}
Using the definition of ccdf() from above, we can then compare the original plot of the CCDF of the distribution with the downsampled version:
myccdf=ccdf(rlnorm(10000,3,2.4))
qplot(x,count,data=myccdf,log='xy',main='original')
downsampled_qplot(x,count,data=myccdf,log='xy',rounding=1,main='rounding = 1')
downsampled_qplot(x,count,data=myccdf,log='xy',rounding=0,main='rounding = 0')
In PDF format, the original plot takes up 640K, and the downsampled versions occupy 20K and 8K, respectively.
I'd either make image files (png or jpeg devices) as Rob already mentioned, or I'd make a 2D histogram. An alternative to the 2D histogram is a smoothed scatterplot, it makes a similar graphic but has a more smooth cutoff from dense to sparse regions of space.
If you've never seen addictedtor before, it's worth a look. It has some very nice graphics generated in R with images and sample code.
Here's the sample code from the addictedtor site:
2-d histogram:
require(gplots)
# example data, bivariate normal, no correlation
x <- rnorm(2000, sd=4)
y <- rnorm(2000, sd=1)
# separate scales for each axis, this looks circular
hist2d(x,y, nbins=50, col = c("white",heat.colors(16)))
rug(x,side=1)
rug(y,side=2)
box()
smoothscatter:
library("geneplotter") ## from BioConductor
require("RColorBrewer") ## from CRAN
x1 <- matrix(rnorm(1e4), ncol=2)
x2 <- matrix(rnorm(1e4, mean=3, sd=1.5), ncol=2)
x <- rbind(x1,x2)
layout(matrix(1:4, ncol=2, byrow=TRUE))
op <- par(mar=rep(2,4))
smoothScatter(x, nrpoints=0)
smoothScatter(x)
smoothScatter(x, nrpoints=Inf,
colramp=colorRampPalette(brewer.pal(9,"YlOrRd")),
bandwidth=40)
colors <- densCols(x)
plot(x, col=colors, pch=20)
par(op)