I hope you can help me. I have the idea of visualizing segments within a plot with a rectangle that can be placed next to the y or x-axis which means that it would be outside of the plot area. It should look similar as in the image below:
I tried to reach the mentioned output by trying two different approaches:
I created two viewports with the grid package and put the plot in one viewport that I placed at the bottom and one viewport on top of that. The big problem here is that I need the coordinates from where the grey background panel of the ggplot starts so I can place the top viewport exactly there, so that the segments conincide with the x-axis length. My code looked like following:
container_viewport <- viewport(x=0,y=0,height=1,width=1,just = c("left","bottom"))
pushViewport(container_viewport)
grid.draw(rectGrob())
popViewport()
section_viewport <- viewport(x=0.055,y=0.99,height=0.085,width=0.935,just=c("left","top"))
pushViewport(section_viewport)
plot_obj <- ggplot_build(testplot)
plot_data <- plot_obj$data[[1]]
grid.draw(rectGrob(gp = gpar(col = "red")))
popViewport()
plot_viewport <- viewport(x=0,y=0,height=0.9,width=1,just=c("left","bottom"))
pushViewport(plot_viewport)
grid.draw(ggplotGrob(testplot))
popViewport()
This looks fine but I had to hardcode the coordinates of the viewport at the top.
I used grid.arrange() to arrange to stack the plots vertically (instead of a grob for the rectangle like in the other approach I create a ggplot instead for that). Here, basically the same problem exists, since I somehow need to put the plot representing the rectangle at the top in the right position on the x-axis. My code looked like following:
p1 <- plot_data %>%
ggplot()+
geom_rect(aes(xmin=-Inf,xmax=Inf,ymin=-Inf,ymax=Inf))
p2 <- testplot
test_plot <- grid.arrange(p1,p2,heights=c(1,10))
This approach does not work that good.
Since I would like to create a solution that can be applied generally, trial and error with the coordinates of the viewport is no option since the length of the y-axis label or tick labels can vary and therefore the length and coordinates of the background panel. When this step is done the segmentation of the rectangle should be no problem anymore.
Maybe this is just not possible but if then I would appreciate any help.
Thank you!
I would probably use patchwork here. Let's start by replicating your plot:
library(ggplot2)
library(patchwork)
p <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point(color = "red") +
labs(x = "test", y = "test")
p
That looks very similar. Now we define (in our own co-ordinates) where we want the section split to occur on the x axis.
section_split <- 5.25
Using just this number, we add rectangles and text annotations that cover a copy of our original plot, and remove its axis annotations using theme_void:
p2 <- p +
annotate("rect", xmin = c(-Inf, section_split), ymin = c(-Inf, -Inf),
xmax = c(section_split, Inf), ymax = c(Inf, Inf),
fill = c("#00a2e8", "#ff7f27")) +
annotate("text", label = c("Section A", "Section B"), size = 6,
y = rep(mean(layer_scales(p)$y$range$range), 2),
x = c((min(layer_scales(p)$x$range$range) + section_split)/2,
(max(layer_scales(p)$x$range$range) + section_split)/2)) +
theme_void()
Now we just draw this second plot above our first, adjusting the relative heights to about 1:10
p2/p + plot_layout(heights = c(1, 10))
The benefit of doing it this way is that, since we copied the original plot, the positional mapping of the x axis is identical between the two plots, and patchwork will automatically line up the panels.
Created on 2023-02-04 with reprex v2.0.2
Related
I am currently creating some histograms in R using ggplot that have many bins and a large data set (850 000 elements).
As a result the vertical lines of each bin are filling in the area under the histogram with the line colour due to there close proximity. I would ideally like this to be clear so I can plot another histogram on the same plot.
Ideally, I would like a histogram with the bin lines hidden where they overlap with another bin so It looks similar to a line plot.
Below is the ggplot code I'm using:
ggplot(df, aes(x=eev)) +
geom_histogram(binwidth = 18,color="black") +
xlim(0,10000) +
scale_y_log10(name="Log of Counts", labels = scales::comma) +
xlab("Incident Energy in eV")
I can't really fiddle around with the bin size too much because I need the definition from the naarrow bins.
I've had a look through the ggplot documentation but can't find what I'm after.
Cheers
Edit:
Following MrFlicks advice I've made some reproducible code
a<-runif(10000, 0, 10)
b<-seq(0,9.999, by = 1/1000)
var<-data.frame(a,b)
ggplot(var, aes(x=a)) +
geom_histogram(binwidth = 0.3, col = "black", fill = "#ffffff00")
This gives the following output
Histogram with bin lines
However I need the final histogram to look like this
Histogram without overlapping bin lines
I can't use geom_freqpoly as the data needs to be presented as a histogram.
Here is the current histogram for some of the real data
Cheers again.
Also, apologies this is the first time posting on stack overflow if my post layout is off etc.
Maybe using hist to generate the values then plotting in ggplot:
library(ggplot2)
set.seed(1)
x = hist(rchisq(1000, df = 4), 100)
df = data.frame(
x = rep(x$breaks, each=2),
y = c(0, rep(x$counts, each = 2), 0))
ggplot(df, aes(x,y)) +
geom_polygon(fill='grey80') +
geom_line(col='red')
Setting a transparent color like #ffffff00 (the last two digits setting opacity to zero) should do the trick. Control the fill colour (the inner of the histogram columns) with, well: fill.
Example:
data.frame(x = rnorm(10000)) %>%
ggplot() +
geom_histogram(aes(x),
fill = 'blue',
binwidth = .025,
col='#ffffff00'
)
Note that while you can increase the border thickness of the columns with the size argument, setting size = 0 does not fully remove the border.
I have a ggplot object. I want to use annotate() to add a label to the top of the plot, so that the upper edge of the label is also the upper edge of the plot. When using default settings, this doesn't seem possible: adding an annotation at the upper edge of the plot causes the upper y-limit to increase.
One can get around this problem by specifying scale_y_continuous(expand = c(0, 0)) when creating the plot. But I don't want to do that, partly because I like the y limits created by the default expand setting. Given this constraint, is it possible to use annotate() to position a label at the top of the plot?
Here is a minimal example that demonstrates the problem:
library(ggplot2)
p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
yMax <- layer_scales(p)$y$range$range[2] # upper y-limit
p + annotate("label", x = 30, y = yMax, vjust = "top", label = "X")
And here is the result:
You see that the annotation is not at the top of the plot. Instead, consistent with the default "expand" settings, the y-limit of the plot has changed.
Possible solutions:
Figure out the y-limits implied by the default expand setting. Then use scale_y_continuous() to both set the y limits and set expand = c(0, 0). This solution will give me the y limits that I want, and it will place the label appropriately. I know how to implement it, but it seems a bit cumbersome. It would also prevent other annotations at the top of the figure from changing the y-limit of the plot -- and I don't want the solution to affect annotations other than the one that I describe here.
Use annotation_custom(), which doesn't change plot limits in the same way. #baptiste suggests a solution like that in this answer to a different question. But annotation_custom() requires a grob. In practice, the annotations that I use may be more complicated than the label in this example, and I won't always know how to create them as a grob that can be passed to annotation_custom(). In addition, I've had some trouble positioning grobs with annotation_custom() while also specifying their exact sizes.
That said, I am quite open to annotation_custom()-based solutions. And perhaps there are solutions other than the two that I've sketched above.
I've read many SO posts on changing plot limits, but I haven't found any that speak to this problem.
A simple solution for that is setting y = Inf instead of using the maximum value found of the y-axis (yMax). The code would be like that then:
# load library
library(ggplot2)
# load data
data(mtcars)
# define plot
p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p + annotate("label", x = 30, y = Inf, vjust = "top", label = "X")
Here is the output:
Let me know if this is what you're looking for.
Does this help?
library(ggplot2)
data(mtcars)
ggplot(mtcars, aes(mpg, wt)) +
geom_point() +
geom_text(label = "X", x = 30, y = max(mtcars$wt))
I'm trying to find a way to insert an image into the corner of a ggplot panel, without specifying the coordinates manually each time.
In this instance, I'm attempting to place a graphic in the top right.
library(magick)
library(ggplot2)
library(datasets)
homer <- magick::image_read("http://icons.iconarchive.com/icons/jonathan-rey/simpsons/128/Homer-Simpson-04-Happy-icon.png")
g <- ggplot(mpg, aes(class)) +
geom_bar() +
labs(
title = "Count of Auto by Class",
subtitle = "Text to Create More Space")
g + annotation_custom(rasterGrob(homer, interpolate = TRUE),
xmax = Inf, ymax = Inf) +
coord_cartesian(clip = "off")
I have found some examples that come close to solving this:
Inserting an image to ggplot outside the chart area
Corner Labels in ggplot2
But neither quite get there. Specifying the exact location at which to place the image seems to require quite a bit of trial-and-error on each plot created, especially when x is categorical.
I would also like to maintain the size of my original image; the code I've used above seems to stretch it across the plot.
Thanks in advance...much appreciated.
try this
library(grid)
a <- rasterGrob(homer, interpolate = TRUE,
width=unit(1,'cm'),
x = unit(1,"npc"), y = unit(1,"npc"),
hjust = 1, vjust=1)
g + annotation_custom(grob = a)
When creating a geom_histogram in ggplot, the bin labels appear directly underneath the bars. How can I make it so that they appear on either side of the bin, so that they describe the range of each bin (so that the bin that includes cases from 0 to 10 will appear between the 0 and 10 labels)?
I tried using
geom_histogram(position=position_nudge(5))
However, the histogram I'm using is stacked (to differentiate categories within each bin), and this effect is ruined when I add this position. Is there another way of doing it? Maybe moving the axis labels themselves instead of the bars?
Reproducible code:
dd<-data.frame(nums=c(1:20,15:30,40:55),cats=c(rep("a",20),rep("b",30),rep("c",2)))
ggplot(dd, aes(nums))+geom_histogram(aes(nums,fill=cats),dd,binwidth = 10)
results in this:
I want the bars to be shifted to the right by 5, so that the 0 aligns with the left-hand side of the histogram
You can try to define breaks and labels
n <- 10
ggplot(dd, aes(nums, fill=cats)) +
geom_histogram(binwidth = n, boundary = 0) +
scale_x_continuous(breaks = seq(0,55,n), labels = seq(0,55, n))
The following moves the labels of the axis. I wasn't sure how to move the ticks on the x axis so I removed them.
ggplot(dd, aes(nums))+geom_histogram(aes(nums),dd,binwidth = 10)+
theme(axis.text.x = element_text(hjust = 5),
axis.ticks.x = element_blank())
I would like to be able to adjust the positions of the loading labels, so that they do not fall atop the the arrows. However, I do not know where the adjustments need to be made. The geom_text can be used to adjust the position of the site positions, but I cannot find where the vectors are stored in str(g).
library(ggplot2)
library(ggfortify)
df <- data.frame(replicate(10,sample(-10:10,10,rep=TRUE)))
names(df) <- c('up','down','left','right','circle','square','triangle','x','r1','l1')
rownames(df) <- paste('Dummy Site', seq(0,9,1))
g <- autoplot(prcomp(df[,-11], scale=TRUE), data=df,
loadings.label=TRUE, loadings=TRUE,
loadings.label.size=8, loadings.colour='blue',
label.size=5) +
geom_text(vjust=-1, label=rownames(df)) +
theme(plot.background=element_blank(),
panel.background=element_rect(fill='transparent',color='black',size=1),
legend.text=element_text(hjust=1),
legend.key=element_blank())
g
I've looked in ggplot2::theme and I've examined the help docs for autoplot, but can't find any mention of the adjusting label position. Bonus points if it can adjust based on the vector of the arrow, but a static adjustment would be acceptable.
Currently, here is what the plot looks like:
You can get the coordinates by layer_data(g, 2). But autoplot(prcomp.obj) passes other arguments to ggbiplot(), so you can change label and loadings.label position using arguments of ggbiplot(), such as loadings.label.hjust (see ?ggbiplot).
example code:
arrow_ends <- layer_data(g, 2)[,c(2,4)]
autoplot(prcomp(df[,-11], scale=TRUE), data=df,
loadings.label=TRUE, loadings=TRUE,
loadings.label.size=8, loadings.colour='blue',
label.size=5, loadings.label.vjust = 1.2) + # change loadings.label position
geom_point(data = arrow_ends, aes(xend, yend), size = 3) + # the coordinates from layer_data(...)
geom_text(vjust=-1, label=rownames(df)) +
theme(plot.background=element_blank(),
panel.background=element_rect(fill='transparent',color='black',size=1),
legend.text=element_text(hjust=1),
legend.key=element_blank())