Change axis breaks/limits of ggplot with geom_col - r

I am having problems with changing the axis ticks in a barplot. I am fairly new in using ggplot so the answer might be very obvious.
Here is some data (yes it is strange, but designed to mimic the original dataset I have, which I am not allowed to share):
lab='this is just a very long example text and it will be longer and longer and longer and longer and longer and longer and longer and longer and longer and end'
number=1:20
n=unlist(lapply(number,paste,value=lab))
a=round(runif(n=20,min=-48000,max=-40000))
b=round(runif(n=20,min=-48000,max=-40000))
c=round(runif(n=20,min=-48000,max=-40000))
d=data.frame(cbind(n,a,b,c))
df=pivot_longer(d,cols=c('a','b','c'))
l1=round(as.numeric(min(df$value))/1000 )*1000+1000
l2=round(as.numeric(max(df$value))/1000 )*1000-1000
lim=seq(from=l1,to=l2,by=-1000)
colScale <- scale_fill_manual(name = "n",values = c(rainbow(nrow(df)/3)))
from which I create a barplot
p1=ggplot(df, aes(name, value, fill = as.factor(n))) +
geom_col(position = "dodge",colour='black') +
#scale_y_continuous(breaks = lim , labels = as.character(lim)) +
coord_flip() +
theme_bw() +
theme(axis.text.x=element_text(angle=90),axis.title.x=element_text(face='bold')) +
theme(axis.text.y=element_text(angle=90,size=15)) +
theme(legend.title=element_blank()) +
labs(x = "",y="test") +
colScale +
guides(fill=guide_legend(ncol=1)) +
ggtitle('something') +
theme(plot.title = element_text(hjust = 0.5,size=20))
which is this
that is basically working as I wanted, but the scaling of the x-axis is very unpleasant. What I want instead is an axis, where the breaks and labels are equal to the vector 'lim'. What I understood was that it should be possible to do this by scaling the respective axis as in the commented line. But when I'm trying this I get the error 'Discrete value supplied to continuous scale'. I tried to change the scale to 'scale_y_discrete' but then the ticks disappear completely. I tried everything I could find but nothing worked, so what is wrong?
Based on the answers I changed the plot definition to:
p1=ggplot(df, aes(name, as.numeric(value), fill = as.factor(n))) +
geom_col(position = "dodge",colour='black') +
scale_y_continuous(breaks = lim , labels = as.character(lim)) +
coord_flip() +
theme_bw() +
theme(axis.text.x=element_text(angle=90),axis.title.x=element_text(face='bold')) +
theme(axis.text.y=element_text(angle=90,size=15)) +
theme(legend.title=element_blank()) +
labs(x = "",y="test") +
colScale +
guides(fill=guide_legend(ncol=1)) +
ggtitle('something') +
theme(plot.title = element_text(hjust = 0.5,size=20))
which produced this plot
now I am able to change the axis ticks, but the plot looks nothing like the first one. My goal is to keep the look, meaning showing only the top part of the bars.

I'd suggest converting value to as.numeric (preferably before ggplot, but you can do it within, like below) and using coord_cartesian to specify the "view window". You also might find it simpler to specify your axes in the order you want them, rather than using coord_flip, which is mostly unnecessary since ggplot 3.3.0.
ggplot(df, aes(as.numeric(value), name, fill = as.factor(n))) +
geom_col(position = "dodge",colour='black') +
scale_x_continuous(breaks = lim , labels = as.character(lim)) +
coord_cartesian(xlim = c(min(as.numeric(df$value)), max(as.numeric(df$value))))
# Theming after this up to you

Related

ggplot2 data labels outside margins

I'm making many figures in ggplot2 using a for loop, but my data labels are extending beyond the plot margin. I've tried using expand, but it only works for some figures. When I try to use par(mar) I get this error message:
Error: Don't know how to add o to a plot.
I also tried just using ggsave to save as a really wide file, but 1) that looks odd and 2) that won't work for making so many different figures.
Does anyone know of any other workarounds? Ideally a way to have the inner plot margins automatically set per figure based on the length of the bars + data labels. Below is the code I'm using and an example figure (you can see the bar for 'x' is outside the margin). Thank you in advance!
for (i in each) {
temp_plot = ggplot(data= subset(Data, Each == i)) +
geom_bar(stat = "identity",
aes(x = reorder(Letter, +Number), y = Number, fill = factor(Category))) +
xlab("Letters") +
ggtitle(paste0("Title"), subtitle = "Subtitle") +
coord_flip() +
theme_classic() +
theme(plot.title = element_text(hjust = 0.5, size=16),
plot.subtitle = element_text(hjust = 0.5)) +
scale_fill_manual(values = c("#00358E", "#00AFD7"),
name= "Category",
labels=c("This","That")) +
geom_text(family="Verdana", size=3,
aes(label=Number2, x=reorder(Letter, +Number), y=Number),
position=position_dodge(width=0.8), hjust=-0.001) +
scale_y_continuous(labels = comma, expand = c(0.01,0)) +
scale_x_discrete(labels = letters)
ggsave(temp_plot, file=paste0("Example", i,".jpeg"))
}
I figured out a simple solution: + ylim(0, 130000)
scale_y_continuous(expand = expansion(mult = c(0, .1)) )

How to set automatic label position based on box height

In a previous question, I asked about moving the label position of a barplot outside of the bar if the bar was too small. I was provided this following example:
library(ggplot2)
options(scipen=2)
dataset <- data.frame(Riserva_Riv_Fine_Periodo = 1:10 * 10^6 + 1,
Anno = 1:10)
ggplot(data = dataset,
aes(x = Anno,
y = Riserva_Riv_Fine_Periodo)) +
geom_bar(stat = "identity",
width=0.8,
position="dodge") +
geom_text(aes( y = Riserva_Riv_Fine_Periodo,
label = round(Riserva_Riv_Fine_Periodo, 0),
angle=90,
hjust= ifelse(Riserva_Riv_Fine_Periodo < 3000000, -0.1, 1.2)),
col="red",
size=4,
position = position_dodge(0.9))
And I obtain this graph:
The problem with the example is that the value at which the label is moved must be hard-coded into the plot, and an ifelse statement is used to reposition the label. Is there a way to automatically extract the value to cut?
A slightly better option might be to base the test and the positioning of the labels on the height of the bar relative to the height of the highest bar. That way, the cutoff value and label-shift are scaled to the actual vertical range of the plot. For example:
ydiff = max(dataset$Riserva_Riv_Fine_Periodo)
ggplot(dataset, aes(x = Anno, y = Riserva_Riv_Fine_Periodo)) +
geom_bar(stat = "identity", width=0.8) +
geom_text(aes(label = round(Riserva_Riv_Fine_Periodo, 0), angle=90,
y = ifelse(Riserva_Riv_Fine_Periodo < 0.3*ydiff,
Riserva_Riv_Fine_Periodo + 0.1*ydiff,
Riserva_Riv_Fine_Periodo - 0.1*ydiff)),
col="red", size=4)
You would still need to tweak the fractional cutoff in the test condition (I've used 0.3 in this case), depending on the physical size at which you render the plot. But you could package the code into a function to make the any manual adjustments a bit easier.
It's probably possible to automate this by determining the actual sizes of the various grobs that make up the plot and setting the condition and the positioning based on those sizes, but I'm not sure how to do that.
Just as an editorial comment, a plot with labels inside some bars and above others risks confusing the visual mapping of magnitudes to bar heights. I think it would be better to find a way to shrink, abbreviate, recode, or otherwise tweak the labels so that they contain the information you want to convey while being able to have all the labels inside the bars. Maybe something like this:
library(scales)
ggplot(dataset, aes(x = Anno, y = Riserva_Riv_Fine_Periodo/1000)) +
geom_col(width=0.8, fill="grey30") +
geom_text(aes(label = format(Riserva_Riv_Fine_Periodo/1000, big.mark=",", digits=0),
y = 0.5*Riserva_Riv_Fine_Periodo/1000),
col="white", size=3) +
scale_y_continuous(label=dollar, expand=c(0,1e2)) +
theme_classic() +
labs(y="Riserva (thousands)")
Or maybe go with a line plot instead of bars:
ggplot(dataset, aes(Anno, Riserva_Riv_Fine_Periodo/1e3)) +
geom_line(linetype="11", size=0.3, colour="grey50") +
geom_text(aes(label=format(Riserva_Riv_Fine_Periodo/1e3, big.mark=",", digits=0)),
size=3) +
theme_classic() +
scale_y_continuous(label=dollar, expand=c(0,1e2)) +
expand_limits(y=0) +
labs(y="Riserva (thousands)")

Unexpected behaviour: italic() causing cut-off of two-line axis label in ggplot2

Use of italics (italic()) in a y-axis label that goes over two lines in ggplot is causing the first line to be partly cut off.
E.g.
ggplot() +
geom_hline(aes(yintercept = 1)) +
labs(y = expression(paste("Something\nsomething", italic(x'))))
There's no reason apparent this should be happening — the same thing doesn't happen with very similar code not using italic(), e.g. using hat() instead:
ggplot() +
geom_hline(aes(yintercept = 1)) +
labs(y = expression(paste("Something\nsomething", hat(x))))
Anyone know why this would occur or what to do about it, other than tedious manual altering plot and margin sizes or such?
Not sure why this happens but you can increase the plot margins within ggplot2...
ggplot() +
geom_hline(aes(yintercept = 1)) +
labs(y = expression(paste("Something\nsomething", hat(x)))) +
theme(plot.margin=unit(c(1,1,1,1), "cm"))

Add axis ticks to ggplot2

This is my code :
ggplot(dat,aes(x=x,y=y))
geom_point(size=5)
stat_smooth(method='glm', se = FALSE)
scale_y_log10()+ xlab("time")
ylab(expression(log(z^2)))
scale_y_continuous(breaks = round(seq(min(dat$y), max(dat$y), by = 10),1))
In the last line I wand to add ticks on y axis, but I have an error
Scale for 'y' is already present. Adding another scale for 'y', which will replace the existing scale.
What's wrong?
You are already doing scale_y_log10(), so adding scale_y_continuous() doesn't make sense. Instead make the breaks inside scale_y_log10():
ggplot(dat,aes(x=x,y=y)) +
geom_point(size=5) +
stat_smooth(method='glm', se = FALSE) +
scale_y_log10(breaks = round(seq(min(dat$y), max(dat$y), by = 10),1))+ xlab("time") +
ylab(expression(log(z^2)))
should work, although when you don't post a minimal example, it's hard to be sure.

Smallest size of GGplot2 geom_text()

I have a plot made with GGplot2. Now when i want to change the size of my text points within the plot, the size of the text does not change. I use the following line of code:
ggplot(data = out, aes(x = V2, y = V1)) +
****geom_text(data = out[!is.na(out$V1),], aes(label = labels, alpha=0.3, size=0.1))**** +
facet_grid(id1 ~ id2,scales="fixed")+
geom_text(data=df.text,aes(pos,pos,label=id1)) + geom_abline( slope=1 ) +
ggtitle("Corralation between measured & calculated affinities") +
ylab("") + xlab("") + theme(panel.grid.minor.x=element_blank(), panel.grid.major.x=element_blank())
}
I put ** between start and end of the line of interest fat. I know that size is the right parameter to change, but why isn't my text changing when for instance making size=0.01.
Thanks to Adam Kimberley, the size parameter should be moved outside of the 2nd brackets like this geom_text(data = out[!is.na(out$V1),], aes(label = labels), size=0.1, alpha=0.3)
Than size of the text alters.

Resources