| Marc Kupietz | a6e4ee6 | 2021-03-05 09:00:15 +0100 | [diff] [blame] | 1 | #' Misc functions |
| 2 | #' |
| 3 | #' @name misc-functions |
| 4 | NULL |
| 5 | #' NULL |
| Marc Kupietz | bb7d232 | 2019-10-06 21:42:34 +0200 | [diff] [blame] | 6 | |
| 7 | #' Convert corpus frequency table to instances per million. |
| 8 | #' |
| 9 | #' Convenience function for converting frequency tables to instances per |
| 10 | #' million. |
| 11 | #' |
| Marc Kupietz | 67edcb5 | 2021-09-20 21:54:24 +0200 | [diff] [blame] | 12 | #' Given a table with columns `f`, `conf.low`, and `conf.high`, `ipm` ads a `column ipm` |
| 13 | #' und multiplies conf.low and `conf.high` with 10^6. |
| Marc Kupietz | bb7d232 | 2019-10-06 21:42:34 +0200 | [diff] [blame] | 14 | #' |
| Marc Kupietz | 67edcb5 | 2021-09-20 21:54:24 +0200 | [diff] [blame] | 15 | #' @param df table returned from [frequencyQuery()] |
| Marc Kupietz | bb7d232 | 2019-10-06 21:42:34 +0200 | [diff] [blame] | 16 | #' |
| Marc Kupietz | 67edcb5 | 2021-09-20 21:54:24 +0200 | [diff] [blame] | 17 | #' @return original table with additional column `ipm` and converted columns `conf.low` and `conf.high` |
| Marc Kupietz | bb7d232 | 2019-10-06 21:42:34 +0200 | [diff] [blame] | 18 | #' @export |
| 19 | #' |
| Marc Kupietz | a6e4ee6 | 2021-03-05 09:00:15 +0100 | [diff] [blame] | 20 | #' @rdname misc-functions |
| Marc Kupietz | bb7d232 | 2019-10-06 21:42:34 +0200 | [diff] [blame] | 21 | #' @importFrom dplyr .data |
| 22 | #' |
| 23 | #' @examples |
| Marc Kupietz | 6ae7605 | 2021-09-21 10:34:00 +0200 | [diff] [blame] | 24 | #' \dontrun{ |
| 25 | #' |
| Marc Kupietz | 617266d | 2025-02-27 10:43:07 +0100 | [diff] [blame] | 26 | #' KorAPConnection() %>% frequencyQuery("Test", paste0("pubDate in ", 2000:2002)) %>% ipm() |
| Marc Kupietz | 05b2277 | 2020-02-18 21:58:42 +0100 | [diff] [blame] | 27 | #' } |
| Marc Kupietz | bb7d232 | 2019-10-06 21:42:34 +0200 | [diff] [blame] | 28 | ipm <- function(df) { |
| 29 | df %>% |
| 30 | mutate(ipm = .data$f * 10^6, conf.low = .data$conf.low * 10^6, conf.high = .data$conf.high * 10^6) |
| 31 | } |
| 32 | |
| Marc Kupietz | 23daf5b | 2019-11-27 10:28:07 +0100 | [diff] [blame] | 33 | #' Convert corpus frequency table of alternatives to percent |
| 34 | #' |
| 35 | #' Convenience function for converting frequency tables of alternative variants |
| Marc Kupietz | 67edcb5 | 2021-09-20 21:54:24 +0200 | [diff] [blame] | 36 | #' (generated with `as.alternatives=TRUE`) to percent. |
| Marc Kupietz | 23daf5b | 2019-11-27 10:28:07 +0100 | [diff] [blame] | 37 | #' |
| Marc Kupietz | 67edcb5 | 2021-09-20 21:54:24 +0200 | [diff] [blame] | 38 | #' @param df table returned from [frequencyQuery()] |
| Marc Kupietz | 23daf5b | 2019-11-27 10:28:07 +0100 | [diff] [blame] | 39 | #' |
| Marc Kupietz | 67edcb5 | 2021-09-20 21:54:24 +0200 | [diff] [blame] | 40 | #' @return original table with converted columns `f`, `conf.low` and `conf.high` |
| Marc Kupietz | 23daf5b | 2019-11-27 10:28:07 +0100 | [diff] [blame] | 41 | #' @export |
| 42 | #' |
| 43 | #' @importFrom dplyr .data |
| 44 | #' |
| Marc Kupietz | a6e4ee6 | 2021-03-05 09:00:15 +0100 | [diff] [blame] | 45 | #' @rdname misc-functions |
| Marc Kupietz | 23daf5b | 2019-11-27 10:28:07 +0100 | [diff] [blame] | 46 | #' @examples |
| Marc Kupietz | 6ae7605 | 2021-09-21 10:34:00 +0200 | [diff] [blame] | 47 | #' \dontrun{ |
| 48 | #' |
| Marc Kupietz | 617266d | 2025-02-27 10:43:07 +0100 | [diff] [blame] | 49 | #' KorAPConnection() %>% |
| Marc Kupietz | 23daf5b | 2019-11-27 10:28:07 +0100 | [diff] [blame] | 50 | #' frequencyQuery(c("Tollpatsch", "Tolpatsch"), |
| 51 | #' vc=paste0("pubDate in ", 2000:2002), |
| 52 | #' as.alternatives = TRUE) %>% |
| 53 | #' percent() |
| Marc Kupietz | 05b2277 | 2020-02-18 21:58:42 +0100 | [diff] [blame] | 54 | #' } |
| Marc Kupietz | 23daf5b | 2019-11-27 10:28:07 +0100 | [diff] [blame] | 55 | percent <- function(df) { |
| 56 | df %>% |
| 57 | mutate(f = .data$f * 10^2, conf.low = .data$conf.low * 10^2, conf.high = .data$conf.high * 10^2) |
| 58 | } |
| 59 | |
| Marc Kupietz | ef5b7c1 | 2026-09-01 07:24:43 +0200 | [diff] [blame^] | 60 | #' Number of characters that all given strings share as a prefix |
| 61 | #' |
| 62 | #' Replaces `PTXQC::lcpCount()`, to avoid depending on PTXQC for two small |
| 63 | #' string functions. The length is determined by binary search over vectorized |
| 64 | #' [startsWith()] calls, which needs `log2(n)` instead of `n` comparisons for a |
| 65 | #' common prefix of `n` characters. |
| 66 | #' |
| 67 | #' As in `PTXQC::lcpCount()`, a single string is its own prefix, and an empty |
| 68 | #' vector has a common prefix of length 0. |
| 69 | #' |
| 70 | #' @param strings vector of strings |
| 71 | #' @return number of characters common to the beginning of all `strings` |
| 72 | #' @noRd |
| 73 | longestCommonPrefixLength <- function(strings) { |
| 74 | strings <- as.character(strings) |
| 75 | if (length(strings) == 0) { |
| 76 | return(0L) |
| 77 | } |
| 78 | if (length(strings) == 1) { |
| 79 | return(nchar(strings[1])) |
| 80 | } |
| 81 | |
| 82 | low <- 0L |
| 83 | high <- min(nchar(strings)) |
| 84 | while (low < high) { |
| 85 | middle <- (low + high + 1L) %/% 2L |
| 86 | # isTRUE keeps NAs from breaking the condition, as in PTXQC, where they |
| 87 | # make the character comparison fail and thus end the common prefix |
| 88 | if (isTRUE(all(startsWith(strings, substr(strings[1], 1L, middle))))) { |
| 89 | low <- middle |
| 90 | } else { |
| 91 | high <- middle - 1L |
| 92 | } |
| 93 | } |
| 94 | low |
| 95 | } |
| 96 | |
| 97 | #' Number of characters that all given strings share as a suffix |
| 98 | #' |
| 99 | #' Replaces `PTXQC::lcsCount()`, which reverses every string character by |
| 100 | #' character before looking for the common prefix. Works like |
| 101 | #' `longestCommonPrefixLength()`, but anchored at the end of the strings. |
| 102 | #' |
| 103 | #' @param strings vector of strings |
| 104 | #' @return number of characters common to the end of all `strings` |
| 105 | #' @noRd |
| 106 | longestCommonSuffixLength <- function(strings) { |
| 107 | strings <- as.character(strings) |
| 108 | if (length(strings) == 0) { |
| 109 | return(0L) |
| 110 | } |
| 111 | if (length(strings) == 1) { |
| 112 | return(nchar(strings[1])) |
| 113 | } |
| 114 | |
| 115 | first <- strings[1] |
| 116 | firstLength <- nchar(first) |
| 117 | low <- 0L |
| 118 | high <- min(nchar(strings)) |
| 119 | while (low < high) { |
| 120 | middle <- (low + high + 1L) %/% 2L |
| 121 | if (isTRUE(all(endsWith(strings, substr(first, firstLength - middle + 1L, firstLength))))) { |
| 122 | low <- middle |
| 123 | } else { |
| 124 | high <- middle - 1L |
| 125 | } |
| 126 | } |
| 127 | low |
| 128 | } |
| 129 | |
| Marc Kupietz | 95240e9 | 2019-11-27 18:19:04 +0100 | [diff] [blame] | 130 | #' Convert query or vc strings to plot labels |
| 131 | #' |
| 132 | #' Converts a vector of query or vc strings to typically appropriate legend labels |
| 133 | #' by clipping off prefixes and suffixes that are common to all query strings. |
| 134 | #' |
| 135 | #' @param data string or vector of query or vc definition strings |
| Marc Kupietz | 62d29a1 | 2020-01-18 12:38:36 +0100 | [diff] [blame] | 136 | #' @param pubDateOnly discard all but the publication date |
| 137 | #' @param excludePubDate discard publication date constraints |
| Marc Kupietz | 95240e9 | 2019-11-27 18:19:04 +0100 | [diff] [blame] | 138 | #' @return string or vector of strings with clipped off common prefixes and suffixes |
| 139 | #' |
| Marc Kupietz | a6e4ee6 | 2021-03-05 09:00:15 +0100 | [diff] [blame] | 140 | #' @rdname misc-functions |
| 141 | #' |
| Marc Kupietz | 95240e9 | 2019-11-27 18:19:04 +0100 | [diff] [blame] | 142 | #' @examples |
| 143 | #' queryStringToLabel(paste("textType = /Zeit.*/ & pubDate in", c(2010:2019))) |
| 144 | #' queryStringToLabel(c("[marmot/m=mood:subj]", "[marmot/m=mood:ind]")) |
| 145 | #' queryStringToLabel(c("wegen dem [tt/p=NN]", "wegen des [tt/p=NN]")) |
| 146 | #' |
| Marc Kupietz | 95240e9 | 2019-11-27 18:19:04 +0100 | [diff] [blame] | 147 | #' @export |
| Marc Kupietz | cf1771d | 2020-03-04 16:03:04 +0100 | [diff] [blame] | 148 | queryStringToLabel <- function(data, pubDateOnly = FALSE, excludePubDate = FALSE) { |
| Marc Kupietz | 62d29a1 | 2020-01-18 12:38:36 +0100 | [diff] [blame] | 149 | if (pubDateOnly) { |
| Marc Kupietz | 7aa4f19 | 2021-03-05 10:51:24 +0100 | [diff] [blame] | 150 | data <-substring(data, regexpr("(pub|creation)Date", data)+7) |
| Marc Kupietz | 62d29a1 | 2020-01-18 12:38:36 +0100 | [diff] [blame] | 151 | } else if(excludePubDate) { |
| Marc Kupietz | 7aa4f19 | 2021-03-05 10:51:24 +0100 | [diff] [blame] | 152 | data <-substring(data, 1, regexpr("(pub|creation)Date", data)) |
| Marc Kupietz | 62d29a1 | 2020-01-18 12:38:36 +0100 | [diff] [blame] | 153 | } |
| Marc Kupietz | ef5b7c1 | 2026-09-01 07:24:43 +0200 | [diff] [blame^] | 154 | leftCommon = longestCommonPrefixLength(data) |
| Marc Kupietz | 62d29a1 | 2020-01-18 12:38:36 +0100 | [diff] [blame] | 155 | while (leftCommon > 0 && grepl("[[:alnum:]/=.*!]", substring(data[1], leftCommon, leftCommon))) { |
| Marc Kupietz | 95240e9 | 2019-11-27 18:19:04 +0100 | [diff] [blame] | 156 | leftCommon <- leftCommon - 1 |
| 157 | } |
| Marc Kupietz | ef5b7c1 | 2026-09-01 07:24:43 +0200 | [diff] [blame^] | 158 | rightCommon = longestCommonSuffixLength(data) |
| Marc Kupietz | 62d29a1 | 2020-01-18 12:38:36 +0100 | [diff] [blame] | 159 | while (rightCommon > 0 && grepl("[[:alnum:]/=.*!]", substring(data[1], 1+nchar(data[1]) - rightCommon, 1+nchar(data[1]) - rightCommon))) { |
| Marc Kupietz | 95240e9 | 2019-11-27 18:19:04 +0100 | [diff] [blame] | 160 | rightCommon <- rightCommon - 1 |
| 161 | } |
| 162 | substring(data, leftCommon + 1, nchar(data) - rightCommon) |
| 163 | } |
| 164 | |
| Marc Kupietz | bb7d232 | 2019-10-06 21:42:34 +0200 | [diff] [blame] | 165 | |
| Marc Kupietz | 865760f | 2019-10-07 19:29:44 +0200 | [diff] [blame] | 166 | ## Mute notes: "Undefined global functions or variables:" |
| 167 | globalVariables(c("conf.high", "conf.low", "onRender", "webUIRequestUrl")) |
| 168 | |
| 169 | |
| 170 | #' Experimental: Plot frequency by year graphs with confidence intervals |
| Marc Kupietz | d68f971 | 2019-10-06 21:48:00 +0200 | [diff] [blame] | 171 | #' |
| Marc Kupietz | 865760f | 2019-10-07 19:29:44 +0200 | [diff] [blame] | 172 | #' Experimental convenience function for plotting typical frequency by year graphs with confidence intervals using ggplot2. |
| Marc Kupietz | 67edcb5 | 2021-09-20 21:54:24 +0200 | [diff] [blame] | 173 | #' **Warning:** This function may be moved to a new package. |
| Marc Kupietz | 865760f | 2019-10-07 19:29:44 +0200 | [diff] [blame] | 174 | #' |
| 175 | #' @param mapping Set of aesthetic mappings created by aes() or aes_(). If specified and inherit.aes = TRUE (the default), it is combined with the default mapping at the top level of the plot. You must supply mapping if there is no plot mapping. |
| 176 | #' @param ... Other arguments passed to geom_ribbon, geom_line, and geom_click_point. |
| Marc Kupietz | d68f971 | 2019-10-06 21:48:00 +0200 | [diff] [blame] | 177 | #' |
| Marc Kupietz | a6e4ee6 | 2021-03-05 09:00:15 +0100 | [diff] [blame] | 178 | #' @rdname misc-functions |
| 179 | #' |
| Marc Kupietz | d68f971 | 2019-10-06 21:48:00 +0200 | [diff] [blame] | 180 | #' @examples |
| Marc Kupietz | 548ac35 | 2023-04-18 17:38:37 +0200 | [diff] [blame] | 181 | #' \dontrun{ |
| Marc Kupietz | d68f971 | 2019-10-06 21:48:00 +0200 | [diff] [blame] | 182 | #' library(ggplot2) |
| Marc Kupietz | 617266d | 2025-02-27 10:43:07 +0100 | [diff] [blame] | 183 | #' kco <- KorAPConnection(verbose=TRUE) |
| Marc Kupietz | 6ae7605 | 2021-09-21 10:34:00 +0200 | [diff] [blame] | 184 | #' |
| Marc Kupietz | d68f971 | 2019-10-06 21:48:00 +0200 | [diff] [blame] | 185 | #' expand_grid(condition = c("textDomain = /Wirtschaft.*/", "textDomain != /Wirtschaft.*/"), |
| Marc Kupietz | 2fbac3d | 2020-01-18 11:01:21 +0100 | [diff] [blame] | 186 | #' year = (2005:2011)) %>% |
| Marc Kupietz | d68f971 | 2019-10-06 21:48:00 +0200 | [diff] [blame] | 187 | #' cbind(frequencyQuery(kco, "[tt/l=Heuschrecke]", |
| 188 | #' paste0(.$condition," & pubDate in ", .$year))) %>% |
| 189 | #' ipm() %>% |
| Marc Kupietz | 865760f | 2019-10-07 19:29:44 +0200 | [diff] [blame] | 190 | #' ggplot(aes(year, ipm, fill = condition, color = condition)) + |
| Marc Kupietz | d68f971 | 2019-10-06 21:48:00 +0200 | [diff] [blame] | 191 | #' geom_freq_by_year_ci() |
| Marc Kupietz | 05b2277 | 2020-02-18 21:58:42 +0100 | [diff] [blame] | 192 | #' } |
| Marc Kupietz | 865760f | 2019-10-07 19:29:44 +0200 | [diff] [blame] | 193 | #' @importFrom ggplot2 ggplot aes geom_ribbon geom_line geom_point theme element_text scale_x_continuous |
| Marc Kupietz | d68f971 | 2019-10-06 21:48:00 +0200 | [diff] [blame] | 194 | #' |
| 195 | #' @export |
| Marc Kupietz | 865760f | 2019-10-07 19:29:44 +0200 | [diff] [blame] | 196 | geom_freq_by_year_ci <- function(mapping = aes(ymin=conf.low, ymax=conf.high), ...) { |
| Marc Kupietz | d68f971 | 2019-10-06 21:48:00 +0200 | [diff] [blame] | 197 | list( |
| Marc Kupietz | 865760f | 2019-10-07 19:29:44 +0200 | [diff] [blame] | 198 | geom_ribbon(mapping, |
| 199 | alpha = .3, linetype = 0, show.legend = FALSE, ...), |
| 200 | geom_line(...), |
| 201 | geom_click_point(aes(url=webUIRequestUrl), ...), |
| Marc Kupietz | 38e4e02 | 2024-04-29 17:21:48 +0200 | [diff] [blame] | 202 | theme(axis.text.x = element_text(angle = 45, hjust = 1), legend.position.inside = c(0.8, 0.2)), |
| Marc Kupietz | d68f971 | 2019-10-06 21:48:00 +0200 | [diff] [blame] | 203 | scale_x_continuous(breaks = function(x) seq(ceiling(x[1]), floor(x[2]), by = 1 + floor(((x[2]-x[1])/30))))) |
| 204 | } |
| 205 | |
| Marc Kupietz | 5fb892e | 2021-03-05 08:18:25 +0100 | [diff] [blame] | 206 | #' |
| Marc Kupietz | 865760f | 2019-10-07 19:29:44 +0200 | [diff] [blame] | 207 | #' @importFrom ggplot2 ggproto aes GeomPoint |
| Marc Kupietz | 5fb892e | 2021-03-05 08:18:25 +0100 | [diff] [blame] | 208 | #' |
| 209 | GeomClickPoint <- ggplot2::ggproto( |
| Marc Kupietz | 865760f | 2019-10-07 19:29:44 +0200 | [diff] [blame] | 210 | "GeomPoint", |
| Marc Kupietz | 5fb892e | 2021-03-05 08:18:25 +0100 | [diff] [blame] | 211 | ggplot2::GeomPoint, |
| Marc Kupietz | 865760f | 2019-10-07 19:29:44 +0200 | [diff] [blame] | 212 | required_aes = c("x", "y"), |
| 213 | default_aes = aes( |
| 214 | shape = 19, colour = "black", size = 1.5, fill = NA, |
| 215 | alpha = NA, stroke = 0.5, url = NA |
| 216 | ), |
| 217 | extra_params = c("na.rm", "url"), |
| 218 | draw_panel = function(data, panel_params, |
| 219 | coord, na.rm = FALSE, showpoints = TRUE, url = NULL) { |
| 220 | GeomPoint$draw_panel(data, panel_params, coord, na.rm = na.rm) |
| 221 | } |
| 222 | ) |
| 223 | |
| 224 | #' @importFrom ggplot2 layer |
| 225 | geom_click_point <- function(mapping = NULL, data = NULL, stat = "identity", |
| Marc Kupietz | 5fb892e | 2021-03-05 08:18:25 +0100 | [diff] [blame] | 226 | position = "identity", na.rm = FALSE, show.legend = NA, |
| 227 | inherit.aes = TRUE, url = NA, ...) { |
| Marc Kupietz | 865760f | 2019-10-07 19:29:44 +0200 | [diff] [blame] | 228 | layer( |
| 229 | geom = GeomClickPoint, mapping = mapping, data = data, stat = stat, |
| 230 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, |
| 231 | params = list(na.rm = na.rm, ...) |
| 232 | ) |
| 233 | } |
| 234 | |