I can set the line style of the grouped lines through the following code:
scale_linetype_manual(values = c("solid", "dashed", "dashed"))
x <- lm(Sepal.Length ~ Sepal.Width + Species, iris)
ggplot(x, aes(Sepal.Width, Sepal.Length, color = Species, linetype = Species)) +
geom_line() +
scale_color_manual(values = c("black", "red", "blue")) +
scale_linetype_manual(values = c("solid", "dashed", "dashed"))
But not after the rms package. What did I miss?
scale_linetype_manual(values = c("solid", "dashed", "dashed")) did not work in the following code.
require(survival)
require(ggplot2)
require(rms)
n <- 1000
set.seed(731)
age <- 50 + 12*rnorm(n)
label(age) <- "Age"
sex <- factor(sample(c('Male','Female'), n,
rep=TRUE, prob=c(.6, .4)))
cens <- 15*runif(n)
h <- .02*exp(.04*(age-50)+.8*(sex=='Female'))
dt <- -log(runif(n))/h
label(dt) <- 'Follow-up Time'
e <- ifelse(dt <= cens,1,0)
dt <- pmin(dt, cens)
units(dt) <- "Year"
dd <- datadist(age, sex)
options(datadist='dd')
S <- Surv(dt,e)
f <- cph(S ~ rcs(age,4) + sex, x=TRUE, y=TRUE)
cox.zph(f, "rank") # tests of PH
anova(f)
x <- Predict(f, age, sex)
ggplot(x,,aes(age, yhat, linetype=sex)) +
geom_line() +
scale_color_manual(values = c("black", "black")) +
scale_linetype_manual(values = c("solid", "dashed"))
It's because the input to ggplot
is an object of class
"predict" rather than simply a dataframe.
By intercepting the ggplot
layer data, it's possible to update the linetype
and then get the dashed line.
Alternatively, you could convert the predict object to a tibble
and then build the ggplot
in the usual way with geom_ribbon()
etc.
library(survival)
library(tidyverse)
library(rms)
# Data
n <- 1000
set.seed(731)
age <- 50 + 12*rnorm(n)
label(age) <- "Age"
sex <- factor(sample(c('Male','Female'), n,
rep=TRUE, prob=c(.6, .4)))
cens <- 15*runif(n)
h <- .02*exp(.04*(age-50)+.8*(sex=='Female'))
dt <- -log(runif(n))/h
label(dt) <- 'Follow-up Time'
e <- ifelse(dt <= cens,1,0)
dt <- pmin(dt, cens)
units(dt) <- "Year"
dd <- datadist(age, sex)
options(datadist='dd')
S <- Surv(dt,e)
f <- cph(S ~ rcs(age,4) + sex, x=TRUE, y=TRUE)
cox.zph(f, "rank")
anova(f)
x <- Predict(f, age, sex)
# Plotting
class(x) # Special "Predict" class
#> [1] "Predict" "data.frame"
p <- ggplot(x, aes(age, yhat, linetype = sex)) +
scale_linetype_manual(values = c("solid", "dashed"))
p # no dashed line
head(layer_data(p, 1)) # no special linetype in ggplot layer data
#> colour x y PANEL group flipped_aes linewidth linetype alpha
#> 1 #000000 19.71985 -0.05545631 1 1 FALSE 0.5 1 NA
#> 2 #000000 20.00869 -0.06045969 1 1 FALSE 0.5 1 NA
#> 3 #000000 20.29754 -0.06546307 1 1 FALSE 0.5 1 NA
#> 4 #000000 20.58638 -0.07046645 1 1 FALSE 0.5 1 NA
#> 5 #000000 20.87523 -0.07546982 1 1 FALSE 0.5 1 NA
#> 6 #000000 21.16408 -0.08047320 1 1 FALSE 0.5 1 NA
# update the layer based on the group (sex)
p[["layers"]][[1]][["aes_params"]][["linetype"]] <- layer_data(p, 1) |>
mutate(linetype = if_else(group == 1, "solid", "dashed")) |> pull(linetype)
p # now we have the dashed line
# You could also convert to a tibble then build the plot adding `geom_ribbon()` etc. (which may be easier)
x |>
as_tibble() |>
ggplot(aes(age, yhat, linetype = sex)) +
geom_line() +
scale_linetype_manual(values = c("solid", "dashed"))
Created on 2024-04-25 with reprex v2.1.0