Related
I can't solve a problem I found when plotting and saving an image from raster with the ggsave() function in R.
When I plot it, it works well. When I use ggsave() to export it, horizontal gray lines are added to the plot.
I want to remove them but I don't know how to do it.
That's an example image with the options and the code I used:
gg.opzioni = list(geom_tile(aes(x, y, fill = values)),
scale_fill_gradientn(n.breaks = 3, colours = c("#52647A", "#2C413C", "#646859"), guide = "legend", na.value = "white"),
theme(plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
axis.title.x = element_text(size = 12), axis.title.y = element_text(size = 12),
plot.margin = unit(c(2, 2, 2, 2), "mm"), panel.background = element_blank(),
panel.border = element_rect(colour = "black", fill = NA, size = 1),
axis.text.x = element_blank(), axis.ticks.x = element_blank(), axis.text.y = element_blank(),
axis.ticks.y = element_blank(), panel.grid.minor = element_blank(), panel.grid.major = element_blank(),
panel.grid.major.x = element_blank(), panel.grid.major.y = element_blank(),
panel.grid.minor.x = element_blank(), panel.grid.minor.y = element_blank(), aspect.ratio = 11/10),
scale_x_continuous(limits = c(0, 1), expand = c(0, 0), breaks = seq(0, 1, 0.1), labels = seq(0, 10, 1)),
scale_y_continuous(limits = c(0, 1), expand = c(0, 0), breaks = seq(0, 1, 0.1), labels = seq(0, 10, 1)),
coord_fixed())
r.sam = ggplot(df) + gg.opzioni + labs(title = "Campione ricostruito", x = "", y = "", fill = "classe:")
ggsave(filename = "lapalma_sam.png", plot = r.sam, device = "png", path = "/Users/Francesco/Downloads/")
I tried to remove the possible grid with the panel.grid options, but it didn't work.
Originally three variables are included in the df object: two of coordinates and one with the pixel class.
library(tidyverse)
df <- tibble(
val = rep(sin(seq(0, 4*pi, length = 100)), 100),
x = rep(1:100, 100),
y = rep(1:100, each = 100)
)
The following replicates your problem, where horizontal lines are visible around each cell:
plot.tiles <- ggplot(data = df, aes(x = x, y = y, fill = val)) +
geom_tile()
ggsave('plot_tile.png', plot.tiles)
This arises because geom_tile() has a border color property. One solution is to make the "color" aesthetic match the "fill" aesthetic:
plot.border <- ggplot(data = df, aes(x = x, y = y, fill = val, color = val)) +
geom_tile()
ggsave('plot_border.png', plot.border)
Or you can use geom_raster(), which does not have a cell border, but functions similarly to geom_tile():
plot.raster <- ggplot(data = df, aes(x = x, y = y, fill = val)) +
geom_raster()
ggsave('plot_raster.png', plot.raster)
I have been trying to create a graph that has non-linear (and non-log) based scaling on the axis. Ideally the graph would not be discontinuous. It is hard to explain so I will show it with pictures. My current graph uses a ln transformed scale to give:
The problem is most of my data is log normally skewed, and I would ideally like to have the large majority of the data centered on the graph. If I could do this perfectly, the axis would scale like:
Upper 20% of graph = 1,001-40,000
Mid 30% of graph = 201-1,000
Lower 50% of graph = 1-200
To attempt this, I have tried the package: gg.gap. I thought using a discontinuous axis would be good, but that introduces white spaces. From what I can tell, these cannot be minimized. I have also tried to facet three graphs vertically. Using cowplots I have achieved this:
This is much closer to what I want, but the problem is that the white space still exist, and the way that the plot margins work, it ends up cutting some data point off in half, leaving weird half circles at the extremities. - Note: I fixed this now with " coord_cartesian(clip = "off")", the points are no longer clipped.
To solve this I am at a loss and thought I would reach out for some help. Here is a minimal reproducible code (still long but it shows everything that produces each graph).
#Generate Random Data set:
set.seed(1)
graphdata <-as.data.frame(rlnorm(29000, meanlog = 4.442651, sdlog = 0.85982))
colnames(graphdata)[1] <- "values"
high_values <- as.data.frame(rlnorm(1000, meanlog = 9.9, sdlog = 0.85))
colnames(high_values)[1] <- "values"
graphdata <- rbind(graphdata,high_values)
graphdata$values <- round(graphdata$values, digits = 0)
#Current Plot
#I used 'Trans = 'log'' to set the axis to a natural log scale. It has worked until my data have become large enough that I need to change the scaling of the axis for better visibility.
library(tidyverse)
graph <- ggplot(graphdata, aes(y = values, x=1))+
geom_jitter(aes(colour = cut(values, c(0,100,200,Inf))), alpha = 0.2, size = 0.5)+
scale_color_manual(values = c("#F0CF19","#F07C0B", "#D52828"))+
scale_y_continuous(breaks = c(0,20,50,100,200,500,1000,2000,5000,10000,20000,40000), trans='log', limits = c(14, 40001), expand = c(0, 0))+
labs(y = "Values", x = NULL)+
scale_x_continuous(expand = c(0.01, 0))+ coord_cartesian(clip = "off")+
theme_classic()+
theme(legend.position = "none",
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.line.x = element_blank())
graph
#My attempt to get an altered axis arrangement - using multiple plots and stacking them:
graph1 <- ggplot(graphdata, aes(y = values, x=1))+
geom_jitter(aes(colour = cut(values, c(0,100,200,Inf))), alpha = 0.2, size = 0.5)+
scale_color_manual(values = c("#F0CF19","#F07C0B", "#D52828"))+
scale_y_continuous(breaks = c(0,20,50,100,200), trans='log', limits = c(14, 200), expand = c(0, 0))+
labs(y = NULL, x = NULL)+
scale_x_continuous(expand = c(0.01, 0))+
theme_classic()+ coord_cartesian(clip = "off")+
theme(legend.position = "none",
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.line.x = element_blank(),
plot.margin = margin(t=0, unit = "pt"))
graph1
graph2 <- ggplot(graphdata, aes(y = values, x=1))+
geom_jitter(aes(colour = cut(values, c(0,100,200,Inf))), alpha = 0.2, size = 0.5)+
scale_color_manual(values = c("#F0CF19","#F07C0B", "#D52828"))+
scale_y_continuous(breaks = c(500,1000), trans='log', limits = c(201, 1000), expand = c(0, 0))+
labs(y = "Values", x = NULL)+
scale_x_continuous(expand = c(0.01, 0))+
theme_classic()+ coord_cartesian(clip = "off")+
theme(legend.position = "none",
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.line.x = element_blank(),
plot.margin = margin(t=0, unit = "pt"))
graph2
graph3 <- ggplot(graphdata, aes(y = values, x=1))+
geom_jitter(aes(colour = cut(values, c(0,100,200,Inf))), alpha = 0.2, size = 0.5)+
scale_color_manual(values = c("#F0CF19","#F07C0B", "#D52828"))+
scale_y_continuous(breaks = c(10000,20000,40000), trans='log', limits = c(1001, 40001), expand = c(0, 0))+
labs(y = NULL,x = NULL)+
scale_x_continuous(expand = c(0.01, 0))+
theme_classic()+ coord_cartesian(clip = "off")+
theme(legend.position = "none",
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.line.x = element_blank(),
plot.margin = margin(t=0, unit = "pt"))
graph3
#Using Cowplot, I stichted together three panels to make one graph that is close to what I want. But the problem lies with the white space between the panels. I want to get rid of it. Also, this method leads to some points being cut-off, leaving wierd half circles.
library(cowplot);library(grid); library(egg)
graph4 <- cowplot::plot_grid(graph3, graph2, graph1, align = "v", ncol = 1, rel_heights = c(0.25,0.25,0.5))
graph4 <- set_panel_size(graph4, width = unit(7, "cm"), height = unit(6, "cm"))
grid.newpage()
grid.draw(graph4)
Thanks!
New, non-clipped image:
It looks like I needed to add in a layer of 'NULL' graphs to adjust the spacing of the white space. I made sure that my plot margins were 0 for top and bottom and then added in a NULL graph and adjusted the spacing to be negative. Here is the adjusted code:
#Generate Random Data set:
set.seed(1)
graphdata <-as.data.frame(rlnorm(29000, meanlog = 4.442651, sdlog = 0.85982))
colnames(graphdata)[1] <- "values"
high_values <- as.data.frame(rlnorm(1000, meanlog = 9.9, sdlog = 0.85))
colnames(high_values)[1] <- "values"
graphdata <- rbind(graphdata,high_values)
graphdata$values <- round(graphdata$values, digits = 0)
graph1 <- ggplot(graphdata, aes(y = values, x=1))+
geom_jitter(aes(colour = cut(values, c(0,100,200,Inf))), alpha = 0.2, size = 0.5)+
scale_color_manual(values = c("#F0CF19","#F07C0B", "#D52828"))+
scale_y_continuous(breaks = c(0,20,50,100,200), trans='log', limits = c(14, 200), expand = c(0, 0))+
labs(y = NULL, x = NULL)+
scale_x_continuous(expand = c(0.01, 0))+
theme_classic()+
coord_cartesian(clip = "off")+
theme(legend.position = "none",
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.line.x = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
plot.margin = margin(0,0,0,0))
graph1
graph2 <- ggplot(graphdata, aes(y = values, x=1))+
geom_jitter(aes(colour = cut(values, c(0,100,200,Inf))), alpha = 0.2, size = 0.5)+
scale_color_manual(values = c("#F0CF19","#F07C0B", "#D52828"))+
scale_y_continuous(breaks = c(500,1000), trans='log', limits = c(201, 1000), expand = c(0, 0))+
labs(y = "Longer title Values", x = NULL)+
scale_x_continuous(expand = c(0.01, 0))+
theme_classic()+
coord_cartesian(clip = "off")+
theme(legend.position = "none",
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.line.x = element_blank(),
axis.title.x = element_blank(),
plot.margin = margin(0,0,0,0))
graph2
graph3 <- ggplot(graphdata, aes(y = values, x=1))+
geom_jitter(aes(colour = cut(values, c(0,100,200,Inf))), alpha = 0.2, size = 0.5)+
scale_color_manual(values = c("#F0CF19","#F07C0B", "#D52828"))+
scale_y_continuous(breaks = c(10000,20000,40000), trans='log', limits = c(1001, 40001), expand = c(0, 0))+
labs(y = NULL,x = NULL)+
scale_x_continuous(expand = c(0.01, 0))+
theme_classic()+
coord_cartesian(clip = "off")+
theme(legend.position = "none",
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.line.x = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
plot.margin = margin(0,0,0,0))
graph3
#Using Cowplot, I stichted together three panels to make one graph that is close to what I want. But the problem lies with the white space between the panels. I want to get rid of it. Also, this method leads to some points being cut-off, leaving wierd half circles.
library(cowplot);library(grid)
graph4 <- cowplot::plot_grid(graph3,NULL, graph2, NULL,graph1, align = "v", ncol = 1, rel_heights = c(0.25,-0.01,0.25,-0.01,0.5)) #adjust spacing with the negative values here.
graph4 <- set_panel_size(graph4, width = unit(7, "cm"), height = unit(6, "cm"))
grid.newpage()
grid.draw(graph4)
I end up with this graph:
Overall I am happy that I can adjust the spacing now. However, this brings in another issue of axis title. It looks like the layering makes the last listed graph as the top most graph. The title from the middle graph is cutoff from the bottom graph. Here is what I mean (title is supposed to read "longer title Values"):
So that is the next hurdle, but may be another question that I have to ask in a separate post.
This question already has answers here:
Wrap long axis labels via labeller=label_wrap in ggplot2
(4 answers)
Closed 2 years ago.
I know hjust is used for the x title axis, but how would I go about centering and multilining the x axis labels? Here is my plotting function:
gg_fun<-function(){
ggplot(tab,
aes(x = Var1, y = Percent)) +
#theme_light() +
theme(panel.background = element_rect(fill = NA),
axis.title.y=element_text(angle=0, vjust=0.5, face="bold"),
axis.title.x=element_blank(),
axis.text.y = element_text(size = 10),
axis.text.x = element_text(size = 12),
axis.ticks.x = element_blank(),
axis.ticks.y = element_blank(),
#panel.grid.minor = element_line(colour = "dark gray"),
panel.grid.major.x = element_blank() ,
# explicitly set the horizontal lines (or they will disappear too)
panel.grid.major.y = element_line(size=.1, color="dark gray" ),
axis.line = element_line(size=.1, colour = "black"),
plot.background = element_rect(colour = "black",size = 1)) +
geom_bar(stat = "Identity", fill="#5596E6") + #"cornflower" blue
ggtitle(element_blank()) +
scale_y_continuous(expand = c(0, 0), breaks = round(seq(0, 1, by = .1), digits = 2),
labels = percent(round(seq(0, 1, by = .1), digits = 2), digits = 0),
limits = c(0,.6)) #+
#scale_x_discrete()
}
Here is an example graph it produces:
I am aware of n.dodge argument for scale_x_discrete(), but this is not what I am looking for. I also do not want to simply abbreviate using labels = abbreviate or specifying precisely as this is time consuming. I have also seen for example levels(birds$effect) <- gsub(" ", "\n", levels(birds$effect)), but this skips every line and makes some labels far too long. How would I go about centering the x label text as well as having it multiline to prevent overlap? Example of what I am going for:
You can use stringr::str_wrap as a labelling function in scale_x_discrete.
Let's take some sample data:
tab <- data.frame(Var1 = c("Video of presentation incl visuals",
"Video of presentation, written text and visuals",
"Written text, plus visuals",
"Other (please specify)"),
Percent = c(0.33, 0.34, 0.16, 0.17))
With your original function, this gives the following plot:
gg_fun()
But with the following modification:
gg_fun<-function(){
ggplot(tab,
aes(x = Var1, y = Percent)) +
#theme_light() +
theme(panel.background = element_rect(fill = NA),
axis.title.y=element_text(angle=0, vjust=0.5, face="bold"),
axis.title.x=element_blank(),
axis.text.y = element_text(size = 10),
axis.text.x = element_text(size = 12),
axis.ticks.x = element_blank(),
axis.ticks.y = element_blank(),
#panel.grid.minor = element_line(colour = "dark gray"),
panel.grid.major.x = element_blank() ,
# explicitly set the horizontal lines (or they will disappear too)
panel.grid.major.y = element_line(size=.1, color="dark gray" ),
axis.line = element_line(size=.1, colour = "black"),
plot.background = element_rect(colour = "black",size = 1)) +
geom_bar(stat = "Identity", fill="#5596E6") + #"cornflower" blue
ggtitle(element_blank()) +
scale_y_continuous(expand = c(0, 0),
breaks = round(seq(0, 1, by = .1), digits = 2),
labels = scales::percent(round(seq(0, 1, by = .1),
digits = 2), digits = 0),
limits = c(0,.6)) +
scale_x_discrete(labels = function(x) stringr::str_wrap(x, width = 16))
}
We get:
gg_fun()
Typically, you have to manually place the newline character '\n' within your labels. However, someone wrote a function to do this automatically, which is provided in this thread.
I was trying to make a chart as the below in ggplot. I wanted the y labels to show the entire set of values from 1 to 50 but I only wanted to generate horizontal gridlines every 10 numbers. I thought adding minor_breaks and then controlling the theme would work. However, setting the major grid lines to element_blankseems to be overriding the minor gridlines as well. I found some questions here where people have asked about adding more gridlines than labels, but I want the reverse.
How can I set the number of gridlines to be smaller than the number of breaks? Thanks!
Here is the code for the plot:
library(nsRFA)
library(ggplot2)
library(dplyr)
data(hydroSIMN)
annualflows %>% ggplot(aes(x = anno, y = cod)) +
geom_point(
shape = 45,
size = 5,
col = "blue"
) +
scale_y_reverse(
breaks = 1:50,
labels = 1:50,
minor_breaks = seq(10, 50, by = 10)
) +
scale_x_continuous(breaks = seq(1920, 1980, by = 10)) +
labs(
x = "Year",
y = "Code"
) +
theme(
panel.background = element_blank(),
panel.border = element_rect(fill = NA),
text = element_text(size = 10),
panel.grid.major.x = element_line(color = "grey80"),
panel.grid.major.y = element_blank(),
panel.grid.minor.y = element_line(color = "grey80") # This doesn't work
)
From reading this https://github.com/tidyverse/ggplot2/issues/403, it would appear that there are some issues surround minor_breaks. However, using geom_hline() should get you what you want.
library(nsRFA)
library(ggplot2)
library(dplyr)
data(hydroSIMN)
minors<-seq(10,50,by=10)
annualflows %>% ggplot(aes(x = anno, y = cod)) +
geom_point(
shape = 45,
size = 5,
col = "blue"
) +
scale_y_reverse(
breaks = 1:50,
labels = 1:50,
minor_breaks = seq(10, 50, by = 10)
) +
scale_x_continuous(breaks = seq(1920, 1980, by = 10)) +
labs(
x = "Year",
y = "Code"
) +
theme(
panel.background = element_blank(),
panel.border = element_rect(fill = NA),
text = element_text(size = 10),
panel.grid.major.x = element_line(color = "grey80"),
#panel.grid.major.y = element_blank(),
#panel.grid.minor.y = element_line(color = "grey80") # This doesn't work
)+
geom_hline(mapping=NULL, yintercept=minors,colour='grey80')
In ggplot I have a graph whose x-axis labels extend beyond the plot window in RStudio even if I try to export the picture and no matter how wide I make the picture. Below is my current solution using limits in scale_x_continuous. Is it possible to have the picture extend so that I can capture my last x-axis label (i.e., 25021643) but without having the line segment extend?
Code to reproduce above:
library(ggplot2)
p <-
ggplot(NULL) +
xlab("x-axis") +
theme_bw() +
scale_x_continuous(breaks = as.integer(seq(0,25021643,(25021643/4))), limits=c(0,26021643),labels = as.integer(seq(0,25021643,(25021643/4))), expand = c(0,0)) +
scale_y_continuous(limits = c(-1, (nrow(chr5)+1)), expand = c(0,0)) +
geom_hline(yintercept = -1) +
geom_segment(aes(x = 0, y = -1, xend = 0, yend = -0.9)) +
geom_segment(aes(x = 25021643, y = -1, xend = 25021643, yend = -0.9)) +
theme(panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
panel.border=element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.x = element_line(size=1),
axis.title.x = element_text(size=20),
axis.text.x = element_text(size=20))
p
Adding plot.margin=unit(c(0,20,0,0),"mm") seemed to do the job.
You may also use:
plot.margin = margin(r = 20, unit = "mm")
Just another way of doing the same thing, but avoiding writing the values for all sides of the plot: 't' is top, 'r' is right, 'l' is left, and 'b' is bottom. You can write all or any sides you wish separated by a comma:
plot.margin = margin(r = 20, l = 30, b = 15, t = 40, unit = "mm")
or, if you wish to use standard units ('pt'):
plot.margin = margin(r = 20)