I am creating a plot of hexbin data in R, in which the color represents the number of data points in each hexbin. I seem to have this working as is shown in the MWE below:
library(hexbin)
library(ggplot2)
set.seed(1)
data <- data.frame(A=rnorm(100), B=rnorm(100), C=rnorm(100), D=rnorm(100), E=rnorm(100))
maxVal = max(abs(data))
maxRange = c(-1*maxVal, maxVal)
x = data[,c("A")]
y = data[,c("E")]
h <- hexbin(x=x, y=y, xbins=5, shape=1, IDs=TRUE, xbnds=maxRange, ybnds=maxRange)
hexdf <- data.frame (hcell2xy (h), hexID = h#cell, counts = h#count)
p <- ggplot(hexdf, aes(x=x, y=y, fill = counts, hexID=hexID)) + geom_hex(stat="identity") + coord_cartesian(xlim = c(maxRange[1], maxRange[2]), ylim = c(maxRange[1], maxRange[2]))
I am now trying to superimpose a subset of the original data in the form of points on top of the hexbin plot. I first create the subset of the original data as follows:
dat <- data[c(1:5),]
Then, I tried to plot these five data points onto the hexbin plot, p:
p + geom_point(data = dat, aes(x=A, y=B))
For which I receive the Error: "Error in eval(expr, envir, enclos) : object 'counts' not found". I also tried the following:
p + geom_point() + geom_point(dat, aes(A, B))
For which I receive the Error: "Error: ggplot2 doesn't know how to deal with data of class uneval".
I tried several new ideas based on similar posts - but would always have an error and no resulting plot. I am wondering if such a technique is possible. If anyone has ideas to share, I would very much appreciate your input!
To solve this problem, we need to set inherit.aes = FALSE in your geom_point call. Basically, you've set the fill aesthetic equal to count in your ggplot call, so when ggplot tries to add the points to the plot, it looks for count in dat. ggplot is telling you "hey, I can't find count in this data set, so I can't add that geom since it's missing an aes".
p + geom_point(data = dat, aes(x=A, y=B),
inherit.aes = FALSE)
Or, we could define p as:
p <- ggplot() +
geom_hex(data = hexdf, aes(x=x, y=y, fill = counts), stat="identity") +
coord_cartesian(xlim = c(maxRange[1], maxRange[2]), ylim = c(maxRange[1], maxRange[2]))
And then we wouldn't need inhert.aes:
p + geom_point(data = dat, aes(x = A, y = B))
Related
The following sample or R code displays contour levels and the data points used in generating the contours.
n <- 10
x <- c(rnorm(n,-1,0.5), rnorm(n,1,0.5))
y <- c(rnorm(n,-1,1), rnorm(n,1,0.5))
df <- data.frame(x,y)
# categorise the points
df$cat <- sample(c(1,2), n, replace=T)
library(ggplot2)
p <- ggplot(df)
# for manual colouring of points, but not showing contours due to error
#p <- p + geom_point(aes(x=x,y=y,col=factor(cat)))
#cols <- c("1"="red", "2"="blue")
#p <- p + scale_color_manual(values=cols)
# this works fine except I am not controlling the colours
p <- p + geom_point(aes(x=x,y=y,col=cat))
p <- p + geom_density2d(aes(x=x,y=y,color=..level..))
print(p)
I am able to colour the points according to their binary category (see commented out code above) manually if I do not display the contours, but adding the contours results in a "Continuous value supplied to discrete scale" error.
Various attempts have failed.
The question: Is it possible to colour the points (according to category) and independently colour the contour levels (according to height)?
You can try
library(tidyverse)
df %>%
ggplot(aes(x=x,y=y)) +
stat_density_2d(aes(fill = ..level..), geom = "polygon") +
geom_point(aes(color=factor(cat)), size=5) +
theme_bw()
Or switch to points where fill is working like shape=21
df %>%
ggplot(aes(x=x,y=y)) +
geom_density2d(aes(color=..level..))+
geom_point(aes(fill=factor(cat)),color="black",shape=21, size=5) +
theme_bw() +
scale_fill_manual(values = c(2,4)) +
scale_color_continuous(low = "green", high = "orange")
or try to add scale_color_gradientn(colours = rainbow(10)) instead.
I have discreet data that looks like this:
height <- c(1,2,3,4,5,6,7,8)
weight <- c(100,200,300,400,500,600,700,800)
person <- c("Jack","Jim","Jill","Tess","Jack","Jim","Jill","Tess")
set <- c(1,1,1,1,2,2,2,2)
dat <- data.frame(set,person,height,weight)
I'm trying to plot a graph with same x-axis(person), and 2 different y-axis (weight and height). All the examples, I find is trying to plot the secondary axis (sec_axis), or discreet data using base plots.
Is there an easy way to use sec_axis for discreet data on ggplot2?
Edit: Someone in the comments suggested I try the suggested reply. However, I run into this error now
Here is my current code:
p1 <- ggplot(data = dat, aes(x = person, y = weight)) +
geom_point(color = "red") + facet_wrap(~set, scales="free")
p2 <- p1 + scale_y_continuous("height",sec_axis(~.*1.2, name="height"))
p2
I get the error: Error in x < range[1] :
comparison (3) is possible only for atomic and list types
Alternately, now I have modified the example to match this example posted.
p <- ggplot(dat, aes(x = person))
p <- p + geom_line(aes(y = height, colour = "Height"))
# adding the relative weight data, transformed to match roughly the range of the height
p <- p + geom_line(aes(y = weight/100, colour = "Weight"))
# now adding the secondary axis, following the example in the help file ?scale_y_continuous
# and, very important, reverting the above transformation
p <- p + scale_y_continuous(sec.axis = sec_axis(~.*100, name = "Relative weight [%]"))
# modifying colours and theme options
p <- p + scale_colour_manual(values = c("blue", "red"))
p <- p + labs(y = "Height [inches]",
x = "Person",
colour = "Parameter")
p <- p + theme(legend.position = c(0.8, 0.9))+ facet_wrap(~set, scales="free")
p
I get an error that says
"geom_path: Each group consists of only one observation. Do you need to
adjust the group aesthetic?"
I get the template, but no points get plotted
R function arguments are fed in by position if argument names are not specified explicitly. As mentioned by #Z.Lin in the comments, you need sec.axis= before your sec_axis function to indicate that you are feeding this function into the sec.axis argument of scale_y_continuous. If you don't do that, it will be fed into the second argument of scale_y_continuous, which by default, is breaks=. The error message is thus related to you not feeding in an acceptable data type for the breaks argument:
p1 <- ggplot(data = dat, aes(x = person, y = weight)) +
geom_point(color = "red") + facet_wrap(~set, scales="free")
p2 <- p1 + scale_y_continuous("weight", sec.axis = sec_axis(~.*1.2, name="height"))
p2
The first argument (name=) of scale_y_continuous is for the first y scale, where as the sec.axis= argument is for the second y scale. I changed your first y scale name to correct that.
I'm trying to generate a ggplot only C.D.F. plot for some of my data. I am also looking to be able to plot an arbitrary number of percentiles as points on top. I have a solution that works for adding a single point to my curve but fails for multiple values.
This works for plotting one percentile value
TestDf <- as.data.frame(rnorm(1000))
names(TestDf) <- c("Values")
percentiles <- c(0.5)
ggplot(data = TestDf, aes(x = Values)) +
stat_ecdf() +
geom_point(aes(x = quantile(TestDf$Values, percentiles),
y = percentiles))
However this fails
TestDf <- as.data.frame(rnorm(1000))
names(TestDf) <- c("Values")
percentiles <- c(0.25,0.5,0.75)
ggplot(data = TestDf, aes(x = Values)) +
stat_ecdf() +
geom_point(aes(x = quantile(TestDf$Values, percentiles),
y = percentiles))
With error
Error: Aesthetics must be either length 1 or the same as the data (1000): x, y
How can I add an arbitrary number of points to a stat_ecdf() plot?
You need to define a new dataset, outside of the aesthetics. aes refers to the original dataframe that you used for making the CDF (in the original ggplot argument).
ggplot(data = TestDf, aes(x = Values)) +
stat_ecdf() +
geom_point(data = data.frame(x=quantile(TestDf$Values, percentiles),
y=percentiles), aes(x=x, y=y))
I am using hexbin() to bin data into hexagon objects, and ggplot() to plot the results. I notice that, sometimes, the binning data frame contains a different number of hexagons than the plot that results from plotting that same binning data frame. Below is an example.
library(hexbin)
library(ggplot2)
set.seed(1)
data <- data.frame(A=rnorm(100), B=rnorm(100), C=rnorm(100), D=rnorm(100), E=rnorm(100))
maxVal = max(abs(data))
maxRange = c(-1*maxVal, maxVal)
x = data[,c("A")]
y = data[,c("E")]
h <- hexbin(x=x, y=y, xbins=5, shape=1, IDs=TRUE, xbnds=maxRange, ybnds=maxRange)
hexdf <- data.frame (hcell2xy (h), hexID = h#cell, counts = h#count)
# Both objects below indicate there are 17 hexagons
# hexdf
# table(h#cID)
# However, plotting only shows 16 hexagons
ggplot(hexdf, aes(x=x, y=y, fill = counts, hexID=hexID)) + geom_hex(stat="identity") + scale_x_continuous(limits = maxRange) + scale_y_continuous(limits = maxRange)
In this example, the hexdf data frame contains 17 hexagons. However, the ggplot(hexdf) resulting plot only shows 16 hexagons, as is shown below.
Note: Syntax in the above example may seem cumbersome, but some of it is because this is a MWE for a more complex goal and I am intentionally keeping those components so that any possible solution might extend to my more complex goal. For instance, I want to maintain the capability to allow for the maxRange variable to be computed from the original data frame called data (which contains additional columns "B", "C", and "D"). At the same time, there may be parts of my syntax that are unnecessarily cumbersome and may be causing the problem - so I am happy to try to fix them to see.
Any ideas what might be causing this discrepancy and how to fix it? Thank you!
The last hexagon is missing as it's (partly) outside the limits you set. It's included if you change the limits, e.g. like so:
ggplot(hexdf, aes(x = x, y = y, fill = counts, hexID = hexID)) +
geom_hex(stat = "identity") +
scale_x_continuous(limits = maxRange * 1.5) +
scale_y_continuous(limits = maxRange * 1.5)
or by using coord_cartesian instead:
ggplot(hexdf, aes(x = x, y = y, fill = counts, hexID = hexID)) +
geom_hex(stat = "identity") +
coord_cartesian(xlim = c(maxRange[1], maxRange[2]), ylim = c(maxRange[1], maxRange[2]))
I have data where I look at the difference in growth between a monoculture and a mixed culture for two different species. Additionally, I made a graph to make my data clear.
I want a barplot with error bars, the whole dataset is of course bigger, but for this graph this is the data.frame with the means for the barplot.
plant species means
Mixed culture Elytrigia 0.886625
Monoculture Elytrigia 1.022667
Monoculture Festuca 0.314375
Mixed culture Festuca 0.078125
With this data I made a graph in ggplot2, where plant is on the x-axis and means on the y-axis, and I used a facet to divide the species.
This is my code:
limits <- aes(ymax = meansS$means + eS$se, ymin=meansS$means - eS$se)
dodge <- position_dodge(width=0.9)
myplot <- ggplot(data=meansS, aes(x=plant, y=means, fill=plant)) + facet_grid(. ~ species)
myplot <- myplot + geom_bar(position=dodge) + geom_errorbar(limits, position=dodge, width=0.25)
myplot <- myplot + scale_fill_manual(values=c("#6495ED","#FF7F50"))
myplot <- myplot + labs(x = "Plant treatment", y = "Shoot biomass (gr)")
myplot <- myplot + opts(title="Plant competition")
myplot <- myplot + opts(legend.position = "none")
myplot <- myplot + opts(panel.grid.minor=theme_blank(), panel.grid.major=theme_blank())
So far it is fine. However, I want to add two different horizontal lines in the two facets. For that, I used this code:
hline.data <- data.frame(z = c(0.511,0.157), species = c("Elytrigia","Festuca"))
myplot <- myplot + geom_hline(aes(yintercept = z), hline.data)
However if I do that, I get a plot were there are two extra facets, where the two horizontal lines are plotted. Instead, I want the horizontal lines to be plotted in the facets with the bars, not to make two new facets. Anyone a idea how to solve this.
I think it makes it clearer if I put the graph I create now:
Make sure that the variable species is identical in both datasets. If it a factor in one on them, then it must be a factor in the other too
library(ggplot2)
dummy1 <- expand.grid(X = factor(c("A", "B")), Y = rnorm(10))
dummy1$D <- rnorm(nrow(dummy1))
dummy2 <- data.frame(X = c("A", "B"), Z = c(1, 0))
ggplot(dummy1, aes(x = D, y = Y)) + geom_point() + facet_grid(~X) +
geom_hline(data = dummy2, aes(yintercept = Z))
dummy2$X <- factor(dummy2$X)
ggplot(dummy1, aes(x = D, y = Y)) + geom_point() + facet_grid(~X) +
geom_hline(data = dummy2, aes(yintercept = Z))