Row

Trend of Total Positive : Total Unique Testing Rate since May (ND)

Trend of Total Positive : Total Unique Testing Rate since May (Cass)

Row

Trend of Daily Positive : Daily Serial Testing Rate w/ 14-day Moving Average (ND)

Trend of Daily Positive : Daily Serial Testing Rate w/ 14-day Moving Average (Cass)

Row

Recovered : Positive (ND)

Recovered : Positive (Cass)

Row

Total # of Unique Tests (ND)

Total # of Unique Tests (Cass)

Row

Daily Testing Momentum Oscillator: Testing Increase/Reduction Compared to Previous Day’s Increase/Reduction (ND)

Daily Testing Momentum Oscillator: Testing Increase/Reduction Compared to Previous Day’s Increase/Reduction (Cass)

Row

Notes

All data from https://health.nd.gov. Daily testing #s are released at 11 am and reference previous day’s tests. Unique testing numbers are for unique tests and do not include repeat tests of an individual previously tested. This is a daily snapshot: any adjustments to the initially published daily numbers the NDDoH may retroactively make will not be reflected here.

There was an issue with the 05/25 and 05/26 numbers in the state-level data, where total positive counts (impossibly) dipped. It’s likely that ND Health made some adjustments to how positives were counted on that date. To ensure better readability, I deleted those two days in the state-wide data column.

Data on 6/20 was not posted in time to be included. The 06/20 numbers in these charts are an average of the 06/19 and 06/21 numbers.

Note from ND Health for June 23 numbers: “Due to a temporary software issue with the Electronic Lab Reporting System, most of the results from June 22 will be delayed. The issue has been resolved and as the system catches up today, the numbers will be reported out on June 24. Thank you for your understanding.”

I added a daily positive:daily # of serial tests chart on 09/02. As more and more people get tested more and more regularly, the unique test values will start to reflect an increasingly shrinking subset of the population, and likely become more erratic. At some point, availability and adoption of routine testing practices will make serial testing rates more useful than unique testing rates.

I changed to recording “Susceptible encounters” (people tested who had not previously been tested positive) for the daily serial testing rate, because the rising number of positive/recovered cases that get re-tested started to artifically skew the daily serial rate upward.

Data from 10/22 - 10/24 are averages, not raw numbers, due to three days of missing data.

NDDoH system was down on 11/10; numbers for that date are averages.

12-08 are averages; no data. Also, removed uniques.

12-25 are averages; no data published.

12-29: added antigen tests to total positives (previously, PCR only).

If you have any questions, please contact me at zpm at zoltanpm dot com

---
title: "ND & Cass County COVID Numbers"
output: 
  flexdashboard::flex_dashboard:
    orientation: rows
    vertical_layout: scroll
    source_code: embed

---

```{r setup, include=FALSE}
library(tidyverse)
library(gdata)
library(plotly)
library(tidyr)
library(zoo)
library(ggrepel)
library(scales)
library(flexdashboard)

data <- read_csv('state_numbers.csv')
data$Date <- as.Date(data$Date)

data_ND <- subset(data, Area=="ND")
data_ND <- data_ND %>% mutate(Total_Diff = (Total.Test-lag(Total.Test))-(lag(Total.Test)-lag(Total.Test, n=2)))
data_ND <- data_ND %>% mutate(Today_Pos = Pos - lag(Pos))
data_ND <- data_ND %>% mutate(Today_Tests = Total.Test - lag(Total.Test))
data_ND <- data_ND %>% mutate(sma = rollmean(Today_Pos/Today_Tests, k=14, fill=NA, align="right"))
data_ND <- data_ND %>% mutate(s_sma = rollmean(Today_Pos/Serial, k=14, fill=NA, align="right"))

data_Cass <- subset(data, Area=="Cass")
data_Cass <- data_Cass %>% mutate(Total_Diff = (Total.Test-lag(Total.Test))-(lag(Total.Test)-lag(Total.Test, n=2)))
data_Cass <- data_Cass %>% mutate(Today_Pos = Pos - lag(Pos))
data_Cass <- data_Cass %>% mutate(Today_Tests = Total.Test - lag(Total.Test))
data_Cass <- data_Cass %>% mutate(sma = rollmean(Today_Pos/Today_Tests, k=14, fill=NA, align="right"))
data_Cass <- data_Cass %>% mutate(s_sma = rollmean(Today_Pos/Serial, k=14, fill=NA, align="right"))


x1 <- ggplot(data_ND, mapping=aes(x=Date, y=Total.Test)) +
  geom_line(color="darkred") +
  geom_point(size=0.5) +
  labs(y="Total Tests: Statewide") +
  theme_minimal() +
  theme(axis.title.x = element_blank()) +
  theme(axis.title.y = element_text(face='bold'))

x2 <- ggplot(data_Cass, mapping=aes(x=Date, y=Total.Test)) +
  xlim(as.Date("2020-04-25"), NA) +
  geom_line(color="darkred") +
  geom_point(size=0.5) +
  labs(y="Total Tests: Cass") +
  theme_minimal() +
  theme(axis.title.x = element_blank()) +
  theme(axis.title.y = element_text(face='bold'))

osc1 <- #data_ND %>% mutate(Color = ifelse(Total_Diff > 0, "darkred", "steelblue")) %>%
  ggplot(data_ND, aes(x=Date, y=Total_Diff)) +
  geom_point(size=0.75) +
  geom_line(color="darkred") + #(aes(color=Color, group=1)) +
  geom_hline(yintercept = 0) +
  scale_y_continuous(labels = function(x) paste0(symnum(x, c(-Inf, 0, Inf), c("", "+")), x)) +
  #geom_text(aes(label = (Total.Test-lag(Total.Test))-(lag(Total.Test)-lag(Total.Test, n=2))), nudge_x = .6) +
  labs(y="+/- Testing vs. Previous Day: Statewide") +
  theme_minimal() +
  theme(axis.title.x = element_blank()) +
  theme(axis.title.y = element_text(face='bold'))

osc2 <- ggplot(data_Cass, aes(x=Date, y=Total_Diff)) +
  xlim(as.Date("2020-04-25"), NA) +
  geom_line(color="darkred") +
  geom_point(size=0.75) +
  geom_hline(yintercept = 0) +
  scale_y_continuous(labels = function(x) paste0(symnum(x, c(-Inf, 0, Inf), c("", "+")), x)) +
  labs(y="+/- Testing vs. Previous Day: Cass") +
  theme_minimal() +
  theme(axis.title.x = element_blank()) +
  theme(axis.title.y = element_text(face='bold'))

y1 <- ggplot(data_ND, mapping=aes(x=Date, y=Pos/Total.Test)) +
  geom_line(color="darkred") +
  geom_point(size=0.5) +
  scale_y_continuous(labels=percent) + 
  labs(y="Total Positive / Total Tests: Statewide") +
  theme_minimal() +
  theme(axis.title.x = element_blank()) +
  theme(axis.title.y = element_text(face='bold'))

y2 <- ggplot(data_Cass, mapping=aes(x=Date, y=Pos/Total.Test)) +
  xlim(as.Date("2020-04-25"), NA) +
  geom_line(color="darkred") +
  geom_point(size=0.5) +
  scale_y_continuous(labels=percent) + 
  labs(y="Total Positive / Total Tests: Cass") +
  theme_minimal() +
  theme(axis.title.x = element_blank()) +
  theme(axis.title.y = element_text(face='bold'))


dy1 <- ggplot(data_ND, mapping=aes(x=Date, y=Today_Pos/Today_Tests)) +
  geom_line(color="darkred") +
  geom_point(size=0.75) +
  geom_line(aes(y=sma)) +
  scale_y_continuous(labels=percent) + 
  labs(y="Daily Positive / Daily Unique Tests: Statewide") +
  theme_minimal() +
  theme(axis.title.x = element_blank()) +
  theme(axis.title.y = element_text(face='bold'))

dy2 <- ggplot(data_Cass, mapping=aes(x=Date, y=Today_Pos/Today_Tests)) +
  xlim(as.Date("2020-04-25"), NA) +
  geom_line(color="darkred") +
  geom_point(size=0.75) +
  geom_line(aes(y=sma)) +
  scale_y_continuous(labels=percent) + 
  labs(y="Daily Positive / Daily Unique Tests: Cass") +
  theme_minimal() +
  theme(axis.title.x = element_blank()) +
  theme(axis.title.y = element_text(face='bold'))

dserial1 <- ggplot(data_ND, mapping=aes(x=Date, y=Today_Pos/Serial)) +
  geom_line(color="darkred") +
  geom_point(size=0.75) +
  geom_line(aes(y=s_sma)) +
  scale_y_continuous(labels=percent) + 
  labs(y="Daily Positive / Daily Serial Tests: Statewide") +
  theme_minimal() +
  theme(axis.title.x = element_blank()) +
  theme(axis.title.y = element_text(face='bold'))

dserial2 <- ggplot(data_Cass, mapping=aes(x=Date, y=Today_Pos/Serial)) +
  xlim(as.Date("2020-04-25"), NA) +
  geom_line(color="darkred") +
  geom_point(size=0.75) +
  geom_line(aes(y=s_sma)) +
  scale_y_continuous(labels=percent) + 
  labs(y="Daily Positive / Daily Serial Tests: Cass") +
  theme_minimal() +
  theme(axis.title.x = element_blank()) +
  theme(axis.title.y = element_text(face='bold'))


z1 <- ggplot(data_ND, mapping=aes(x=Date)) +
  geom_line(aes(y=Pos), color="darkred") +
  geom_point(size=0.5,aes(y=Pos)) +
  annotate("text", x=as.Date("2020-04-25")+0.95, y=2000, label="Positive", color="darkred") +
  #annotate("rect", xmin=as.Date("2020-04-25"), xmax = as.Date("2020-04-25")+1, ymin=890, ymax=970, fill="darkred", alpha=.2) +
  geom_line(aes(y=Rec), color="steelblue") +
  geom_point(size=0.5,aes(y=Rec)) +
  annotate("text", x=as.Date("2020-04-25")+0.95, y=0, label="Recovered", color="steelblue") +
  #annotate("rect", xmin=as.Date("2020-04-25"), xmax = as.Date("2020-04-25")+1, ymin=350, ymax=430, fill="steelblue", alpha=.2) +
  labs(y="Recovered vs. Total Positives: Statewide") +
  #geom_text(label=paste0(round(data_ND$Rec/data_ND$Pos, 2)*100, "%"), y=99+((803+310)/2), nudge_x=.09, size=2.5) +
  theme_minimal() +
  theme(axis.title.x = element_blank()) +
  theme(axis.title.y = element_text(face='bold'))

z2 <- ggplot(data_Cass, mapping=aes(x=Date)) +
  xlim(as.Date("2020-04-25"), NA) +
  geom_line(aes(y=Pos), color="darkred") +
  geom_point(size=0.5,aes(y=Pos)) +
  annotate("text", x=as.Date("2020-04-29")+0.95, y=1000, label="Positive", color="darkred") +
  #annotate("rect", xmin=as.Date("2020-04-29")+0.05, xmax = as.Date("2020-04-29")+1.05, ymin=535, ymax=575, fill="darkred", alpha=.2) +
  geom_line(aes(y=Rec), color="steelblue") +
  geom_point(size=0.5,aes(y=Rec)) +
  annotate("text", x=as.Date("2020-04-29")+0.95, y=0, label="Recovered", color="steelblue") +
  #annotate("rect", xmin=as.Date("2020-04-29")+0.05, xmax = as.Date("2020-04-29")+1.05, ymin=220, ymax=260, fill="steelblue", alpha=.2) +
  labs(y="Recovered vs. Total Positives: Cass") +
  #geom_hline(data = tail(data_Cass, yintercept = (data_Cass$Pos/2)) +
  #geom_text(label=paste0(round(data_Cass$Rec/data_Cass$Pos, 2)*100, "%"), y=((513+210)/2), nudge_x=.09, size=2.5) +
  theme_minimal() +
  theme(axis.title.x = element_blank()) +
  theme(axis.title.y = element_text(face='bold'))
```


Row {data-height=350}
-----------------------------------------------------------------------

### Trend of Total Positive : Total Unique Testing Rate since May (ND)

```{r}
ggplotly(y1)

```

### Trend of Total Positive : Total Unique Testing Rate since May (Cass)
```{r}
ggplotly(y2)
```
















Row {data-height=350}
-----------------------------------------------------------------------

### Trend of Daily Positive : Daily Serial Testing Rate w/ 14-day Moving Average (ND)

```{r}
ggplotly(dserial1)

```

### Trend of Daily Positive : Daily Serial Testing Rate w/ 14-day Moving Average (Cass)
```{r}
ggplotly(dserial2)
```


Row {data-height=350}
-----------------------------------------------------------------------

### Recovered : Positive (ND)

```{r}
ggplotly(z1)
```

### Recovered : Positive (Cass)

```{r}
ggplotly(z2)
```


Row {data-height=350}
-----------------------------------------------------------------------

### Total # of Unique Tests (ND)

```{r}
ggplotly(x1)

```

### Total # of Unique Tests (Cass)
```{r}
ggplotly(x2)

```


Row {data-height=350}
-----------------------------------------------------------------------

### Daily Testing Momentum Oscillator: Testing Increase/Reduction Compared to Previous Day's Increase/Reduction (ND)

```{r}
ggplotly(osc1)

```

### Daily Testing Momentum Oscillator: Testing Increase/Reduction Compared to Previous Day's Increase/Reduction (Cass)
```{r}
ggplotly(osc2)
```


Row {data-height=550}
-----------------------------------------------------------------------

### Notes
All data from https://health.nd.gov. Daily testing #s are released at 11 am and reference previous day's tests. Unique testing numbers are for unique tests and do not include repeat tests of an individual previously tested. This is a daily snapshot: any adjustments to the initially published daily numbers the NDDoH may retroactively make will not be reflected here.

There was an issue with the 05/25 and 05/26 numbers in the state-level data, where total positive counts (impossibly) dipped. It's likely that ND Health made some adjustments to how positives were counted on that date. To ensure better readability, I deleted those two days in the state-wide data column. 

Data on 6/20 was not posted in time to be included. The 06/20 numbers in these charts are an average of the 06/19 and 06/21 numbers.

Note from ND Health for June 23 numbers: "Due to a temporary software issue with the Electronic Lab Reporting System, most of the results from June 22 will be delayed. The issue has been resolved and as the system catches up today, the numbers will be reported out on June 24. Thank you for your understanding."

I added a daily positive:daily # of serial tests chart on 09/02. As more and more people get tested more and more regularly, the unique test values will start to reflect an increasingly shrinking subset of the population, and likely become more erratic. At some point, availability and adoption of routine testing practices will make serial testing rates more useful than unique testing rates.

I changed to recording "Susceptible encounters" (people tested who had not previously been tested positive) for the daily serial testing rate, because the rising number of positive/recovered cases that get re-tested started to artifically skew the daily serial rate upward.

Data from 10/22 - 10/24 are averages, not raw numbers, due to three days of missing data.

NDDoH system was down on 11/10; numbers for that date are averages.

12-08 are averages; no data. Also, removed uniques.

12-25 are averages; no data published.

12-29: added antigen tests to total positives (previously, PCR only).

If you have any questions, please contact me at zpm at zoltanpm dot com