The Ask:
Please help me understand my conceptual error in the use of scale_x_binned() in ggplot2 as it relates to centering breaks beneath the appropriate bin in a geom_histogram().
Starting Example:
library(ggplot2)
df <- data.frame(hour = sample(seq(0,23), 150, replace = TRUE))
# The data is just the integer values of the 24-hour clock in a day. It is
# **NOT** continuous data.
ggplot(df, aes(x = hour)) +
geom_histogram(bins = 24, fill = "grey60", color = "red")

This produces a histogram with labels properly centered beneath the bin for which it belongs, but I want to label each hour, 0 - 23.
To do that, I thought I would assign breaks using scale_x_binned()
as demonstrated below.
Now I try to add the breaks:
ggplot(df, aes(x = hour)) +
geom_histogram(bins = 24, fill = "grey60", color = "red") +
scale_x_binned(name = "Hour of Day",
breaks = seq(0,23))
#> Warning: Removed 1 rows containing missing values (`geom_bar()`).

This returns the number of labels I wanted, but they are not centered
beneath the bins as desired. I also get the warning message for missing
values associated with geom_bar().
I believe I am overwriting the bins = 24 from the geom_histogram() call when I use the scale_x_binned() call afterward, but I don't understand exactly what is causing geom_histogram() to be centered in the first case that I am wrecking with my new call. I'd really like to have that clarified as I am not seeing my error when I read the associated help pages.
EDIT:
The "Starting Example" essentially works (bins are centered) except for the number of labels I ultimately want. If you built the ggplot2 layer differently, what is the equivalent code? That is, instead of:
ggplot(df, aes(x = hour)) +
geom_histogram(bins = 24, fill = "grey60", color = "red")
the call was instead built something like:
ggplot(df, aes(x = hour)) +
geom_histogram(fill = "grey60", color = "red") +
scale_x_binned(n.breaks = 24) # I know this isn't right, but akin to this.
or maybe
ggplot(df, aes(x = hour)) +
stat_bin(bins = 24, center = 0, fill = "grey60", color = "red")

It sounds like you are looking to use non-default labeling, where you want the labels to be aligned to the midpoint of the bins instead of their boundaries, which is what the
breaksdefine. We could do that by using a continuous scale and hiding the main breaks, but keeping the minor breaks, like below.scale_x_binneddoes not have minor breaks. It only has breaks at the boundaries of the bins, so it's not obvious to me how you could place the break labels at the midpoints of the bins.