Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shift x-axis ticks with scale_x_datetime and geom_col so bars are NOT centered on tick mark

I am plotting time series data in half-hour intervals, using geom_col() to show number of birds counted in each interval. ggplot2 plots each bar centered over the x-axis tick mark, but I need each bar to begin to the right of each tick mark. In other words, I need each bar to span the width of its corresponding half-hour interval.

I have tried the suggested solutions in these posts without luck:

  • Bars starting after x-axis tickmark when using scale_x_datetime
  • How to force the x-axis tick marks to appear at the end of bar in heatmap graph?

Below is example code that reproduces the issue:

    ``` r
library(lubridate)
#> 
#> Attaching package: 'lubridate'
#> The following objects are masked from 'package:base':
#> 
#>     date, intersect, setdiff, union
library(ggplot2)
library(tidyverse)

df <- data.frame(
  date = c("2019-05-16", "2019-05-16", "2019-05-16", "2019-05-16", "2019-05-16", "2019-05-16", "2019-05-16", "2019-05-16"),
  time = c("16:30:00", "17:00:00", "17:30:00", "18:00:00", "18:30:00", "19:00:00", "19:30:00", "20:00:00"),
  count = c(5, 100, 14, 342, 59, 321, 44, 98),
  stringsAsFactors = FALSE)

datetime_df <- df %>% 
  mutate(time_stamp = paste(date, time) %>% as_datetime())

plot <- ggplot(datetime_df, aes(x = time_stamp, y = count)) +
  geom_col() +
  scale_x_datetime(breaks = scales::date_breaks("30 mins"), date_labels = "%H:%M",
                                    limits = c(as_datetime("2019-05-16 16:00:00"), 
                                               as_datetime("2019-05-16 20:30:00"))) +
  scale_y_continuous(expand = c(0,0), breaks = seq(0, 500, by = 50), limits = c(0,500))

Created on 2020-10-01 by the reprex package (v0.3.0)

Here is the resulting bar chart

Many thanks for any ideas on how to solve this issue!

like image 521
m.hand Avatar asked Oct 01 '20 04:10

m.hand


People also ask

Which function would you use to set the ticks for X axis of the plot?

xticks( ticks ) sets the x-axis tick values, which are the locations along the x-axis where the tick marks appear. Specify ticks as a vector of increasing values; for example, [0 2 4 6] . This command affects the current axes.

What is a tick mark on an axis?

A tick is a short line on an axis. For category axes, ticks separate each category. For value axes, ticks mark the major divisions and show the exact point on an axis that the axis label defines. Ticks are always the same color and line style as the axis.

How do you add a tick to a graph?

Add tick marks on an axisClick the chart, and then click the Chart Design tab. Click Add Chart Element > Axes > More Axis Options. On the Format Axis pane, expand Tick Marks, and then click options for major and minor tick mark types.

What do you call the ticks on a graph?

Hatch marks (also called hash marks or tick marks) are a form of mathematical notation. They are used in three ways as: Unit and value marks — as on a ruler or number line. Congruence notation in geometry — as on a geometric figure. Graphed points — as on a graph.


1 Answers

You can mimic this easily by adding 15 minutes to your times:

plot <- ggplot(datetime_df, aes(x = time_stamp + minutes(15), y = count)) +
  geom_col() +
  scale_x_datetime(breaks = scales::date_breaks("30 mins"), date_labels = "%H:%M",
                                    limits = c(as_datetime("2019-05-16 16:00:00"), 
                                               as_datetime("2019-05-16 20:30:00"))) +
  scale_y_continuous(expand = c(0,0), breaks = seq(0, 500, by = 50), limits = c(0,500))
plot

enter image description here

To make the ticks line up exactly with the start of the bar, you'll need to set the width parameter in geom_col to match the number of minutes added. After a little trial and error, this seems to work:

half_width_in_min = 13
plot <- ggplot(datetime_df, aes(x = time_stamp + minutes(half_width_in_min ), y = count)) +
  geom_col(width = 60 * 24 * 1.25 * half_width_in_min / 15) +
  scale_x_datetime(breaks = scales::date_breaks("30 mins"), date_labels = "%H:%M",
                                    limits = c(as_datetime("2019-05-16 16:00:00"), 
                                               as_datetime("2019-05-16 20:30:00"))) +
  scale_y_continuous(expand = c(0,0), breaks = seq(0, 500, by = 50), limits = c(0,500))
plot

enter image description here

like image 67
Gregor Thomas Avatar answered Oct 17 '22 20:10

Gregor Thomas