---
title: "Random slopes"
author: "James Thorson"
output: rmarkdown::html_vignette
#output: rmarkdown::pdf_document
bibliography: 'dsem_vignettes.bib'
vignette: >
  %\VignetteIndexEntry{Random slopes}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE, warning=FALSE, message=FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
start_time = Sys.time()
# Install locally
#  devtools::install_local( R'(C:\Users\James.Thorson\Desktop\Git\dsem)', force=TRUE )
# Build
#  setwd(R'(C:\Users\James.Thorson\Desktop\Git\dsem)'); devtools::build_rmd("vignettes/spatial_diffusion.Rmd")
```

## Random slopes models

`dsem` can be specified to estimate variation over time in a slope parameter that measures the impact of one variable on another.  

To show this, we predict sea surface temperature from Departure Bay based upon the Pacific Decadal Oscillation: 

```{r simulate, echo=TRUE, message=FALSE}
library(dsem)

# Load data
data(pdo_departure_bay)

# Format
tsdata = ts(data.frame(
  Temp = pdo_departure_bay[,2],
  PDO = pdo_departure_bay[,3],
  slope = NA
), start = 1914 )
```

We first fit these data using a stationary slope parameter:

```{r fit_constant, echo=TRUE, message=FALSE}
# Model
sem = "
  PDO -> Temp, 0, slope
  PDO -> PDO, 1, ar_PDO
  Temp -> Temp, 1, ar_Temp
"

# Fit
fit0 = dsem(
  tsdata = tsdata[,1:2],
  sem = sem,
  estimate_mu = colnames(tsdata)[1:2],
  estimate_delta0 = FALSE,
  control = dsem_control(
    quiet = TRUE,
    use_REML = FALSE
  )
)
```

We then re-fit while estimating the slope parameter as a model variable that follows a first-order autoregressive process:

```{r fit_varying, echo=TRUE, message=FALSE}
# Model
sem = "
  PDO -> Temp, 0, slope
  slope -> slope, 1, ar_slope
  PDO -> PDO, 1, ar_PDO
  Temp -> Temp, 1, ar_Temp
"

# Fit
fit = dsem(
  tsdata = tsdata,
  sem = sem,
  estimate_mu = colnames(tsdata),
  estimate_delta0 = FALSE,
  control = dsem_control(
    quiet = TRUE,
    use_REML = FALSE,
    gmrf_parameterization = "full"
  )
)
```

We then plot the predicted state-variables:
```{r plot_states, echo=TRUE, message=FALSE}
# get estimates and SEs for first model
df = expand.grid( year = time(tsdata), var = colnames(tsdata))
df$est = as.vector(as.list(fit$sdrep, what = "Estimate", report = TRUE)$z_tj)
df$se = as.vector(as.list(fit$sdrep, what = "Std. Error", report = TRUE)$z_tj)
df$obs = as.vector(tsdata)

# get estimates and SEs for second model
df0 = expand.grid( year = time(tsdata), var = "constant_slope" )
df0$est =  subset( summary(fit0), path == "PDO -> Temp" )$Estimate
df0$se =  subset( summary(fit0), path == "PDO -> Temp" )$Std_Error
df0$obs = NA

# Combine
df = rbind( df, df0 )
df$var = factor( df$var, levels = c("PDO","Temp","slope","constant_slope") )

# Plot
library(ggplot2)
ggplot(df) +
  geom_line( aes( x=year, y = est) ) +
  geom_point( aes( x=year, y = obs) ) +
  geom_ribbon( aes( x = year, ymin = est - 1.96*se, ymax = est + 1.96*se), alpha = 0.4 ) +
  facet_grid( vars(var), scales = "free_y", labeller =
              labeller(var = c(PDO = "PDO", Temp = "Temperature (C)", slope = "slope (varying)", constant_slope = "slope (constant)")) ) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "black") +
  labs(x = "Year", y = "Observation / Estimate")
```

And can also visualize the estimated graph
```{r plot_graph, echo=TRUE, message=FALSE}
library(igraph)
library(ggraph)

g = make_empty_graph(8)
V(g)$name = c("P[t]", "T[t]", "z[t]", "b[t]", "P[t+1]", "T[t+1]", "z[t+1]", "b[t+1]")
V(g)$shape = c( "square","square","diamond","circle", "square","square","diamond","circle" )
V(g)$label = c("P[t]", "T[t]", "", "beta[t]", "P[t+1]", "T[t+1]", "", "beta[t+1]")

#
g <- add_edges(g, c("P[t]", "T[t]"), attr = list(label = "", type = "solid", col = "black"))
g <- add_edges(g, c("P[t+1]", "T[t+1]"), attr = list(label = "", type = "solid", col = "black"))
g <- add_edges(g, c("b[t]", "z[t]"), attr = list(label = "", type = "solid", col = "black"))
g <- add_edges(g, c("b[t+1]", "z[t+1]"), attr = list(label = "", type = "solid", col = "black"))
# ARs
val = paste0( round(subset(summary(fit),path == "slope -> slope")$Estimate,2), " (", round(subset(summary(fit),path == "slope -> slope")$Std_Error,2),")")
g <- add_edges(g, c("b[t]", "b[t+1]"), attr = list(label = val, type = "dotted", col = "grey"))
val = paste0( round(subset(summary(fit),path == "PDO -> PDO")$Estimate,2), " (", round(subset(summary(fit),path == "PDO -> PDO")$Std_Error,2),")")
g <- add_edges(g, c("P[t]", "P[t+1]"), attr = list(label = val, type = "dotted", col = "grey"))
val = paste0( round(subset(summary(fit),path == "Temp -> Temp")$Estimate,2), " (", round(subset(summary(fit),path == "Temp -> Temp")$Std_Error,2),")")
g <- add_edges(g, c("T[t]", "T[t+1]"), attr = list(label = val, type = "dotted", col = "grey"))

loc_nodes = rbind(
  c(x = 1, y = 3),
  c(1,0),
  c(1,1),
  c(0,2),
  c(4,3),
  c(4,0),
  c(4,1),
  c(3,2)
)

layout = create_layout( g, loc_nodes[,c("x","y")] )
ggraph(layout) +
  geom_edge_link2(
    arrow = arrow(length = unit(2, "mm")),
    end_cap = ggraph::circle(7, 'mm'),
    start_cap = ggraph::circle(0, 'mm'),
    aes( label = label, linetype = type, col = col ),  # , edge_width = ifelse(type == "dotted", 0.8, 0.8)
    vjust = -0.2,
    hjust = 0.4,
    label_parse = TRUE
  ) +
  geom_node_point(
    aes(shape = shape, size = ifelse(shape == "diamond",8,15) ),
    #size = 15,
    stroke = 1.2,
    color = "black",
    fill = "white"
  ) +
  geom_node_label(
    fill = "white",
    lwd = 0,
    aes(label = label),
    parse = TRUE
  ) +
  theme(panel.background = element_rect(fill = NA, color = NA)) +
  coord_cartesian( xlim = c(-0.5, 4.5), ylim = c(-0.5, 3.5) )  +
  scale_shape_manual(values = c("circle" = 21, "square" = 22, "diamond" = 23), guide = "none") +  # ?scale_shape
  scale_edge_linetype_manual(values = c("solid" = "solid", "dotted" = "solid"), guide = "none") +
  scale_edge_colour_manual(values = c("black" = "black", "grey" = "black"), guide = "none") +
  scale_size( range = c(6,15), guide = "none" )
```



```{r, include = FALSE, warning=FALSE, message=FALSE}
run_time = Sys.time() - start_time
```
Runtime for this vignette: `r paste( round(unclass(run_time),2), attr(run_time, "units") )`

