Bounding position for geom_text() - r

I am making several instances of a tilted bar chart. As the sizes of count and the differences in percent vary, part of one of the labels (count) is pushed outside the bar in some instances. I need the labels to be entirely inside the bar in all instances. If not repositioned to fit inside the bar, I need the labels to be centered as is.
The code is:
library(tidyverse)
library(ggplot2)
data <- tibble(type = c('Cat', 'Dog'),
group = c('Pets', 'Pets'),
count = c(10000, 990000),
percent = c(1, 99))
ggplot(data, aes(x = group, y = percent, fill = type)) +
geom_bar(stat = 'identity',
position = position_stack(reverse = TRUE)) +
coord_flip() +
geom_text(aes(label = count),
position = position_stack(vjust = 0.5,
reverse = TRUE))

Use hjust="inward":
ggplot(data, aes(x = group, y = percent, fill = type)) +
geom_bar(stat = 'identity', position = position_stack(reverse = TRUE)) +
coord_flip() +
geom_text(aes(label = count), hjust = "inward", position = position_stack(vjust = 0.5, reverse = TRUE))

One thing key to note here is that plots in ggplot are drawn differently depending on the graphics device resolution, width, and height settings. This is why plots look a bit different depending on the computer you use to plot them. If I take your default graph and save different aspect ratios, this becomes evident:
width=3, height=5
width=7, height=5
The aspect ratio and resolution change the plot. You can also see this for yourself within R studio by just resizing the plot viewer window.
With that being said, there are some options to adjust your plot to be less likely to clip text out of bounds:
Rotate your text or rotate your plot back to horizontal bars. For long text labels, they are going to work out better with horizontal bars anyway.
geom_text_repel from the ggrepel package. Direct replacement of geom_text puts your labels in the plot area, and you can use min.segment.length= to specify the minimum line length as well as force= and direction= to play with positioning. Again, works better if you flip back your chart.
Use the expand= argument applied to scale_y_continuous. Try adding scale_y_continuous(expand=c(0.25,0.25)) to your plot, for example. Note that since your coordinate system is flipped, you have to specify "y" to expand "x". This expands the plot area around the geoms.
Change the output width= and height= and resolution when exporting your plots. As indicated above, this is the simple solution.
There are probably other suggestions, but that's mine.

Related

Stacking overlapping tiles using geom_tile()

I'm trying to figure out how to place tiles that represent points using geom_tile(), and my issue is that overlapping tiles only appear as one tile. I'm trying to get tiles with the same y-values to be adjacent to each other, even though they have the same value. My initial thought was to use position = "dodge", however that spread out the tiles all over my bar graph.
My current code is
ggplot(dataset, aes(x = Country, y = `Health Sciences`)) +
geom_bar(stat = "identity", width = 0.25) +
geom_tile(dataset_long, mapping = aes(x = Country, y = Percent, fill = Subject),
position = position_dodge(width=0, preserve = "total")) +
coord_flip()
but it doesn't produce the intended effect. The graph below shows some tiles that are "stacked" atop one another if they have overlapping values, however, I'm trying to get them to be directly adjacent to each other instead. Any help would be appreciated, thanks!
Graph with stacked tiles

Small ggplot2 plots placed on coordinates on a ggmap

I would like to first use ggmap to plot a specific area with longitude and latitude as axes.
Then I would like to put small ggplot2 plots on the specific locations, given their longitude and latitude. These can be barplots with minimal theme.
My database may have the columns:
1. town
2. longitude
3. latitude
4. through 6. value A, B, C
I generate a plot (pseudocode)
p <- ggmap(coordinates)
and I have my minimal ggplot2 design
q<-ggplot2()+geom_bar(....)+ ... x-axis null y axis null minimal template
How to combine the two designs to have a ggmap with small minimal ggplot plots imposed on specific coordinates of the map?
Here's one I did using pie charts as points on a scatterplot. You can use the same concept to put barcharts on a map at specific lat/long coordinates.
R::ggplot2::geom_points: how to swap points with pie charts?
Needs further update. Some of the code used was abbreviated from another answer, which has since been deleted. If you find this answer via a search engine, drop a comment and I'll get around to fleshing it back out.
Updated:
Using mostly your adapted code from your answer, but I had to update a few lines.
p <- ggmap(Poland) + coord_quickmap(xlim = c(13, 25), ylim = c(48.8, 55.5), expand = F)
This change makes a better projection and eliminates the warnings about duplicated scales.
df.grobs <- df %>%
do(subplots = ggplot(., aes(1, value, fill = component)) +
geom_col(position = position_dodge(width = 1),
alpha = 0.75, colour = "white") +
geom_text(aes(label = round(value, 1), group = component),
position = position_dodge(width = 1),
size = 3) +
theme_void()+ guides(fill = F)) %>%
mutate(subgrobs = list(annotation_custom(ggplotGrob(subplots),
x = lon-0.5, y = lat-0.5,
xmax = lon+0.5, ymax = lat+0.5)))
Here I explicitly specified the dodge width for your geom_col so I could match it with geom_text. I used round(value, 1) for the label aesthetic, and it automatically inherits the x and y aesthetics from the subplots = ggplot(...) call. I also manually set the size to be quite small, so the labels would fit, but then I increased the overall bounding box for each subgrob, from 0.35 to 0.5 in each direction.
df.grobs %>%
{p +
.$subgrobs +
geom_text(data=df, aes(label = name), vjust = 3.5, nudge_x = 0.065, size=2) +
geom_col(data = df,
aes(Inf, Inf, fill = component),
colour = "white")}
The only change I made here was for the aesthetics of the "ghost" geom_col. When they were set to 0,0 they weren't plotted at all since that wasn't within the x and y limits. By using Inf,Inf they're plotted at the far upper right corner, which is enough to make them invisible, but still plotted for the legend.

how to make each bar stand out (with border) in grouped barplot using ggplot2? [duplicate]

I am currently using ggplot2 to plot a barchart with too many levels in fill. As a result, I am unable tell when a bar ends and the other begin.
Here's my sample data code of what I am doing right now.
variable<-c("X1","X1","X1","X1","X1","X1","X1","X1","X1","X2","X2","X2","X2","X2","X2","X2","X2","X2","X3","X3","X3","X3","X3","X3","X3","X3","X3")
Length.1<-c(4.24,0.81,0.81,NA,NA,NA,NA,NA,NA,4.24,0.81,0.81,NA,NA,NA,NA,NA,NA,4.24,0.72,0.72,0.16,NA,NA,NA,NA,NA)
data<-data.frame(variable=as.factor(variable),value=as.factor(1:length(variable)),Length.1=Length.1)
## Plots a stacked bar chat in ggplot2 with text labels. Credit to MYaseen208
library(ggplot2)
p <- qplot(variable, Length.1, data = data, geom = "bar", fill = value, theme_set(theme_bw()))
p + geom_text(aes(label = Length.1), size = 3, hjust = 0.5, vjust = 3, position = "stack")
Currently, the plot looks fine. However in my actual data set, length(data$value) is much higher and I can't see the differences between different bars as clearly. So, I wish to change the colours of the bars to white and draw a black border around each one. Does anyone know how I can do that?
I would use the ggplot function instead of qplot. Then you can set the color and fill manually:
ggplot(data,aes(x=variable, y=Length.1,group=value))+
geom_bar(fill="white",color="black")+
geom_text(aes(label = Length.1), size = 3, hjust = 0.5, vjust = 3, position ="stack") +
theme_bw()
p <- ggplot(aes(variable, Length.1), data = data)+ geom_bar(stat="identity",colour="black", fill="white")+geom_text(...)

Colour just the top border of geom_bar

A chart with a lot of bars looks very squished, for instance -
ggplot(data.frame(x = 1:1000, y = (rnorm(1000)), fill = sample(c('a','b','c'), 1000, replace = T)), aes(x, y, fill = fill)) + geom_bar(stat = 'identity')
I have a chart for a similar dataset which I feel I will be able to make more sense out of by just colouring the top border of the bar. I'm unable to achieve this. The closest I can do is incorporate a geom_step but this also adds vertical lines where the y value changes and this crowds the chart even more. geom_point sizes aren't necessarily synced with the separation on the x axis so they spill over to the side for small x values. The only sure shot solution I'm able to think of is to actually manipulate the data such that I'm able to draw geom_segments to do my work for me. Is there any other way
PS: I need to stick to this format for reasons.
You could use geom_errorbar() and set ymin= and ymax= to your y values. Then you can play with width= and size= to get the look you need.
ggplot(data.frame(x = 1:1000, y = (rnorm(1000)), fill = sample(c('a','b','c'), 1000, replace = T))) +
geom_errorbar(aes(x=x,ymin=y,ymax=y,color=fill),size=0.5,width=3)

In ggplot2, can borders of bars be changed on only one side? (color, thickness)

I know, 3D Barcharts are a sin. But i´m asked to do them and as a trade-off i suggested to only make a border with a slightly darker color than the bar´s on the top and the right side of the bar. Like that, the bars would have some kind of "shadow" (urgh) but at least you still would be able to compare them.
Is there any way to do this?
ggplot(diamonds, aes(clarity)) + geom_bar()
Another possibility, using two sets of geom_bar. The first set, the green ones, are made slightly higher and offset to the right. I borrow the data from #Didzis Elferts.
ggplot(data = df2) +
geom_bar(aes(x = as.numeric(clarity) + 0.1, y = V1 + 100),
width = 0.8, fill = "green", stat = "identity") +
geom_bar(aes(x = as.numeric(clarity), y = V1),
width = 0.8, stat = "identity") +
scale_x_continuous(name = "clarity",
breaks = as.numeric(df2$clarity),
labels = levels(df2$clarity))+
ylab("count")
As you already said - 3D barcharts are "bad". You can't do it directly in ggplot2 but here is a possible workaround for this.
First, make new data frame that contains levels of clarity and corresponding count for each level.
library(plyr)
df2<-ddply(diamonds,.(clarity),nrow)
Then in ggplot() call use new data frame and clarity as x values and V1 (counts) as y values and add geom_blank() - this will make x axis with levels we need. Then add geom_rect() to produce shading for bars - here xmin and xmax values are made as.numeric() from clarity and constant is added - for xmin constant should be less than half of bars width and xmax constant larger than half of bars width. ymin is 0 and ymax is V1 (counts) plus some constant. Finally add geom_bar(stat="identity") above this shadow to plot actually barplot.
ggplot(df2,aes(clarity,V1)) + geom_blank()+
geom_rect(aes(xmin=as.numeric(clarity)-0.38,
xmax=as.numeric(clarity)+.5,
ymin=0,
ymax=V1+250),fill="green")+
geom_bar(width=0.8,stat="identity")

Resources