Browse Source

Make app

* Add new datapoint from 2017
* Add source column
* Add UI
* Add Server logic
* Add About page
Petra Lamborn 5 years ago
parent
commit
64cf4ed274
3 changed files with 261 additions and 8 deletions
  1. 4
    3
      P.csv
  2. 5
    4
      V.csv
  3. 252
    1
      app.R

+ 4
- 3
P.csv View File

@@ -1,3 +1,4 @@
1
-Date,         Length
2
-"2016-08-31", 17
3
-"2018-05-08", 26
1
+"Date",       "Length", "Source"
2
+"2016-08-31", 17,       "https://fyi.org.nz/request/4305-transgender-grs-waitlist-progress"
3
+"2017-01-13", 19,       "https://www.stuff.co.nz/national/health/88374973/Gender-reassignment-decades-long-wait-list-horrendous"
4
+"2018-05-08", 26,       "https://fyi.org.nz/request/7586-grs-waitlist-update"

+ 5
- 4
V.csv View File

@@ -1,4 +1,5 @@
1
-Date,         Length
2
-"2015-04-02", 61
3
-"2016-08-31", 71
4
-"2018-05-08", 77
1
+"Date",       "Length", "Source"
2
+"2015-04-02", 61, "https://fyi.org.nz/request/2548-gender-reassignment-surgery-waiting-list-size-and-status"
3
+"2016-08-31", 71, "https://fyi.org.nz/request/4305-transgender-grs-waitlist-progress"
4
+"2017-01-13", 71, "https://www.stuff.co.nz/national/health/88374973/Gender-reassignment-decades-long-wait-list-horrendous"
5
+"2018-05-08", 77, "https://fyi.org.nz/request/7586-grs-waitlist-update"

+ 252
- 1
app.R View File

@@ -1,10 +1,261 @@
1 1
 library(shiny)
2
+library(ggplot2)
3
+library(scales)
4
+library(tidyverse)
5
+library(shinycssloaders)
2 6
 
3
-ui <- fluidPage(
7
+# UI ----
8
+ui <- navbarPage("Gender Reassignment Surgery", collapsible = TRUE, 
9
+                 selected = "About",
10
+  # Vaginoplasty UI ----
11
+  tabPanel("Vaginoplasty — \"MtF\"",
12
+       sidebarPanel(width=3, 
13
+            checkboxInput("vagprojc", label="Project waiting list out to:", 
14
+                          value=FALSE),
15
+            sliderInput("vagprojyears", label=NULL, min=2030, max=2080, 
16
+                        step=1, value=2030, sep=""),
17
+            numericInput("vagin", "Additions to list per year", min=0, 
18
+                         max=NA, step=0.1, value=0),
19
+            numericInput("vagout", "Funded vaginoplasties per year", 
20
+                         min=0.1, max=NA, step=0.1, value=1.5),
21
+            h4("Options"),
22
+            checkboxInput("vagwly", "Show waiting list length in years"),
23
+            checkboxInput("vagminc", "Set graph minimum", value=TRUE),
24
+            conditionalPanel("input.vagminc",
25
+             numericInput("vagmin", label=NULL, value=0)),
26
+            checkboxInput("vagmaxc", "Set graph maximum", value=FALSE),
27
+            conditionalPanel("input.vagmaxc",
28
+             numericInput("vagmax", label=NULL, value=NA))
29
+       ),
30
+       mainPanel(
31
+          tabsetPanel(
32
+            tabPanel("Graph",
33
+              h3("New Zealand vaginoplasty waiting list"),
34
+              plotOutput("vagPlot") %>% withSpinner(type=5)
35
+            ),
36
+            tabPanel("Table",
37
+              h3("Table of projected waiting list values"),
38
+              tableOutput("vagpTable") %>% withSpinner(type=1)
39
+            )
40
+          )
41
+       )
42
+  ),
43
+  # Phalloplasty UI ----
44
+  tabPanel("Phalloplasty — \"FtM\"",
45
+       sidebarPanel(width=3,
46
+            checkboxInput("phalprojc", label="Project waiting list out to:", 
47
+                          value=FALSE),
48
+            sliderInput("phalprojyears", label=NULL, min=2030, max=2080, 
49
+                        step=1, value=2030, sep=""),
50
+            numericInput("phalin", "Additions to list per year", min=0, 
51
+                         max=NA, step=0.1, value=0),
52
+            numericInput("phalout", "Funded phalloplasties per year", 
53
+                         min=0.1, max=NA, step=0.1, value=0.5),
54
+            h4("Options"),
55
+            checkboxInput("phalwly", "Show waiting list length in years"),
56
+            checkboxInput("phalminc", "Set graph minimum", value=TRUE),
57
+            conditionalPanel("input.phalminc",
58
+             numericInput("phalmin", label=NULL, value=0)),
59
+            checkboxInput("phalmaxc", "Set graph maximum", value=FALSE),
60
+            conditionalPanel("input.phalmaxc",
61
+             numericInput("phalmax", label=NULL, value=NA))
62
+       ),
63
+       mainPanel(
64
+          tabsetPanel(
65
+            tabPanel("Graph",
66
+              h3("New Zealand phalloplasty waiting list"),
67
+              plotOutput("phalPlot") %>% withSpinner(type=5)
68
+            ),
69
+            tabPanel("Table",
70
+              h3("Table of projected waiting list values"),
71
+              tableOutput("phalpTable") %>% withSpinner(type=1)
72
+            )
73
+          )
74
+       )
75
+  ),
76
+  # About Page ----
77
+  tabPanel("About",
78
+           p("Since a review in 2003 the New Zealand Ministry of Health",
79
+             "has nominally funded \"MtF\" GRS (i.e. trans women's vaginoplasty) at",
80
+             "a rate of three every two years, and \"FtM\" GRS (trans men's phalloplasty)",
81
+             "at one every two years. The retirement of Peter Walker, who was performing",
82
+             "vaginoplasty for the MoH, in 2014—coupled with the apparent increase",
83
+             "in number of publically out transgender people—has led to astronomical rises to",
84
+             "the waiting lists for both types of surgery."),
85
+           p("Several people have obatained details about the waiting lists from",
86
+             "the Ministry via Official Information Act requests since 2015.",
87
+             "The data obtained is summarised at the bottom of this page;",
88
+             "if you have newer datapoints or others",
89
+             "that have been missed please send them to me on", 
90
+             a(href="https://twitter.com/OleumPetra", "Twitter"), "or",
91
+             a(href="mailto:oleumpetra+blog@gmail.com", "via email"), "."),
92
+           p("This app shows that data visually, but it also projects it",
93
+             "into the future, allowing the rate of people being added",
94
+             "to the list to be changed by the user, along with the",
95
+             "level of government funding. The inadequacy of the present",
96
+             "funding levels can be easily seen, and the size of the increase",
97
+             "that is required estimated."),
98
+           p("Note however that, as this crisis has been ongoing for some",
99
+             "time, many people interested in surgery will not have taken",
100
+             "the time and expense to formally add themselves to the",
101
+             "waiting list. Therefore the true size of the problem",
102
+             "cannot be easily estimated. In addition the Ministry",
103
+             "has contacted a number of people on the list and found that,",
104
+             "given the sheer length of time that has elapsed already,",
105
+             "some do not wish to continue with surgery or have found",
106
+             "some way to self-fund, shortening",
107
+             "the list without actually funding a surgery."),
108
+           hr(),
109
+           h4("Known vaginoplasty waiting list lengths"),
110
+           tableOutput("mtfData") %>% withSpinner(type=1, proxy.height = "100px"),
111
+           h4("Known phalloplasty waiting list lengths"),
112
+           tableOutput("ftmData") %>% withSpinner(type=1, proxy.height = "100px")
113
+  )
4 114
    
5 115
 )
6 116
 
117
+# Server ----
7 118
 server <- function(input, output) {
119
+  # Data logic ----
120
+  pData <- reactive({
121
+    read.csv("P.csv", header=T, stringsAsFactors = FALSE) %>%
122
+      mutate(Date = as.Date(Date))
123
+  })
124
+  
125
+  vData <- reactive({
126
+    read.csv("V.csv", header=T, stringsAsFactors = FALSE) %>%
127
+      mutate(Date = as.Date(Date))
128
+  })
129
+  
130
+  output$mtfData <- renderTable({
131
+    vData() %>% mutate(Date = format(Date, "%d/%m/%Y"),
132
+                       `Length (years)` = Length / 1.5) %>%
133
+      select("Date", "Length", "Length (years)", "Source")
134
+  })
135
+  
136
+  output$ftmData <- renderTable({
137
+    pData() %>% mutate(Date = format(Date, "%d/%m/%Y"),
138
+                       `Length (years)` = Length / 0.5) %>%
139
+      select("Date", "Length", "Length (years)", "Source")
140
+  })
141
+  
142
+  # Projection logic ----
143
+  vagProj <- reactive({
144
+    vd <- vData()
145
+    ld <- vd$Date[nrow(vd)]
146
+    ld.y <- as.numeric(format(ld, "%Y")) # year of last data value
147
+    ld.d <- format(ld, "-%m-%d") # date part of last data value
148
+    lv <- vd$Length[nrow(vd)] # last length value
149
+    yrs <- (ld.y + 1):(input$vagprojyears) # Vector of projection years
150
+    ny <- length(yrs) # Number of projection years
151
+    pc <- rep(input$vagin - input$vagout, ny)
152
+    pv <- cumsum(pc) + lv
153
+    pv <- ifelse(pv < 0, 0, pv)
154
+    dates <- as.Date(paste0(yrs, ld.d))
155
+    data.frame(Date=c(ld, dates), Length = c(lv, pv))
156
+  })
157
+  
158
+  phalProj <- reactive({
159
+    pd <- pData()
160
+    ld <- pd$Date[nrow(pd)]
161
+    ld.y <- as.numeric(format(ld, "%Y")) # year of last data value
162
+    ld.d <- format(ld, "-%m-%d") # date part of last data value
163
+    lv <- pd$Length[nrow(pd)] # last length value
164
+    yrs <- (ld.y + 1):(input$phalprojyears) # Vector of projection years
165
+    ny <- length(yrs) # Number of projection years
166
+    pc <- rep(input$phalin - input$phalout, ny)
167
+    pv <- cumsum(pc) + lv
168
+    pv <- ifelse(pv < 0, 0, pv)
169
+    dates <- as.Date(paste0(yrs, ld.d))
170
+    data.frame(Date=c(ld, dates), Length = c(lv, pv))
171
+  })
172
+  
173
+  # V plot logic ----
174
+  output$vagPlot <- renderPlot({
175
+    vd <- vData()
176
+    showyearsleft <- input$vagwly
177
+    if (showyearsleft) {
178
+      vd <- mutate(vd, Length = Length / 1.5)
179
+    }
180
+    ggplot(vd, aes(Date, Length)) -> v.p
181
+    v.p + geom_line(size = 1.5, na.rm = TRUE) -> v.p
182
+    if (input$vagprojc) {
183
+      vpr <- vagProj()
184
+      if (showyearsleft) {
185
+        vpr <- mutate(vpr, Length = Length / input$vagout)
186
+      }
187
+      v.p + geom_line(data=vpr, aes(Date, Length), 
188
+                      size=1.5, linetype = "dashed",
189
+                      na.rm=TRUE) -> v.p
190
+    }
191
+    if (showyearsleft) {
192
+      v.p + ylab("Waiting list length (years)") -> v.p
193
+    } else {
194
+      v.p + ylab("Waiting list length (people)") -> v.p
195
+    }
196
+    
197
+    v.p + theme_linedraw() -> v.p
198
+    glim <- c(
199
+      ifelse(input$vagminc, input$vagmin, NA),
200
+      ifelse(input$vagmaxc, input$vagmax, NA)
201
+    )
202
+    v.p + scale_y_continuous(limits=glim) -> v.p
203
+    v.p
204
+  })
205
+  
206
+  # P plot logic ----
207
+  output$phalPlot <- renderPlot({
208
+    pd <- pData()
209
+    showyearsleft <- input$phalwly
210
+    if (showyearsleft) {
211
+      pd <- mutate(pd, Length = Length / 0.5)
212
+    }
213
+    ggplot(pd, aes(Date, Length)) -> p.p
214
+    p.p + geom_line(size = 1.5, na.rm=TRUE) -> p.p
215
+    if (input$phalprojc) {
216
+      ppr <- phalProj()
217
+      if (showyearsleft) {
218
+        ppr <- mutate(ppr, Length = Length / input$phalout)
219
+      }
220
+      p.p + geom_line(data=ppr, aes(Date, Length), 
221
+                      size=1.5, linetype = "dashed",
222
+                      na.rm=TRUE) -> p.p
223
+    }
224
+    if (showyearsleft) {
225
+      p.p + ylab("Waiting list length (years)") -> p.p
226
+    } else {
227
+      p.p + ylab("Waiting list length (people)") -> p.p
228
+    }
229
+    
230
+    p.p + theme_linedraw() -> p.p
231
+    glim <- c(
232
+      ifelse(input$phalminc, input$phalmin, NA),
233
+      ifelse(input$phalmaxc, input$phalmax, NA)
234
+    )
235
+    p.p + scale_y_continuous(limits=glim) -> p.p
236
+    p.p
237
+  })
238
+  
239
+  # Projection table logic ----
240
+  output$phalpTable <- renderTable({
241
+    pp <- phalProj() %>% mutate(Date = format(Date, "%Y"))
242
+    names(pp) <- c("Year", "Length")
243
+    if (input$phalwly) {
244
+      pp <- mutate(pp, Length = Length / input$phalout)
245
+      names(pp) <- c("Year", "Length (years)")
246
+    }
247
+    pp
248
+  })
249
+  
250
+  output$vagpTable <- renderTable({
251
+    vp <- vagProj() %>% mutate(Date = format(Date, "%Y"))
252
+    names(vp) <- c("Year", "Length")
253
+    if (input$vagwly) {
254
+      vp <- mutate(vp, Length = Length / input$vagout)
255
+      names(vp) <- c("Year", "Length (years)")
256
+    }
257
+    vp
258
+  })
8 259
 }
9 260
 
10 261
 shinyApp(ui = ui, server = server)