/R/diverging_chart.R

https://github.com/thomas-neitmann/ggcharts · R · 212 lines · 90 code · 7 blank · 115 comment · 9 complexity · cb4e8d98977891965c55a0aa91ff55ef MD5 · raw file

  1. #' Diverging Bar Chart
  2. #'
  3. #' Easily create a diverging bar chart
  4. #'
  5. #' @param data Dataset to use for the diverging bar chart
  6. #' @param x \code{character} or \code{factor} column of \code{data}
  7. #' @param y \code{numeric} column of \code{data} representing the bar length
  8. #' @param bar_colors A \code{character} vector of length 2 containing the colors
  9. #' for the positive and negative bars
  10. #' @param text_color \code{character}. The color for the bar annotations
  11. #' @param text_size \code{numeric}. The size of the bar annotation text in pt
  12. #'
  13. #' @return An object of class \code{ggplot}
  14. #'
  15. #' @author Thomas Neitmann
  16. #'
  17. #' @seealso
  18. #' To learn how to further customize this plot have a look at the 'customize' vignette:
  19. #' \code{vignette("customize", package = "ggcharts")}
  20. #'
  21. #' @examples
  22. #' if (requireNamespace("tidyr")) {
  23. #' library(magrittr)
  24. #' data(biomedicalrevenue)
  25. #' biomedicalrevenue %>%
  26. #' dplyr::filter(year > 2016) %>%
  27. #' tidyr::pivot_wider(
  28. #' values_from = revenue,
  29. #' names_from = year,
  30. #' names_prefix = "revenue_"
  31. #' ) %>%
  32. #' dplyr::mutate(diff = revenue_2018 - revenue_2017) %>%
  33. #' diverging_bar_chart(company, diff)
  34. #' }
  35. #'
  36. #' data(mtcars)
  37. #' mtcars_z <- dplyr::transmute(
  38. #' .data = mtcars,
  39. #' model = row.names(mtcars),
  40. #' hpz = scale(hp)
  41. #' )
  42. #'
  43. #' diverging_bar_chart(mtcars_z, model, hpz)
  44. #'
  45. #' ## Change the colors
  46. #' diverging_bar_chart(mtcars_z, model, hpz, bar_color = c("darkgreen", "darkred"))
  47. #'
  48. #' ## Decrease the axis label font size
  49. #' diverging_bar_chart(mtcars_z, model, hpz, text_size = 8)
  50. #'
  51. #' ## Display the axis label text in the same color as the bars
  52. #' diverging_bar_chart(mtcars_z, model, hpz, text_color = c("#1F77B4", "#FF7F0E"))
  53. #'
  54. #' @import ggplot2
  55. #' @importFrom rlang .data
  56. #' @export
  57. #' @export
  58. diverging_bar_chart <- function(data, x, y,
  59. bar_colors = c("#1F77B4", "#FF7F0E"),
  60. text_color = "auto",
  61. text_size = 10) {
  62. x <- rlang::enquo(x)
  63. y <- rlang::enquo(y)
  64. diverging_chart(
  65. data = data,
  66. x = !!x,
  67. y = !!y,
  68. geom = "bar",
  69. colors = bar_colors,
  70. text_color = text_color,
  71. text_size = text_size
  72. )
  73. }
  74. #' Diverging Lollipop Chart
  75. #'
  76. #' Easily create a diverging lollipop chart
  77. #'
  78. #' @param data Dataset to use for the diverging lollipop chart
  79. #' @param x \code{character} or \code{factor} column of \code{data}
  80. #' @param y \code{numeric} column of \code{data} representing the lollipop length
  81. #' @param lollipop_colors A \code{character} vector of length 2 containing the
  82. #' colors for the positive and negative lollipops
  83. #' @param line_size \code{numeric}. Size of the lollipop 'stick'
  84. #' @param point_size \code{numeric}. Size of the lollipop 'head'
  85. #' @param text_color \code{character}. The color for the lollipop annotations
  86. #' @param text_size \code{numeric} The size of the lollipop annotation text in pt
  87. #'
  88. #' @return An object of class \code{ggplot}
  89. #'
  90. #' @author Thomas Neitmann
  91. #'
  92. #' @seealso
  93. #' To learn how to further customize this plot have a look at the 'customize' vignette:
  94. #' \code{vignette("customize", package = "ggcharts")}
  95. #'
  96. #' @examples
  97. #' if (requireNamespace("tidyr")) {
  98. #' library(magrittr)
  99. #' data(biomedicalrevenue)
  100. #' biomedicalrevenue %>%
  101. #' dplyr::filter(year > 2016) %>%
  102. #' tidyr::pivot_wider(
  103. #' values_from = revenue,
  104. #' names_from = year,
  105. #' names_prefix = "revenue_"
  106. #' ) %>%
  107. #' dplyr::mutate(diff = revenue_2018 - revenue_2017) %>%
  108. #' diverging_lollipop_chart(company, diff)
  109. #' }
  110. #'
  111. #' data(mtcars)
  112. #' mtcars_z <- dplyr::transmute(
  113. #' .data = mtcars,
  114. #' model = row.names(mtcars),
  115. #' hpz = scale(hp)
  116. #' )
  117. #'
  118. #' diverging_lollipop_chart(mtcars_z, model, hpz)
  119. #'
  120. #' ## Change the colors
  121. #' diverging_lollipop_chart(mtcars_z, model, hpz, lollipop_colors = c("darkgreen", "darkred"))
  122. #'
  123. #' ## Decrease the axis label font size
  124. #' diverging_lollipop_chart(mtcars_z, model, hpz, text_size = 8)
  125. #'
  126. #' ## Display the axis label text in the same color as the bars
  127. #' diverging_lollipop_chart(mtcars_z, model, hpz, text_color = c("#1F77B4", "#FF7F0E"))
  128. #'
  129. #' @import ggplot2
  130. #' @importFrom rlang .data
  131. #' @export
  132. diverging_lollipop_chart <- function(data, x, y,
  133. lollipop_colors = c("#1F77B4", "#FF7F0E"),
  134. line_size = 0.75, point_size = 3,
  135. text_color = "auto", text_size = 10) {
  136. x <- rlang::enquo(x)
  137. y <- rlang::enquo(y)
  138. diverging_chart(
  139. data = data,
  140. x = !!x,
  141. y = !!y,
  142. geom = "lollipop",
  143. colors = lollipop_colors,
  144. line_size = line_size,
  145. point_size = point_size,
  146. text_color = text_color,
  147. text_size = text_size
  148. )
  149. }
  150. diverging_chart <- function(data, x, y,
  151. geom = c("bar", "lollipop"),
  152. colors = c("#1F77B4", "#FF7F0E"),
  153. line_size = 0.75,
  154. point_size = 3,
  155. text_color = "auto",
  156. text_size = "auto") {
  157. x <- rlang::enquo(x)
  158. y <- rlang::enquo(y)
  159. geom <- match.arg(geom)
  160. if (length(text_color) == 1 && text_color == "auto") {
  161. text_color <- ggcharts_current_theme()$text$colour
  162. }
  163. data <- dplyr::mutate(
  164. .data = data,
  165. !!x := reorder(!!x, !!y),
  166. .color = ifelse(!!y >= 0, colors[1], colors[2])
  167. )
  168. limit <- max(dplyr::pull(data, !!y)) * 1.05
  169. if (length(text_color) == 1) text_color <- rep(text_color, 2)
  170. if (geom == "bar") {
  171. plot <- ggplot(data, aes(!!x, !!y, fill = .data$.color)) +
  172. geom_col() +
  173. scale_fill_identity()
  174. } else {
  175. plot <- ggplot(data, aes(!!x, !!y, color = .data$.color)) +
  176. geom_segment(aes(y = 0, xend = !!x, yend = !!y), size = line_size) +
  177. geom_point(size = point_size) +
  178. scale_color_identity()
  179. }
  180. plot +
  181. coord_flip() +
  182. geom_text(
  183. data = dplyr::filter(data, !!y >= 0),
  184. color = text_color[1],
  185. size = text_size,
  186. aes(label = !!x, y = 0, hjust = "right"),
  187. nudge_y = -limit * .01
  188. ) +
  189. geom_text(
  190. data = dplyr::filter(data, !!y < 0),
  191. color = text_color[2],
  192. size = text_size,
  193. aes(label = !!x, y = 0, hjust = "left"),
  194. nudge_y = limit * .013
  195. ) +
  196. geom_hline(
  197. yintercept = 0,
  198. color = ggcharts_current_theme()$text$colour,
  199. size = .4
  200. ) +
  201. labs(x = NULL) +
  202. ylim(-limit, limit) +
  203. ggcharts_current_theme(grid = "Y") +
  204. guides(y = guide_none())
  205. }