第 5 章 Scale
In geom, aes(xxx=yyy)
, defines a mapping from data vector yyy
to aesthetic vector xxx
. To change or fine tune this mapping, you add scale_xxx_...
to your ggplot object.
In general, a mapping can be divided into two parts
- How to map?
limits
: the range of data vector to be mapped.
values
: the mapped values fromlimits
.
- In the the mapping, what to show to the readers? This is about the information in legend (圖例說明)
breaks
: the picked values inlimits
.
labels
: the mapped values ofbreaks
.
name
: the title of the legend.
Depending on aesthetics, not all five settings will be necessary.
5.1 Legend
<- data.frame(
data_cat1 x=c(1, 2, 3, 1, 2, 3),
y=c(0.2, 0.3, 0.2, 0.4, 0.4, 0.52),
fill=c("m", "m", "m", "f", "f", "f")
)<- list()
ggplot0 0 #input$null
$plot1 <-
ggplot0ggplot(
data=data_cat1
+
) geom_area(
mapping=aes(
x=x,
y=y,
fill=factor(fill, levels=c("m", "f"))
)
)$plot1 ggplot0
$plot1 +
ggplot0scale_fill_discrete(
name="Gender",
breaks=c("m", "f"),
labels=c("Male", "Female")
-> ggplot0$plot2
) $plot2 ggplot0
On every graph, by default, there is legend and/or axis that show information of how aes=variable
mapping is defined. However, those variable value expressions you see in the legend/axis are defined by labels
(such as “Male,” “Female”), whose corresponding variable values are defined in breaks
(such as “m” and “f”); and name
gives lengend/axis a title (such as “Gender”).
5.2 Time axis
Generate basic plot:
<-
dataSet1 data.frame(
x=1979:2018
)set.seed(2038)
$y <- sample(10:40, length(dataSet1$x), T)
dataSet1<- list()
ggplot1
ggplot()+
geom_step(
data=dataSet1,
mapping=
aes(
x=x,
y=y
)-> ggplot1$plot0
) $plot0 ggplot1
Define x-axis labels:
= c(
breaks 1979,
seq(1985, 2015, by=5),
2018
)= c(
labels "1979", "85", "90", "95", "2000", "05", "10", "15", "18"
)
$plot0 +
ggplot1scale_x_continuous(
breaks=breaks,
labels=labels
-> ggplot1$plot1
)
$plot1 ggplot1
Remove scale ticks
$plot1 +
ggplot1theme(
axis.ticks.length.x = unit(0,"mm")
-> ggplot1$plot1
)
$plot1 ggplot1
Add ticks:
major ticks: ticks that belong to constant time span labels
minor ticks: ticks that are not major ticks.
<- list()
ticks $major <- seq(1980, 2015, by=5)
ticks$minor <- c(1979, 2018)
ticks
= 3 #input$length
majorLength = 0.7 #input$ratio
minor_majorRatio
$plot1 +
ggplot1geom_rug(
mapping=aes(
x=ticks$major
),outside=TRUE, # draw rug outside the plot panel
size=0.5, #input$majorsize
length=grid::unit(
majorLength, "mm"
)+
) geom_rug(
mapping=aes(
x=ticks$minor
),outside = TRUE,
size=0.5, #input$minorsize
length=grid::unit(
*majorLength,
minor_majorRatio"mm"
)+
)coord_cartesian(clip="off") -> # allow drawing outside the plot panel
$plot2
ggplot1
$plot2 ggplot1
$plot2 +
ggplot1theme(
axis.text.x = element_text(
margin = margin(
12 #input$margin
),size=16 #input$textSize
))
margin(t=0, r=0, b=0, l=0, unit='pt')
5.2.1 Custom axis function
Pull out all the axis-related building blocks:
{# scale_x
scale_x_continuous(
breaks=breaks,
labels=labels
+
) theme(
axis.ticks.length.x = unit(0,"mm"),
axis.text.x = element_text(
margin = margin(
12 #input$margin
),size=16 #input$textSize
)+
)geom_rug(
mapping=aes(
x=ticks$major
),outside=TRUE, # draw rug outside the plot panel
size=0.5, #input$majorsize
length=grid::unit(
majorLength, "mm"
)+
) geom_rug(
mapping=aes(
x=ticks$minor
),outside = TRUE,
size=0.5, #input$minorsize
length=grid::unit(
*majorLength,
minor_majorRatio"mm"
)+
)coord_cartesian(clip="off")
}
Build a function:
<- function(
axis_x_continuouse_custom
breaks, labels,
ticks_major, ticks_minor,ticks_major_length = 3,
minor_major_tickLength_ratio = 0.7,
text_size = 16,
text_top_margin = 12,
major_tick_size = 0.5,
minor_tick_size = 0.5
){list(
scale_x_continuous(
breaks=breaks,
labels=labels
), theme(
axis.ticks.length.x = unit(0,"mm"),
axis.text.x = element_text(
margin = margin(
#input$margin
text_top_margin
),size=text_size #input$textSize
)
), geom_rug(
mapping=aes(
x=ticks_major
),outside=TRUE, # draw rug outside the plot panel
size=major_tick_size, #input$majorsize
length=grid::unit(
ticks_major_length, "mm"
)
), geom_rug(
mapping=aes(
x=ticks_minor
),outside = TRUE,
size=minor_tick_size,
length=grid::unit(
*ticks_major_length,
minor_major_tickLength_ratio"mm"
)
), coord_cartesian(clip="off")
) }
= c(
breaks 1979,
seq(1985, 2015, by=5),
2018
)= c(
labels "1979", "85", "90", "95", "2000", "05", "10", "15", "18"
)<- seq(1980, 2015, by=5)
ticks_major <- c(1979, 2018)
ticks_minor
$plot0 +
ggplot1axis_x_continuouse_custom(
breaks=breaks, labels=labels,
ticks_major = ticks_major,
ticks_minor = ticks_minor
)
5.2.2 Advanced function
Other input as default: when
labels
is omitted, usebreaks
valueWhen
ticks_minor
is omitted, remove minor geom_rug.
<- function(
axis_x_continuouse_custom labels = breaks,
breaks, ticks_minor=NULL,
ticks_major, ticks_major_length = 3,
minor_major_tickLength_ratio = 0.7,
text_size = 16,
text_top_margin = 12,
major_tick_size = 0.5,
minor_tick_size = 0.5
){list(
scale_x_continuous(
breaks=breaks,
labels=labels
), theme(
axis.ticks.length.x = unit(0,"mm"),
axis.text.x = element_text(
margin = margin(
#input$margin
text_top_margin
),size=text_size #input$textSize
)
), geom_rug(
data = data.frame(
ticks_major=ticks_major
),mapping=aes(
x=ticks_major
),outside=TRUE, # draw rug outside the plot panel
size=major_tick_size, #input$majorsize
length=grid::unit(
ticks_major_length, "mm"
)
),if(!is.null(ticks_minor)){
geom_rug(
data = data.frame(
ticks_minor=ticks_minor
),mapping=aes(
x=ticks_minor
),outside = TRUE,
size=minor_tick_size,
length=grid::unit(
*ticks_major_length,
minor_major_tickLength_ratio"mm"
)
)else {
} NULL
}, coord_cartesian(clip="off")
) }
$plot0 +
ggplot1axis_x_continuouse_custom(
breaks=breaks,
ticks_major = ticks_major
)
There are many possible scale_x
. We can build a axis_x_custom
function that can take all possible scale_x_zzz
as input, and return axis_x_zzz_custom
function as an output.
Function that can take function as input is called functional.
Functionals that generate functions are called function generators.
<- function(scale_x){
axis_x_custom function(
labels = breaks,
breaks, ticks_minor=NULL,
ticks_major, ticks_major_length = 3,
minor_major_tickLength_ratio = 0.7,
text_size = 16,
text_top_margin = 12,
major_tick_size = 0.5,
minor_tick_size = 0.5
){list(
scale_x(
breaks=breaks,
labels=labels
), theme(
axis.ticks.length.x = unit(0,"mm"),
axis.text.x = element_text(
margin = margin(
#input$margin
text_top_margin
),size=text_size #input$textSize
)
), geom_rug(
data = data.frame(
ticks_major=ticks_major
),mapping=aes(
x=ticks_major
),outside=TRUE, # draw rug outside the plot panel
size=major_tick_size, #input$majorsize
length=grid::unit(
ticks_major_length, "mm"
)
),if(!is.null(ticks_minor)){
geom_rug(
data = data.frame(
ticks_minor=ticks_minor
),mapping=aes(
x=ticks_minor
),outside = TRUE,
size=minor_tick_size,
length=grid::unit(
*ticks_major_length,
minor_major_tickLength_ratio"mm"
)
)else {
} NULL
}, coord_cartesian(clip="off")
)
} }
# generate axis_x_continuous_custom
<-
axis_x_continuous_custom2 axis_x_custom(scale_x_continuous)
$plot0 +
ggplot1axis_x_continuous_custom2(
breaks=breaks,
ticks_major = ticks_major
)$plot0 +
ggplot1axis_x_continuous_custom2(
breaks=breaks, labels=labels,
ticks_major = ticks_major,
ticks_minor = ticks_minor
)
5.2.3 Time period
When axis x is to represent a period:
Basic plot:
<- data.frame(
dataSet2 x=seq(from=lubridate::ymd("2013-01-01"),
to=lubridate::ymd("2013-12-31"),
by="1 day")
)
$y <- {
dataSet2<- c(100)
y set.seed(2033)
<- rnorm(length(dataSet2$x), sd=50)
shocks
shocksfor(t in 2:length(dataSet2$x)){
<- 1*t + 0.6*y[[t-1]] + shocks[[t]]
y[[t]]
}
y }
7-days moving average:
install.packages("zoo")
library(dplyr)
%>%
dataSet2 mutate(
y_smooth=zoo::rollmean(y, 7, na.pad=TRUE, align="center")
-> dataSet2 )
zoo::rollmean(y, window_width, padding_na_to_maintain_length, window_center)
<- list()
ggplot2 $plot1 <- {
ggplot2ggplot()+
geom_line(
data=dataSet2,
mapping=aes(
x=x,
y=y_smooth
)
)
}
$plot1 ggplot2
Add rug ticks and labels:
<-
axis_x_date_custom axis_x_custom(scale_x_date)
# breaks in middle of the month
# set 15th of every month
=seq(
breaksfrom=lubridate::ymd("20130115"),
to=lubridate::ymd("20131215"),
by="1 month"
)=lubridate::month(
labels
breaks,label=TRUE # Use month name based on OS locale
)
labels
=c(
ticks_majorseq(
from=lubridate::ymd("20130101"),
to=lubridate::ymd("20131231"),
by="1 month"
),::ymd("20131231")) lubridate
Locales in your operating system determine how month and weekday should be expressed:
* Windows: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c
* Mac OS/linux:
<- system("locale -a", intern = TRUE) locales
::month(breaks,
lubridatelocale = "zh_TW",
label = T # returned as month abbreviates
)::wday(breaks,
lubridatelocale = "zh_TW",
label = T # returned as month abbreviates
)
$plot1 +
ggplot2axis_x_date_custom(
breaks=breaks, labels=labels,
ticks_major=ticks_major,
ticks_major_length = 2, #input$tickLength
text_size = 14 #input$textSize
)
5.2.4 dot-dot-dot
...
can pass any arguments not defined in function usage as one argument input that can be used in any place by calling...
.
<- function(scale_x){
axis_x_custom function(
labels = breaks,
breaks, ticks_minor=NULL,
ticks_major, ticks_major_length = 3,
minor_major_tickLength_ratio = 0.7,
text_size = 16,
text_top_margin = 12,
major_tick_size = 0.5,
minor_tick_size = 0.5, ...
){list(
scale_x(
breaks=breaks,
labels=labels, ...
), theme(
axis.ticks.length.x = unit(0,"mm"),
axis.text.x = element_text(
margin = margin(
#input$margin
text_top_margin
),size=text_size #input$textSize
)
), geom_rug(
data = data.frame(
ticks_major=ticks_major
),mapping=aes(
x=ticks_major
),outside=TRUE, # draw rug outside the plot panel
size=major_tick_size, #input$majorsize
length=grid::unit(
ticks_major_length, "mm"
)
),if(!is.null(ticks_minor)){
geom_rug(
data = data.frame(
ticks_minor=ticks_minor
),mapping=aes(
x=ticks_minor
),outside = TRUE,
size=minor_tick_size,
length=grid::unit(
*ticks_major_length,
minor_major_tickLength_ratio"mm"
)
)else {
} NULL
}, coord_cartesian(clip="off")
)
} }
<-
axis_x_date_custom axis_x_custom(scale_x_date)
$plot1 +
ggplot2axis_x_date_custom(
breaks=breaks, labels=labels,
ticks_major=ticks_major,
ticks_major_length = 2, #input$tickLength
text_size = 14, #input$textSize
name="2013"
)
Multiple rug tick lengths:
<- data.frame(
dataSet3 x=seq(from=lubridate::ymd("2011-01-01"),
to=lubridate::ymd("2014-06-01"),
by="1 month")
)
$y <- {
dataSet3<- c(100)
y set.seed(2033)
<- rnorm(length(dataSet3$x), sd=50)
shocks
shocksfor(t in 2:length(dataSet3$x)){
<- 1*t + 0.6*y[[t-1]] + shocks[[t]]
y[[t]]
}
y
}
%>%
dataSet3 mutate(
y_smooth = zoo::rollmean(y, 5, na.pad=TRUE, align="center")
-> dataSet3 )
<- list()
ggplot3 ggplot()+
geom_line(
data=dataSet3,
mapping=aes(
x=x,
y=y_smooth
)-> ggplot3$plot1
) $plot1 ggplot3
# breaks in middle of years, set at June, except 2014, set at March
= c(
breaks seq(
from=lubridate::ymd("20110601"),
to=lubridate::ymd("20130601"),
by="1 year"
),::ymd("20140301")
lubridate
)= c("2011", "12", "13", "14")
labels =seq(
ticks_majorfrom=lubridate::ymd("20110101"),
to=lubridate::ymd("20140101"),
by="1 year"
)=seq(
ticks_minorfrom=lubridate::ymd("20110101"),
to=lubridate::ymd("20140601"),
by="1 month"
)
$plot1 +
ggplot3axis_x_date_custom(
breaks=breaks,
labels=labels,
ticks_major = ticks_major,
ticks_minor = ticks_minor
)
Exercise 5.1 How do you put ticks inside?
For date/time axis:
* always assign ticks to the beginning and the end of the sample period.
* when too many ticks are there,
* try to label few of them, like labeling every 5 years, every 6 months, etc. Or
* use period marking.
* when use period marking, put labels in the middle of the period.
5.3 XY axis
5.3.1 Expansion and out-of-bound
Among scale_x_...
and scale_y_...
, there are two arguments that might be handy:
expand: define the padding around the limits of the plot. (圖形與xy軸的留白空間)
oob (out of bound): define what to do when observations are out of limits bound. (超出作圖範圍的資料點要怎麼處置)
<- data.frame(
dataSet x=rep(c("Jan", "Feb", "Mar"),2),
y=c(10, 20, 30, 10, 25, 33),
group=c(rep("Art", 3), rep("General", 3))
)ggplot()+
geom_col(
data=dataSet,
mapping=
aes(
x=x, y=y,
fill=group
),position="dodge",
width=0.8
+
)scale_y_continuous(
expand =
expansion(0, #input$multiply
0 #input$add
) )
expand = c(lowerBoundStretch, upperBoundStretch)
:lowerBoundStretch=c(a,b)
:lowerBound - a*range -b
upperBoundStretch=c(c,d)
:upperBound + c*range +d
expansion(m, n)
will set a=c=m, b=d=n.
5.3.2 Secondary axis
Rescale right series to left series range.
Map LHS breaks to RHS
5.3.2.1 Preliminary analytics
The relationship between two series.
=readRDS("data/eu.Rds")
eu
<- econDV2::Object(ggplot4)
ggplot4 $data = eu$data2 |> dplyr::filter(
ggplot4>= "2011-01-01"
time
)$summary$industrialProductionChange$range <- {
ggplot4$data$ind_procution_change |> range(na.rm = T)
ggplot4
}$summary$unemploymentRate$range <- {
ggplot4$data$unemploymentRate |> range(na.rm=T)
ggplot4
}
$scatter_path <- function(plotly=F, timeEnd="2014-06-01"){
ggplot4ggplot(
data=ggplot4$data |> subset(
<= timeEnd),
time mapping=aes(
x=ind_procution_change,
y=unemploymentRate,
label=time
)+
)geom_point()+geom_path() -> gg
if(plotly){plotly::ggplotly(gg)} else {gg}
}
$scatter_path(T) ggplot4
- Observe negative correlation between year-to-year change of industrial production and unemployment rate.
5.3.2.2 Graphic design
- A graph that shows negative correlated movements.
$ggplot <- function(){
ggplot4ggplot(
data= ggplot4$data |>
subset(time <= "2014-06-01"),
mapping=aes(x=time)
)
}$industrialProduction <- function(){
ggplot4geom_col(
mapping=aes(
y=ind_procution_change
),fill="#04a2d0"
)
}$unemployment <- function(){
ggplot4geom_line(
aes(
y=unemploymentRate
),color="#77230f"
)
}$scale_y_ind_production <- function(...){
ggplot4scale_y_continuous(
name="Industrial production",
limits = c(-10, 11),
breaks = seq(-10, 10, by=5),
labels = seq(-10, 10, by=5),
...
)
}$scale_y_unemployment <- function(...){
ggplot4scale_y_continuous(
name="Unemployment",
limits = c(3, 13),
breaks = seq(4,12, by=2),
...
)
}
$just$industrialProduction <- function(){
ggplot4$ggplot()+
ggplot4$industrialProduction()+
ggplot4$scale_y_ind_production()
ggplot4
}$just$unemployment <- function(){
ggplot4$ggplot()+
ggplot4$unemployment()+
ggplot4$scale_y_unemployment()
ggplot4
}
$twoSeries <- function(...){
ggplot4$ggplot()+
ggplot4$industrialProduction()+
ggplot4$unemployment()+
ggplot4$scale_y_ind_production(...)
ggplot4
}$twoSeries() ggplot4
5.3.2.3 Secondary axis
$sec_y_unemployment <- function(){
ggplot4
# mapping left breaks to unemployment range
# ggplot4$scale_y_ind_production() -> left_y
# left_y$breaks |> range()
= function(breaks){
transfer_leftBreaks ::rescale(breaks,
scalesfrom=c(-10,10), to=c(4, 12))
}
# left_y$breaks |> transfer_leftBreaks()
sec_axis(
name="Unemployment",
trans=transfer_leftBreaks,
breaks=seq(4, 12, by=2)
)
}
$twoSeries(
ggplot4sec.axis=ggplot4$sec_y_unemployment()
)
5.3.2.4 Rescale right series
Unemployment is drawn based on left y scale, not based on the secondary (right) y scale.
One plot can only have one y scale to define y coordinate (which will be the left y).
Unemployment rate of 10 will be placed at the height of 10 as left y would show, but
Right y 10 is actually in line with left -5; So
We need to map unemployment rate of 10 to -5, which is an inverse transfer function of
transfer_leftBreaks
.
$scaled_unemployment <- function(){
ggplot4
<- function(breaks){
transferInv_leftBreaks ::rescale(breaks,
scalesto=c(-10,10), from=c(4, 12))
}
geom_line(
aes(
y=transferInv_leftBreaks(unemploymentRate)
),color="#77230f"
)
}
$twoSeries_recaled <- function(){
ggplot4$ggplot() +
ggplot4$industrialProduction() +
ggplot4$scaled_unemployment() +
ggplot4$scale_y_ind_production(
ggplot4sec.axis=ggplot4$sec_y_unemployment(),
expand=expansion(0,add=c(0,1))
)
}$twoSeries_recaled() ggplot4
5.3.2.5 Time axis
$scale_x <- function(){
ggplot4<- econDV2::axis_x_custom(scale_x_date)
scale_x_custom scale_x_custom(
breaks = lubridate::ymd(c(paste(2011:2013,"06","01"), "2014-03-01")),
labels = c("2011", "12", "13", "14"),
ticks_major = lubridate::ymd(
paste(2011:2014, "1", "1")
),ticks_minor = seq(
from=lubridate::ymd("2011-01-01"),
to=lubridate::ymd("2014-06-01"),
by="1 month"
)
) }
5.3.2.6 gg$dash
=8 #input$size_title
size=8 #input$size_text
size_text=1 #input$vjust
vjust=0 #input$angel
angle=-50 #input$margin_l
margin_l=-50 #input$margin_r
margin_r$twoSeries_recaled() +
ggplot4$scale_x() +
ggplot4theme(
axis.title.x = element_blank(),
axis.line.y=element_blank(),
axis.ticks.y=element_blank(),
panel.grid.major.y=
element_line(color="#ececec"),
axis.text.y.left=
element_text(color="#04a2d0",
size=size_text
),axis.text.y.right=
element_text(color="#77230f",
size=size_text
),axis.title.y.left =
element_text(
color="#04a2d0",
size=size,
vjust=vjust,
angle=angle,
margin=margin(
r=margin_l
)
),axis.title.y.right =
element_text(
color="#77230f",
size=size,
vjust=vjust,
angle=angle,
margin=margin(
l=margin_r
)
),axis.ticks.length.y=unit(0,"mm")
)
5.3.2.7 final plot
$finalPlot <- function(){
ggplot4<- 15
size <- 19
size_text <- 1
vjust <- 0
angle <- -103
margin_l <- -84
margin_r $twoSeries_recaled() +
ggplot4$scale_x() +
ggplot4theme(
axis.title.x = element_blank(),
axis.line.y = element_blank(),
axis.ticks.y = element_blank(),
panel.grid.major.y =
element_line(color = "#ececec"),
axis.text.y.left =
element_text(
color = "#04a2d0",
size = size_text
),axis.text.y.right =
element_text(
color = "#77230f",
size = size_text
),axis.title.y.left =
element_text(
color = "#04a2d0",
size = size,
vjust = vjust,
angle = angle,
margin = margin(
r = margin_l
)
),axis.title.y.right =
element_text(
color = "#77230f",
size = size,
vjust = vjust,
angle = angle,
margin = margin(
l = margin_r
)
),axis.ticks.length.y = unit(0, "mm")
)
}$finalPlot() ggplot4
5.4 Color/Fill
5.4.1 Discrete
Set up simulated data:
<- data.frame(
dataSet3 x=seq(
from=lubridate::ymd("2020-01-03"),
to=lubridate::ymd("2020-08-12"),
by="1 day"
)
)<- c("Britain","France","Germany","Italy","Spain")
countries <- c(0.1, 0.2, 0.3, 0.4, 0.5)
slopes for(i in seq_along(slopes)){
<-
dataSet3[[countries[[i]]]] 0 + slopes[[i]]*as.integer(dataSet3$x-dataSet3$x[[1]])
}|>
dataSet3 ::pivot_longer(
tidyrcols="Britain":"Spain",
names_to = "country",
values_to = "y"
-> dataSet3 )
Initiate a base plot:
<- list()
ggplot3 $data <- dataSet3
ggplot3$plot1 <- function(){
ggplot3ggplot()+
geom_line(
data=ggplot3$data,
mapping=aes(
x=x,
y=y,
group=country,
color=country
)
)
}
$plot1() ggplot3
Formulate the plotting process as a function has an advantage of data set substitutability. We can substitute ggplot3$data
by:
$data <- new_data
ggplot3$plot1() ggplot3
This is because function is lazily evaluated which will look for
ggplot3$data
when it is called.The birth place of
ggplot3$plot1
function is global environment. Therefore, any update ofggplot3$data
in global environment before a call ofggplot3$plot1
will always be based on the updated value.
Prepare color scale:
$color$limits <- c("Britain", "France", "Germany", "Italy", "Spain")
ggplot3$color$values <- c("#984152", "#1e80ab", "#2ec1d2", "#af959f", "#e5b865")
ggplot3$color$labels <- c("英", "法", "德", "義", "西") ggplot3
Formulate the scale_color_manual
call as a function
$scale_color_manual <- function()
ggplot3
{= ggplot3$color$limits
limits = ggplot3$color$values
values
# a call to scale_color_manual
scale_color_manual(
limits = limits,
values = values,
breaks = limits,
labels = ggplot3$color$labels
) }
$plot1() +
ggplot3$scale_color_manual() ggplot3
{...}
returns the visible value of the last executed line.
$axis_x_date_monthlyPeriod <- function()
ggplot3
{<- data.frame(
dd x = ggplot3$data$x
)require(dplyr)
%>%
dd arrange(x) %>%
mutate(
year=lubridate::year(x),
month=lubridate::month(x)
%>%
) group_by(year,month) %>%
distinct() %>%
summarise(
day1 = min(x),
midlength = round(length(x)/2,0),
breaks = day1 + lubridate::days(midlength),
labels = lubridate::month(breaks, label=T)
%>% ungroup() -> dx
) <- range(dd$x)
xrange <- {
rug_x c(xrange, dx$day1) |>
unique() |>
sort()
}
list(
geom_rug(
mapping=aes(
x=rug_x
),outside = T
),coord_cartesian(clip="off"),
scale_x_date(
breaks=dx$breaks,
labels = dx$labels
),theme(
axis.ticks.length.x = grid::unit(0,"mm")
)
) }
$plot1() +
ggplot3$scale_color_manual() +
ggplot3$axis_x_date_monthlyPeriod() ggplot3