Specifying the position of a label in geom_text - r

I created a barplot and later added geom_text. I would like to make labels start at the bottom of each bar, I tried to use position vjust and hjust, also specify y = 0, but they didn't work, because labels have different lengths. I would like to solve it by specyfing geom_text arguments if possible. That's part of how my plot looks:
I want to make every label start at the same height, or just at the bottom of each bar
Code similar to my original
xxx <- sample(letters,1000, replace = T)
xxx <- data.frame(x=xxx)
text <- c(rep(c("b","adsasdasasd"),13))
library(tidyverse)
xxx %>%
count(x) %>%
ggplot(aes(x,n))+
geom_bar(stat="identity")+
geom_text(aes(x, label = text),y=0, angle=90)

It should work using both y=0 to specify the position relative to the graph, and hjust to specify the position of the text relative to the y:
library(tidyverse)
xxx <- sample(letters,1000, replace = T)
xxx <- data.frame(x=xxx)
text <- c(rep(c("b","adsasdasasd"),13))
xxx %>%
count(x) %>%
ggplot(aes(x,n))+
geom_bar(stat="identity")+
geom_text(aes(x, label = text), y=0, hjust="bottom", angle=90)

Related

ggplot2: how to horizontal center legend at top of plot with long Y-axis labels?

I am attempting to plot some data with really long Y-axis labels. I want to position the legend at the top of the plot, and center it horizontally w.r.t. the entire plot width (as dictated by the width of the panel + the Y-axis labels). I can't seem to figure out how to do this.
Here is the toy data I have been working with:
library(magrittr)
library(dplyr)
library(ggplot2)
iris_new <- iris
iris_new %<>%
mutate(Sepal.Width = paste0(Sepal.Width,
paste0(sample(letters, size = 100, replace = TRUE),
collapse = "")))
plt0 <- ggplot(iris_new, aes(Sepal.Length, Sepal.Width, color = Species)) +
geom_point() + theme(legend.position = "top", legend.direction = "horizontal")
plt0
The basic plot:
legend.justification = "left" simulates what I want, but not perfectly since it is simply aligning the legend to the left margin of the panel, and it just so happens that this approximately coincides with the middle of the plot width.
plt1 <- plt0 + theme(legend.justification = "left")
plt1
But this solution isn't really satisfactory as I cannot guarantee that the Y-axis labels might not get longer (or shorter). Of course, I could use stringr::str_wrap() to limit the label width to say 40 characters, but I really want to know if there is a simple ggplot2 solution to the alignment issue. This would also not account for the fact that the plotted data might force the X-axis to vary between plots.
guides(fill = guide_legend(title.position = "left", label.position = "left")) and guides(fill = guide_legend(title.hjust = 0, label.hjust = 0)) didn't work either.
The expected output would be something like this (simulated using LibreOffice Impress):
I apologize if this is a trivial question. I did try and search for relevant posts on stackoverflow, but I was unable to find a solution.
This is close to what you require
p1 <-ggplot(iris_new, aes(Sepal.Length, Sepal.Width, color = Species)) +
geom_point()
p2 <- p1 + theme(legend.position = "top")
le1 <- cowplot::get_legend(p1)
le1
cowplot::plot_grid(p2, le1, nrow = 2, rel_heights = c(1, 0.2))
Although I do see another legend at the bottom not sure how to remove it but horizontal center its close

Tidy up ggplot with Jitter and fixing axis labels?

Hi guys, I have this very messy plot. How can I
rotate the x axis text so that you can actually read it
not include every y value in the y-axis (maybe have the y axis in intervals of 5)
add jitter so that the plot is easier is read
remove the NA values (I tried to, but I guess it did not work)
remove the legend (had to crop it for confidentiality)
here is my code:
data <- ndpdata[which(ndpdata$FC.Fill.Size==20),] #20 fill size
library(tidyr)
my_df_long <- gather(data, group, y, -FC.Batch.Nbr)
data = my_df_long[2075:2550,]
ggplot(data, aes(FC.Batch.Nbr, y, color=FC.Batch.Nbr), na.rm=TRUE) + geom_point()
To rotate the x axis add this to your ggplot:
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))
If you don't want to include every value on the y axis, you can set breaks:
scale_y_continuous(breaks = c(251,270,290,310,325))
To add jitter points try position = "jitter" inside geom_point():
geom_point(position = "jitter")
To remove NA's you can use it on your data:
data <- data[!is.na(data)]
To remove legend add this to your ggplot:
theme(legend.position = "none")

ggplot heatmap gridline formatting geom_tile and geom_rect

I have been working on creating a heatmap for a few days and I cannot get the final formating of gridlines to work. See the codes and attached plots below. What I am trying to do is to align the gridline along the tiles of the heatmap using geom_tile() so each tile fills the inside of the grid in a box way. I was able to align the gridlines using geom_raster() but the y-axis label ticks at either the top or the bottom of the tile but I need it to tick at the center (See red highlight), also I cannot get geom_raster to wrap a white line border around the tiles so the color blocks looks a bit disorganized in my original dataset. Would be grateful for any help with the formatting codes. Thanks very much!
#The data set in long format
y<- c("A","A","A","A","B","B","B","B","B","C","C","C","D","D","D")
x<- c("2020-03-01","2020-03-15","2020-03-18","2020-03-18","2020-03-01","2020-03-01","2020-03-01","2020-03-01","2020-03-05","2020-03-06","2020-03-05","2020-03-05","2020-03-20","2020-03-20","2020-03-21")
v<-data.frame(y,x)
#approach 1 using geom_tile but gridline does not align with borders of the tiles
v%>%
count(y,x,drop=FALSE)%>%
arrange(n)%>%
ggplot(aes(x=x,y=fct_reorder(y,n,sum)))+
geom_tile(aes(fill=n),color="white", size=0.25)
I have tried running similar codes from another post but I wasn't able to get it to run properly. I think because my x variable is a count variable of y variable so cannot be formatted into a factor variable to specify xmin and xmax in geom_rect()
#approach 2 using geom_raster but y-axis label can't tick at the center of tiles and there's no border around the tile to differentiate between tiles.
v%>%
count(y,x,drop=FALSE)%>%
arrange(n)%>%
ggplot()+
geom_raster(aes(x=x,y=fct_reorder(y,n,sum),fill=n),hjust=0,vjust=0)
I think it makes sense to keep the ticks and in turn the grid lines where they are. To still achieve what you're looking for, I would suggest you expand your data to include all possible combinations and simply set the na.value to a neutral fill color:
# all possible combinations
all <- v %>% expand(y, x)
# join with all, n will be NA for obs. in all that are not present in v
v = v %>% group_by_at(vars(y, x)) %>%
summarize(n = n()) %>% right_join(all)
ggplot(data = v,
aes(x=x, y=fct_reorder(y,n, function(x) sum(x, na.rm = T))))+ # note that you must account for the NA values now
geom_tile(aes(fill=n), color="white",
size=0.25) +
scale_fill_continuous(na.value = 'grey90') +
scale_x_discrete(expand = c(0,0)) +
scale_y_discrete(expand = c(0,0))
This is a bit of a hack. My approach converts the categorical variables to numerics which adds minor grid lines to the plot which align with the tiles. To get rid of the major grid lines I simply use theme(). Drawback: Breaks and labels have to be set manually.
library(ggplot2)
library(dplyr)
library(forcats)
v1 <- v %>%
count(y,x,drop=FALSE)%>%
arrange(n) %>%
mutate(y = fct_reorder(y, n, sum),
y1 = as.integer(y),
x = factor(x),
x1 = as.integer(x))
labels_y <- levels(v1$y)
breaks_y <- seq_along(labels_y)
labels_x <- levels(v1$x)
breaks_x <- seq_along(labels_x)
ggplot(v1, aes(x=x1, y=y1))+
geom_tile(aes(fill=n), color="white", size=0.25) +
scale_y_continuous(breaks = breaks_y, labels = labels_y) +
scale_x_continuous(breaks = breaks_x, labels = labels_x) +
theme(panel.grid.major = element_blank())
Created on 2020-05-23 by the reprex package (v0.3.0)
Edit: Checked for long var names
y<- c("John Doe","John Doe","John Doe","John Doe","Mary Jane","Mary Jane","Mary Jane","Mary Jane","Mary Jane","C","C","C","D","D","D")
x<- c("2020-03-01","2020-03-15","2020-03-18","2020-03-18","2020-03-01","2020-03-01","2020-03-01","2020-03-01","2020-03-05","2020-03-06","2020-03-05","2020-03-05","2020-03-20","2020-03-20","2020-03-21")
v<-data.frame(y,x)
Created on 2020-05-23 by the reprex package (v0.3.0)

How to make ggplot legend add objects horizontally (vs vertically)

The legend in ggplot can be moved to the bottom of the graphic as a horizontal legend by adding the following arguments to the theme function:
legend.position="bottom" moves the legend below the graph
legend.direction="horizontal" orients the legend to be horizontal.
However, not really...
The legend.direction="horizontal" simply seems to decrease the number of rows in the legend and the number of legend objects in each row.
This can be done manually using guides(color=guide_legend(nrow=x)
dat <- data.frame(plot = rep(letters,2), val = rep(1:length(letters),2))
library(ggplot2)
ggplot(dat, aes(x = val, y = val, color = plot)) +
geom_point() +
theme(legend.position="bottom") +
guides(color=guide_legend(nrow=2))
Regardless....
If you notice in the graphic output of the above code, even though I can control the "dimensions" of my legend (i.e., the number of rows), I can't figure out how to change the ordering of the legend from vertical to horizontal.
So instead of a being above b etc. ("vertically" sorted) as above, I want b to be added next to a ("horizontally" sorted).
How do I make my legend add objects horizontally vs vertically?
Like so:
Try adding byrow = TRUE to guide_legend:
ggplot(dat, aes(x = val, y = val, color = plot)) +
geom_point() +
theme(legend.position="bottom") +
guides(color=guide_legend(nrow=2, byrow = TRUE))

How to plot a line with color vector in R Plotly

Say I have the following data frame:
ret <- rnorm(100, 0, 5)
df <- data.frame(
x = seq(1, 100, 1),
ret = ret,
y = 100 + cumsum(ret),
col = c(ifelse(ret > 0, "red", "forestgreen"), NA)[-1]
)
Here I'm simulating the returns of some fictional financial asset using rnorm named 'ret', and am defining a color vector named 'col' where upticks are green and downticks are red.
What I want to produce is something like the following:
library(ggplot2)
ggplot(df, aes(x=x, y=y)) + geom_line(aes(colour=col, group=1))
But I want to make a similar image using plotly so that I can zoom in on sections of the plot. My first thought was to try simply using the ggplotly() function around the code that produced the desired image:
library(plotly)
ggplotly(ggplot(df, aes(x=x, y=y)) + geom_line(aes(colour=col, group=1)))
But the plot is no longer grouped. Additionally, I tried using plot_ly() but can't seem to make the line segments get their color according to the 'col' attribute that I'm specifying:
plot_ly(data=df, x = ~x) %>% add_lines(y = ~y, line = list(color=~col))
But my color argument doesn't affect the color of the line. I've tried various other things but keep ending up with one of the two undesired plots. Any help would be much appreciated!
Note: I've already made candlestick and OHLC charts with plot_ly(), but I can't work with them because the y axis doesn't scale when you zoom in to a subsection of the plot.
I was able to get the desired behaviour from ggplotly by using geom_segment and making each segment link up to the next (x, y) value, regardless of colour:
library(dplyr)
df = df %>%
arrange(x) %>%
mutate(x_next = lead(x), y_next = lead(y))
p = ggplot(df, aes(x=x, y=y)) +
geom_segment(aes(xend = x_next, yend = y_next, colour=col))
ggplotly(p)
That said, I don't have a good answer for why ggplotly doesn't produce the desired output in the first place.

Resources