Conditionally assign geom_text placement for bar charts with ggplot2 - r

I am having an issue when making bar charts with mixed sign values in ggplot2. Take the following example:
df <- data.frame(year = letters[1:2],
value = c(1, -1))
ggplot(df, aes(year, value)) +
geom_col() +
geom_text(aes(label = value), vjust = 0.0, size = 5)
Which yields:
I would like to be consistent with the placement of the text - either below or on top of the bars. This is tricky because in both cases in the graph above, the text is directly above the value. However, because the first value is positive and the second value is negative the text appears in a different location relative to the bar. What I would like to see is (adjustments in red):
My question is: Is it possible to conditionally format label placement based on the sign of the value?

df <- data.frame(year = letters[1:3],
value = c(1, -1,-5)) %>%
mutate(text_location = ifelse(value < 0,0,value))
ggplot(df, aes(year, value)) +
geom_col() +
geom_text(aes(y = text_location,label = value), vjust = 0.0, size = 5)

Related

ggplot: position dodge based on category

I'd like to use position dodge to offset one variable in my ggplot chart (in this case banana) and leave the other two variables (red_apple and green_apple) without an offset. Using position_dodge applies the offset to each variable, but I'd like to choose which variables are offset specifically.
library(ggplot2)
data <- data.frame(Place = c(rep('Place_A',30),rep('Place_B',30)),
variable = c(rep(c(rep('red_Apple',10),rep('green_Apple',10),rep('bananna',10)),2)),
value = rep(c(1:10,1:10-.05,1:10+.2),2))
dodge = position_dodge(.5)
ggplot(data, aes(Place, value)) +
geom_point(aes(color=variable),position=dodge)
Is there for example a way to scale position manually, like how you can do for other aesthetics?
This obviously throws an error, but is what I was hoping for...
ggplot(data, aes(Place, value)) +
geom_point(aes(color=variable, position = variable)) +
scale_position_manual(breaks = c('green_Apple','red_Apple','bananna'),
values = c(position_dodge(0),position_dodge(0),position_dodge(.5)))
Does this look like what you want?
data$grp = ifelse(data$variable == "bananna", 2, 1)
ggplot(data, aes(Place, value, group = grp)) +
geom_point(aes(color=variable), position = position_dodge(0.5))

Show only data labels for every N day and highlight a line for a specific variable in R ggplot

I'm trying to figure out two problems in R ggplot:
Show only data labels for every N day/data point
Highlight (make the line bigger and/or dotted) for a specific variable
My code is below:
gplot(data = sales,
aes(x = dates, y = volume, colour = Country, size = ifelse(Country=="US", 1, 0.5) group = Country)) +
geom_line() +
geom_point() +
geom_text(data = sales, aes(label=volume), size=3, vjust = -0.5)
I can't find out a way how to space the data labels as currently they are being shown for each data point per every day and it's very hard to read the plot.
As for #2, unfortunately, the size with ifelse doesn't work as 'US' line is becoming super huge and I can't change that size not matter what I specify in the first parameter of ifelse.
Would appreciate any help!
As no data was provided the solution is probably not perfect, but nonetheless shows you the general approach. Try this:
sales_plot <- sales %>%
# Create label
# e.g. assuming dates are in Date-Format labels are "only" created for even days
mutate(label = ifelse(lubridate::day(dates) %% 2 == 0, volume, ""))
ggplot(data = sales_plot,
# To adjust the size: Simply set labels. The actual size is set in scale_size_manual
aes(x = dates, y = volume, colour = Country, size = ifelse(Country == "US", "US", "other"), group = Country)) +
geom_line() +
geom_point() +
geom_text(aes(label = label), size = 3, vjust = -0.5) +
# Set the size according the labels
scale_size_manual(values = c(US = 2, other = .9))

plotting stacked points using ggplot

I have a data frame and I would like to stack the points that have overlaps exactly on top of each other.
here is my example data:
value <- c(1.080251e-04, 1.708859e-01, 1.232473e-05, 4.519876e-03,2.914256e-01, 5.869711e-03, 2.196347e-01,4.124873e-01, 5.914052e-03, 2.305623e-03, 1.439013e-01, 5.407597e-03, 7.530298e-02, 7.746897e-03)
names = letters[1:7]
data <- data.frame(names = rep(names,), group = group, value = value, stringsAsFactors = T)
group <- c(rep("AA", 7) , rep("BB", 7))
I am using the following command:
p <- ggplot(data, aes(x = names, y = "", color = group)) +
geom_point(aes(size = -log(value)), position = "stack")
plot(p)
But the stacked circle outlines out of the grid. I want it close or exactly next to the bottom circle. do you have any idea how I can fix the issue?
Thanks,
The y-axis has no numeric value, so use the group instead. And we don't need the color legend now since the group labels are shown on the y-axis.
ggplot(data, aes(x = names, y = group, color = group)) +
geom_point(aes(size = -log(value))) +
guides(color=FALSE)

Readjusting the horizontal axis in ggplot

I have a simple dataset, containing values from 0 to 1. When I plot it, naturally, the horizontal axis is zero. I would like this reference to be 0.5 and the bars falling below 0.5 to be reversed and colored differently than those falling above this threshold.
my.df <- data.frame(group=state.name[1:20],col1 = runif(20))
p <- ggplot(my.df, aes(x=group,y=col1)) +
geom_bar(stat="identity")+ylim(0,0.5)
I am thinking of dissecting the data into two, one subset being greater than 0.5 and the other being larger than 0.5, then somewhat combining these two subsets in the same ggplot. Is there any other clearer way to do that? Thanks!
To build on #jas_hughes's answer, you can subtract 0.5 from your col1 variable, then rename the labels on the y-axis.
df <- data.frame(group=state.name[1:20],value=runif(20))
df %>% ggplot(aes(reorder(group,value),value-0.5)) + geom_bar(stat='identity') +
scale_y_discrete(name='Value',
labels=c('0','0.5','1'),
limits=c(-0.5,0,0.5),
expand = c(-0.55, 0.55)) +
xlab('State') +
theme(axis.text.x = element_text(angle=45,hjust=1))
The y-variable you are trying to communicate is distance from 0.5, so you need to change the values in col1 to reflect this.
library(dplyr)
library(ggplot)
my.df %>%
mutate(col2 = col1-0.5) %>%
ggplot() +
aes(x = group, y = col2, fill = col2 >=0) +
geom_bar(stat = 'identity') +
theme(legend.position = 'none',
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
ylab('Col1 above 0.5 (AU)')
Note, you can also use the aes(fill = col1 >= 0.5) option to color code the bars without shifting the axis (which is what I would recommend if col1 contains percentages).

Facet wrap radar plot with three apexes in R

I have created the following plot which gives the shape of the plot I desire. But when I facet wrap it, the shapes no longer remain triangular and become almost cellular. How can I keep the triangular shape after faceting?
Sample data:
lvls <- c("a","b","c","d","e","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15")
df <- data.frame(Product = factor(rep(lvls, 3)),
variable = c(rep("Ingredients", 20),
rep("Defence", 20),
rep("Benefit", 20)),
value = rnorm(60, mean = 5))
Now when I use this code, I get the shapes I desire.
ggplot(df,
aes(x = variable,
y = value,
color = Product,
group = Product)) +
geom_polygon(fill = NA) +
coord_polar()
However, the products are all on top of one another so ideally I would like to facet wrap.
ggplot(df,
aes(x = variable,
y = value,
color = Product,
group = Product)) +
geom_polygon(fill = NA) +
coord_polar() +
facet_wrap(~Product)
But when I facet wrap, the shapes become oddly cellular and not triangular (straight lines from point to point). Any ideas on how to alter this output?
Thanks.

Resources