|
181 | 181 | poss_comb <- expand.grid("outcome" = step_outcomes,
|
182 | 182 | "arm" = arm_levels)
|
183 | 183 | missing_row <- dplyr::anti_join(poss_comb,
|
184 |
| - hce_ecdf[, c("outcome", "arm")]) |
| 184 | + hce_ecdf[, c("outcome", "arm")], |
| 185 | + by = c("outcome", "arm")) |
185 | 186 |
|
186 | 187 | # If there are missing rows, fill them in
|
187 | 188 | if (nrow(missing_row) > 0) {
|
|
304 | 305 | `%>%` <- dplyr::`%>%`
|
305 | 306 | n <- dplyr::n
|
306 | 307 |
|
| 308 | + # Extract the active and control arm treatment names |
307 | 309 | actv <- unname(arm_levels["active"])
|
308 | 310 | ctrl <- unname(arm_levels["control"])
|
309 | 311 |
|
| 312 | + # Retrieve hce data for the last outcome as well as the x-axis position |
| 313 | + # to start from |
310 | 314 | binary_data <- hce_dat[hce_dat$outcome == last_outcome, ]
|
311 | 315 | start_binary_endpoint <- meta[meta$outcome == last_outcome, ]$startx
|
312 | 316 |
|
| 317 | + # Get the y-values that the step outcomes ended on for both arms |
313 | 318 | actv_y <- ecdf_mod$meta[
|
314 | 319 | ecdf_mod$meta$arm == actv &
|
315 | 320 | ecdf_mod$meta$outcome == utils::tail(step_outcomes, 1),
|
|
319 | 324 | ecdf_mod$meta$outcome == utils::tail(step_outcomes, 1),
|
320 | 325 | ]$ecdf_end
|
321 | 326 |
|
| 327 | + # Calculate difference of proportion statistics for each arm (estimate |
| 328 | + # and lower confidence interval boundary) using prop.test |
| 329 | + # Note: we are using percentages rather than proportions (*100) |
322 | 330 | binary_meta <- binary_data %>%
|
323 | 331 | dplyr::group_by(arm) %>%
|
324 | 332 | dplyr::summarise(n = n(),
|
325 |
| - average = base::mean(value, na.rm = TRUE), |
326 |
| - conf_int = 1.96 * sqrt((average * (1 - average)) / n)) %>% |
| 333 | + x = base::sum(value, na.rm = TRUE), |
| 334 | + average = 100 * |
| 335 | + as.numeric(stats::prop.test(x, n)$estimate), |
| 336 | + se = abs(average - (100 * |
| 337 | + as.numeric(stats::prop.test(x, n)$conf.int)[1]))) %>% |
327 | 338 | dplyr::ungroup()
|
328 | 339 |
|
329 |
| - x_radius <- (100 - start_binary_endpoint) * min(binary_meta$conf_int) |
330 |
| - y_height <- min(c(0.4 * abs(actv_y - ctrl_y), 0.8 * x_radius)) |
| 340 | + # To create ellipsis shape and avoid overlapping between both of them, |
| 341 | + # set the height to 80% of the SE (minimum scaled in x-axis or y-axis range) |
| 342 | + width <- (100 - start_binary_endpoint) * min(binary_meta$se) / 100 |
| 343 | + y_range <- (max(actv_y, ctrl_y) + 10) * min(binary_meta$se) / 100 |
| 344 | + y_height <- min(c(0.4 * abs(actv_y - ctrl_y), 0.8 * min(width, y_range))) |
331 | 345 |
|
| 346 | + # Create ellipsis centered around proportion estimate (x0) as well as |
| 347 | + # y-value that the step outcomes ended on for each arm, |
| 348 | + # with the standard error as width and the height as calculated above |
332 | 349 | actv_point <-
|
333 | 350 | .create_ellipsis_points(unlist(binary_meta[binary_meta$arm == actv,
|
334 | 351 | "average"]),
|
335 | 352 | actv_y,
|
336 | 353 | unlist(binary_meta[binary_meta$arm == actv,
|
337 |
| - "conf_int"]), |
| 354 | + "se"]), |
338 | 355 | y_height)
|
339 |
| - |
340 | 356 | ctrl_point <-
|
341 | 357 | .create_ellipsis_points(unlist(binary_meta[binary_meta$arm == ctrl,
|
342 | 358 | "average"]),
|
343 | 359 | ctrl_y,
|
344 | 360 | unlist(binary_meta[binary_meta$arm == ctrl,
|
345 |
| - "conf_int"]), |
| 361 | + "se"]), |
346 | 362 | y_height)
|
347 | 363 |
|
348 | 364 | binary_data <- rbind(data.frame("outcome" = last_outcome,
|
|
357 | 373 | binary_data$x,
|
358 | 374 | start_binary_endpoint,
|
359 | 375 | 0,
|
360 |
| - 1 |
| 376 | + 100 |
361 | 377 | )
|
362 | 378 |
|
363 | 379 | binary_meta$average <- .to_rangeab(
|
364 | 380 | binary_meta$average,
|
365 | 381 | start_binary_endpoint,
|
366 | 382 | 0,
|
367 |
| - 1 |
| 383 | + 100 |
368 | 384 | )
|
369 | 385 |
|
370 | 386 | binary_meta$y <- 0
|
|
377 | 393 | ))
|
378 | 394 | }
|
379 | 395 |
|
| 396 | +# Create ellipsis centered around point (x0,y0), |
| 397 | +# with range (x0+a,y0+b) |
380 | 398 | .create_ellipsis_points <- function(x0, y0, a, b) {
|
381 | 399 |
|
| 400 | + # First create equally spaced points on a unit |
| 401 | + # circle (with x-coordinates cos_p and y-coordinates |
| 402 | + # sin_p), ranging from -1 to 1 |
382 | 403 | points <- seq(0, 2 * pi, length.out = 361)
|
383 | 404 | cos_p <- cos(points)
|
384 | 405 | sin_p <- sin(points)
|
| 406 | + # Change the shape by changing the x-axis range (to 2*a) |
| 407 | + # and y axis range (to 2*b) |
385 | 408 | x_tmp <- abs(cos_p) * a * sign(cos_p)
|
386 | 409 | y_tmp <- abs(sin_p) * b * sign(sin_p)
|
| 410 | + # Move x and y values to be centered around x0 and y0 |
387 | 411 | edata <- data.frame(x = x0 + x_tmp, y = y0 + y_tmp)
|
388 | 412 |
|
389 | 413 | return(edata)
|
|
0 commit comments