1

I have a dataframe with 4 columns. This includes year, month, week_no (week of the year), and a count field (n).

I want to plot a line graph showing the number of starts by year, with a individual line for each year. The x-axis would would use the week number field, but would be labelled using the month, so it would produce something like the below:

Sample from dataframe

year month week number starts
2021 Dec 50 101
2021 Dec 51 104
2021 Dec 52 110
2022 Jan 1 111
2022 Jan 2 115
2022 Jan 3 144
2022 Jan 4 156

I have used the below code in plotly but this displays the week number on the x-axis

plot_ly(df, x = ~week_number, y = ~starts  type = 'scatter',color = ~year, mode = 'lines')
M--
  • 25,431
  • 8
  • 61
  • 93
Nick Read
  • 53
  • 2
  • 1
    You'll want to convert your year/week values into proper date values. See https://stackoverflow.com/questions/45549449/transform-year-week-to-date-object then you can use a proper time series axis and only show the month: https://plotly.com/r/time-series/ – MrFlick Jan 09 '23 at 16:26
  • @MrFlick there's an issue with that, if you actually convert them to the right dates (year, week no.), then they won't appear like what OP asked for. You need to put an arbitrary year (constant for all). – M-- Jan 10 '23 at 07:45
  • @M-- I'm not sure I understand. It doesn't seem that the OP wants the month names to repeat as they do in your solution. There should be only one label for "Dec" as in the sample image. – MrFlick Jan 10 '23 at 14:21
  • @MrFlick 2021 and 2022 are on top of each other. – M-- Jan 10 '23 at 14:30
  • 1
    @M-- Ah. I see what you are saying now. Got it. – MrFlick Jan 10 '23 at 14:33

1 Answers1

1

I have made an adjustment to the data, to put all the dates near December, so the plot looks better for this small portion of dataset. See below;

All you need to do is changing ticktext using layout:

library(plotly)

plot_ly(df1, x = ~week_number, y = ~starts,  
            type = 'scatter', color=~as.character(year), mode = 'lines') %>% 
  layout(xaxis = list(tickvals = ~week_number, ticktext = ~month))

Update:

In order to only get one tick mark for each month, we need the actual dates, not just week numbers. You can convert a date formatted as YYYY-UU-uu to the conventional date format. However, here since you want all years to appear on top of each other, we should create an arbitrary date with the same year for all the rows, so the plot won't get extended to multiple years.

After mutating those dates, we can use layout to set the dtick to M1 and format the labels as %b to only show the month names and dhow them once. ticklabelmode = 'period' makes sure to have a tick for every month. I added a hovertemplate to show the week number. I also removed the title from the axes and added a graph title to make the final plot look more like what you've shown in your question.

library(plotly)
library(dplyr)

df2 %>% 
  mutate(pseudo_Date = as.Date(paste(2000, week_number, 1, sep="-"), "%Y-%U-%u")) %>% 
 plot_ly(., x = ~pseudo_Date, y = ~starts,  
         type = 'scatter', color=~as.character(year), mode = 'lines',
         hovertemplate = "Week Number: %{x|%U | } %{x}") %>% 
  layout(xaxis = list(title = "", 
                      dtick = "M1", tickformat = '%b', ticklabelmode = "period"),
         yaxis = list(title = ""),
         title = 'Chart 2. Total starts by week')

Data:

df1 <- read.table(text = "year  month   week_number     starts
2021    Dec     50  101
2021    Dec     51  104
2021    Dec     52  110
2022    Nov     48  111
2022    Dec     49  115
2022    Dec     50  144
2022    Dec     51  156", header = T, stringsAsFactor = F)

df2 <- read.table(text = "year  month   week_number     starts
2020    Nov     46  100
2020    Nov     47  120
2020    Nov     48  111
2020    Dec     49  115
2020    Dec     50  144
2020    Dec     51  156
2021    Dec     50  101
2021    Dec     51  104
2021    Dec     52  110
2022    Jan     1   108
2022    Jan     2   108
2022    Jan     3   125
2022    Jan     4   160", header = T, stringsAsFactor = F)
M--
  • 25,431
  • 8
  • 61
  • 93