Alignment of Numbers on the Individual Bars

Alignment of numbers on the individual bars

The error is from the scale_y_continuous call. Formatting of labels is now handled by the labels argument. See the ggplot2 0.9.0 transition guide for more details.

There was another problem with the labels not lining up correctly; I fixed that by adding a group=B to the aesthetics for the geom_text; I'm not quite sure why this is necessary, though. I also took out x=A from the geom_text aesthetics because it was not needed (it would be inherited from the ggplot call.

library("ggplot2")
library("scales")

ggplot(data=df, aes(x=A, y=Freq))+
geom_bar(aes(fill=B), position = position_dodge()) +
geom_text(aes(label = paste(sprintf("%.1f", Freq*100), "%", sep=""),
y = Freq+0.015, group=B),
size = 3, position = position_dodge(width=0.9)) +
scale_y_continuous(labels = percent) +
theme_bw()

Sample Image

Alignment of numbers on the individual bars with ggplot2

You need to add position=position_dodge(width=0.9) to the geom_text call.

Cleaning up your code a little gives:

p <- ggplot(data=df, aes(x=A, y=Freq))+
geom_bar(aes(fill=B), position = position_dodge()) +
geom_text(aes(label = paste(sprintf("%.1f", Freq*100), "%", sep=""),
y = Freq+0.015, x=A),
size = 3, position = position_dodge(width=0.9)) +
scale_y_continuous(formatter = "percent") +
theme_bw()

which results in

Sample Image

Aligning error bars with different numbers of bars per group in ggplot2

If I add dodge to error bars, too, I get this:

ggplot(aes(x = factor(loc), y = mean, fill = factor(spcs)), data = df) + 
geom_col(position = position_dodge(preserve = "single")) +
geom_errorbar(
aes(ymin = mean - 0.2, ymax = mean + 0.2),
position = position_dodge(width = 0.9, preserve = "single"),
width = 0.2)

Sample Image

EDIT

My guess is that some factor dropping is happening for a combination of factors loc*spcs, but I'm not motivated enough right now to go check it out. In any case, a workaround would be to add missing values for missing factors.

df <- data.frame(mean = 2:8, loc = c(rep(1, 4), 2, rep(3, 2)), spcs = c(1:4, 1, 2, 4))
df <- rbind(df, data.frame(mean = NA, loc = 3, spcs = c(1, 3)))

ggplot(aes(x = factor(loc), y = mean, fill = factor(spcs)), data = df) +
geom_col(position = position_dodge(preserve = "single")) +
geom_errorbar(
aes(ymin = mean - 0.2, ymax = mean + 0.2),
position = position_dodge(width = 0.9, preserve = "single"),
width = 0.2)

Sample Image

How can I align labels in a group of bar charts?

There are a number of issues with your minimal reproducible example. I strongly recommend using the reprex package and following How to make a minimal reproducible example and How to make a great R reproducible example for future posts.

The answer to your question is, I believe, very straightforward. If you add preserve = "single" to each geom_text() the labels appear to be positioned correctly. I wasn't able to run your example code, so I have stripped out some of the problematic sections to illustrate my answer:

library(tidyverse)

df <- structure(list(office = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 5L, 6L, 6L, 6L, 6L,
6L, 6L, 6L, 6L, 6L, 7L, 8L, 8L, 8L),
sentiment = c("positive",
"positive", "neutral", "neutral", "positive", "positive", "positive",
"positive", "neutral", "neutral", "neutral", "positive", "positive",
"negative", "negative", "positive", "neutral", "neutral", "neutral",
"positive", "neutral", "neutral", "negative", "positive", "positive",
"neutral", "positive", "positive", "neutral", "positive", "positive",
"positive", "positive", "positive", "negative", "neutral", "positive",
"positive", "positive", "positive", "positive", "neutral", "positive",
"positive", "positive", "positive", "positive", "neutral", "positive",
"positive")), class = "data.frame", row.names = c(NA, -50L))

office_sentiment <- df[ , c("office","sentiment")]
office_sentiment <- office_sentiment %>% group_by(sentiment,office) %>% summarize(Count = n())
#> `summarise()` has grouped output by 'sentiment'. You can override using the `.groups` argument.
office_sentiment <- filter(office_sentiment, Count >= 1,sentiment != "NA") #%>%
office_sentiment
#> # A tibble: 15 × 3
#> # Groups: sentiment [3]
#> sentiment office Count
#> <chr> <int> <int>
#> 1 negative 1 3
#> 2 negative 4 1
#> 3 neutral 1 11
#> 4 neutral 2 1
#> 5 neutral 4 1
#> 6 neutral 6 1
#> 7 neutral 8 1
#> 8 positive 1 12
#> 9 positive 2 2
#> 10 positive 3 4
#> 11 positive 4 1
#> 12 positive 5 1
#> 13 positive 6 8
#> 14 positive 7 1
#> 15 positive 8 2

office_sentiment_percentage <- df[ , c("office","sentiment")]
office_sentiment_percentage <- office_sentiment_percentage %>% group_by(sentiment,office) %>% summarize(Count = n())
#> `summarise()` has grouped output by 'sentiment'. You can override using the `.groups` argument.
office_sentiment_percentage <- filter(office_sentiment_percentage, Count >= 1,sentiment != "NA") %>%
mutate(percentage=Count/sum(Count)*100)
office_sentiment_percentage$percentage <- paste0(round(office_sentiment_percentage$percentage,1),"%")


ggplot(office_sentiment_percentage,
aes(x = office, y = Count, fill = sentiment)) +
ggtitle("Sentiment by Office") +
geom_col(width = 1,
position = position_dodge2(
padding = 0.1,
reverse = FALSE,
preserve = c("single")
)) +
scale_color_manual(
values = c("#66CCFF", "#009999", "#FF66CC"),
aesthetics = c("colour", "fill")
) +
scale_y_continuous(sec.axis = waiver(), expand = expansion(mult = c(0, 0.05))) +
facet_wrap(~office, strip.position = "bottom", scales = "free_x") +
xlab("sentiment") +
ylab("total count") +
theme(axis.text.x = element_blank()) +
geom_text(
aes(label = Count),
vjust = 1.5,
position = position_dodge2(width = 1, preserve = "single"),
size = 2.5
) +
geom_text(
aes(label = percentage),
vjust = -.3,
position = position_dodge2(width = 1, preserve = "single"),
size = 2.5
) +
guides(fill = guide_legend(reverse = TRUE))

Sample Image

Created on 2022-01-14 by the reprex package (v2.0.1)

Does this solve your problem?

How to align the bars of a histogram with the x axis?

This will center the bar on the value

data <- data.frame(number = c(5, 10, 11 ,12,12,12,13,15,15))
ggplot(data,aes(x = number)) + geom_histogram(binwidth = 0.5)

Here is a trick with the tick label to get the bar align on the left..
But if you add other data, you need to shift them also

ggplot(data,aes(x = number)) + 
geom_histogram(binwidth = 0.5) +
scale_x_continuous(
breaks=seq(0.75,15.75,1), #show x-ticks align on the bar (0.25 before the value, half of the binwidth)
labels = 1:16 #change tick label to get the bar x-value
)

other option: binwidth = 1, breaks=seq(0.5,15.5,1) (might make more sense for integer)

Overlay geom_point to geom_bar. How to align the points and bars?

The simple issue is the coloring of the points. To get black points simply map cyl on the group aesthetic in the geom_point layer. The tricky part is the positioning. To get the positioning of the points right you have to fill up mydf2 to include all combinations of cyl and carb as you have already done for mydf1. To this end I use tidyr::complete. Try this:

library(ggplot2)

mtcars$model <- rownames(mtcars)
#head(mtcars)

mtcars$cyl <- as.factor(as.character(mtcars$cyl))
mtcars$carb <- as.factor(as.character(mtcars$carb))
#summary(mtcars)
mydf1 <- as.data.frame(data.table::data.table(mtcars)[, list(max=max(disp)), by=list(cyl=cyl, carb=carb)])

mydf2 <- mtcars[,c(2,3,11,12)]

zerodf <- expand.grid(cyl=unique(mtcars$cyl), carb=unique(mtcars$carb))
mydf1 <- merge(mydf1, zerodf, all=TRUE)
mydf1$max[which(is.na(mydf1$max))] <- 0

mydf2 <- tidyr::complete(mydf2, carb, cyl)

ggplot(data = NULL, aes(group = cyl)) +
geom_bar(data=mydf1, aes(carb, max, fill=cyl), position="dodge", stat="identity") +
scale_fill_manual(values=c("blue","red","grey")) +
geom_point(data=mydf2, aes(carb, disp, group=cyl), position = position_dodge(width = 0.9), shape=3, size=5, show.legend=FALSE)
#> Warning: Removed 9 rows containing missing values (geom_point).

Sample Image

geom_text how to position the text on bar as I want?

Edit:

The easier solution to get hjust/vjust to behave intelligently is to add the group aesthetic to geom_text and then hjust & position adjust for the group automatically.

1. Vertical Orientation

ggplot(data) + 
geom_bar(
aes(x = name, y = count, fill = week, group = week),
stat='identity', position = 'dodge'
) +
geom_text(
aes(x = name, y = count, label = count, group = week),
position = position_dodge(width = 1),
vjust = -0.5, size = 2
) +
theme_bw()

This gives:

Sample Image

2. Horizontal Orientation

ggplot(data) + 
geom_bar(
aes(x = name, y = count, fill = week, group = week),
stat='identity', position = 'dodge'
) +
geom_text(
aes(x = name, y = count, label = count, group = week),
hjust = -0.5, size = 2,
position = position_dodge(width = 1),
inherit.aes = TRUE
) +
coord_flip() +
theme_bw()

This gives:

Sample Image


This is not necessarily the most general way to do this, but you can have a fill dependent hjust (or vjust, depending on the orientation) variable. It is not entirely clear to me how to select the value of the adjustment parameter, and currently it is based on what looks right. Perhaps someone else can suggest a more general way of picking this parameter value.

1. Vertical Orientation

library(dplyr)
library(ggplot2)

# generate some data
data = data_frame(
week = as.factor(rep(c(1, 2), times = 5)),
name = as.factor(rep(LETTERS[1:5], times = 2)),
count = rpois(n = 10, lambda = 20),
hjust = if_else(week == 1, 5, -5),
vjust = if_else(week == 1, 3.5, -3.5)
)

# Horizontal
ggplot(data) +
geom_bar(
aes(x = name, y = count, fill = week, group = week),
stat='identity', position = 'dodge'
) +
geom_text(
aes(x = name, y = count, label = count, vjust = vjust),
hjust = -0.5, size = 2,
inherit.aes = TRUE
) +
coord_flip() +
theme_bw()

Here is what that looks like:

Sample Image

2. Horizontal Orientation

ggplot(data) + 
geom_bar(
aes(x = name, y = count, fill = week, group = week),
stat='identity', position = 'dodge'
) +
geom_text(
aes(x = name, y = count, label = count, vjust = vjust),
hjust = -0.5, size = 2,
inherit.aes = TRUE
) +
coord_flip() +
theme_bw()

Here is what that looks like:

Sample Image

Aligning subplots with a pyplot barplot and seaborn heatmap

A problem is that the colorbar takes away space from the heatmap, making its plot narrower than the bar plot. You can create a 2x2 grid to make room for the colorbar, and remove the empty subplot. Change sharex=True to sharex='col' to prevent the colorbar getting the same x-axis as the heatmap.

Another problem is that the heatmap has its cell borders at positions 0, 1, 2, ..., so their centers are at 0.5, 1.5, 2.5, .... You can put the bars at these centers instead of at their default positions:

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

fig, ((ax1, cbar_ax), (ax2, dummy_ax)) = plt.subplots(nrows=2, ncols=2, figsize=(26, 16), sharex='col',
gridspec_kw={'height_ratios': [5, 1], 'width_ratios': [20, 1]})
missings_df = np.random.rand(3, 3)
sns.heatmap(missings_df.T, cmap="Blues", cbar_ax=cbar_ax, xticklabels=False, linewidths=2, ax=ax1)

ax2.set_xlabel('Time (hours)')

patient_counts = np.random.randint(10, 50, 3)
x_ticks = ['Time1', 'Time2', 'Time3']
x_tick_pos = [i + 0.5 for i in range(len(x_ticks))]
ax2.bar(x_tick_pos, patient_counts, align='center')
ax2.set_xticks(x_tick_pos)
ax2.set_xticklabels(x_ticks)
dummy_ax.axis('off')

plt.tight_layout()
plt.show()

example plot

PS: Be careful not to mix the "functional" interface with the "object-oriented" interface to matplotlib. So, try not to use plt.xlabel() as it is not obvious that it will be applied to the "current" ax (ax2 in the code of the question).

Chart bars not aligning with x axis values in d3.js

Try this code:

.rangeBands([0, width], someValue)



Related Topics



Leave a reply



Submit