Israel as Mask Compliance Case Study

COVID-19 in Motion - How policy directly affects incident rates

Houston Haynes

7 minute read

A Crucible

Having read several articles about Israel’s mask mandate and how that showed marked results that I had to see for myself. It didn’t disappoint. When leveled for cases-per-million the shape of the data is unmistakable.

The data came from Our World In Data and made for ample analysis. That said, there are some data shapes that cause me to raise an eyebrow. However, the chart below is a really stark visual story. I added some plotlines to indicate dates of policy changes (gathered from a wiki page) and the visual story is unmistakable. Not only does the case count per day skyrocket but it also lags the re-issuance of stricter guidelines.

Comparison Countries

I was fairly arbitrary in my selection of countries to compare to Israel’s data. I picked US and UK because the response in general has been so poor from a policy perspective. And as counterpoint I pulled in Canada and Germany who have better national strategies. India and China were chosen for their population size (even when leveled for cases per million I was expecting to see more from their data) and Japan has a pretty well-established mask culture. As you look at death and test rates below the picture continues to develop.

Researchers will talk about the lag time between a change in policy and the shift in incident rates, but seldom will you see a more clear example. And of course the final piece to this mosaic is that the case rate in Israel moves below the UK, US, Germany and Canada as of the latest date (Nov 9) as of this writing.

Deaths per Million

I was shocked to see the deaths per million so high in the UK. I honestly wonder if the US not being a higher number might be about improper/false attribution of cause of death. I’ve read anecdotes about folks in rest homes whose families assert they died from COVID-19 but their COD was listed as some other, more common cause. That said, the trend of the numbers in Israel after the new lockdown policy in mid September shows both the lagging response post-implementation as well as a rate the descends below those of the US and UK.

Tests per Thousand

While the tests per thousand is increasing, it’s not nearly high enough. It’s really interesting to see how Israel’s testing jumped up at the same time that case rate spiked. The drop-off at the end I assume is lag in reporting that will eventually be back-filled, but I’ll go to other sources if this data sub-set flattens out.

Code Review

The majority of this code is formatting the display elements of the chart using the highcharter library. Here I’ll focus on how the data was collected and processed for use in this chart. Not all time series charts are the same and I’m using the “stock” chart type for the windowed slider at the bottom.

# begin setup code chunk

URL <- ""

coviddata <- read.csv(URL)

# end setup code chunk

data <- select(coviddata, date, location, new_cases_smoothed_per_million) %>%
  rename(value = new_cases_smoothed_per_million) %>%
  mutate(value = ifelse(, 0, value)) %>%
  mutate(date = ymd(date))

data.wide <-  pivot_wider(data, names_from = location, values_from = value)

data_xts <- xts(data.wide[,-1], = data.wide$date)

last_updated <- paste("Source:  -  Report Last Updated:",
                        format(Sys.time(), "%a %b %d %Y %X"))

thm <- hc_theme_merge(
  hc_theme(colors = c("#800000", "#102156", "#d4622b",  
                        "#45C0F5", "#AFDC00", "#85DFD0", "purple", "orange"),
           chart = list(backgroundColor = ""),
           title = list(style = list(fontFamily = "Ubuntu")),
           subtitle = list(style = list(fontFamily = "Ubuntu")),
           legend = list(itemStyle = list(fontFamily ='Ubuntu',color ='black'))))

widget <- highchart(type = "stock") %>%
  hc_add_theme(thm) %>%
  hc_title(text = "Global New Cases per Million - Israel as Case Study", align = "center") %>%
    text = "With Comparison to Japan, China, India, Canada, Germany, UK & US", align = "center") %>%
      borderColor = 'rgba(160, 160, 160, 0.3)',
      borderRadius = 8,
      borderWidth = 2) %>%
  hc_credits(enabled = TRUE, 
             text = last_updated, 
             position = list(align = "left", x = 10, y = -5)) %>%
  hc_add_series(data_xts$Israel, type = "line", name = "Israel") %>%
  hc_add_series(data_xts$Japan, type = "line", name = "Japan") %>%
  hc_add_series(data_xts$China, type = "line", name = "China") %>%
  hc_add_series(data_xts$India, type = "line", name = "India") %>%
  hc_add_series(data_xts$Canada, type = "line", name = "Canada") %>%
  hc_add_series(data_xts$Germany, type = "line", name = "Germany") %>%
  hc_add_series(data_xts$`United States`, type = "line", name = "US") %>%
  hc_add_series(data_xts$`United Kingdom`, type = "line", name = "UK") %>%
  hc_tooltip(valueDecimals = 2) %>%
  hc_xAxis(type = "datetime",
    plotLines = list(list(
      label = list(text = "Schools opened"),
      color = "#4D6278",
      width = 3,
      value = datetime_to_timestamp(as.Date('2020-05-03', tz = 'UTC'))
      label = list(text = "Schools shut down"),
      color = "#4D6278",
      width = 3,
      value = datetime_to_timestamp(as.Date('2020-06-01', tz = 'UTC'))
      label = list(text = "New stricter controls announced"),
      color = "#4D6278",
      width = 3,
      value = datetime_to_timestamp(as.Date('2020-07-13', tz = 'UTC'))
      label = list(text = "Loosened 'traffic light' plan"),
      color = "#800000",
      width = 4,
      value = datetime_to_timestamp(as.Date('2020-08-31', tz = 'UTC'))
    plotBands = list(
        label = list(text = "New nationwide
lockdown policy", align = "left"), color = "rgba(100, 0, 0, 0.1)", from = datetime_to_timestamp(as.Date('2020-09-13', tz = 'UTC')), to = datetime_to_timestamp(as.Date(end(data_xts), tz = 'UTC')) ) ) ) %>% hc_legend( enabled = TRUE, align = "right", layout = "proximate", x = 0, y = 0 ) frameWidget(widget, width="100%", height="32rem")

The file from “Our World in Data” is pulled in a single chunk at the top of the R markdown document, and the entire data set is placed in a dataframe that each individual report chunk can process for its own use. You’ll see the creation of an initial data dataframe, which in each case selects on of the dozen or more columns in the original set. Then the wide version of the table is created to split out each country-based time series into its own column. That wide dataframe is then converted to an xts or extended time series dataframe.

Each report is largely the same. The only factors that are changed is the selected metric (new cases/million, new deaths/million, new tests/thousand) and of course the titles. The plotLines and plotBands are largely manually generated - from dates I found in the wikipedia page mentioned above. The one plotBand date that is dynamically set is the end date which always uses the last date of the current report range. Once there’s a change in policy then that will again require some hand-curated edits. Until then the daily reports will continue to ‘stretch’ that last plotBand as the data grows.

Continuing Research

This isn’t the only report I had planned for looking at this data, but given the recent press around Israel’s changes in policy, and the dramatic effect that had on COVID incident rates, I had to see the data for myself. As more data is gathered and more interesting questions are posed to that data, other report types will surely follow.

Faces of COVID-19
The pandemic-related posts on this site are about more than data. Behind every number is a person, a family and a community. As reports are refreshed, new selections will also be chosen at random. To see how this is done, see this sidebar.

Key Value
BuildDateTime 2021-02-24 17:08:05 -0800
LastGitUpdate 2021-02-23 18:58:41 -0800
GitHash 27bc899
CommitComment update to Israel plotBand