#' client_stats UI Function
#'
#' @description A shiny Module.
#'
#' @param id,input,output,session Internal parameters for {shiny}.
#'
#' @noRd
#'
#' @importFrom shiny NS tagList
mod_client_stats_ui <- function(id) {
ns <- NS(id)
tagList(fluidRow(
column(
theme = bs_theme(version = 4, bootswatch = "minty"),
width = 12,
HTML("<h4>Market share of Clients by users Device Display Names (excluding Element)</h4>"),
shinycssloaders::withSpinner(plotOutput(ns(
"clientMarketShare_no_element"
), height = "900px"))
)
),fluidRow(
column(
theme = bs_theme(version = 4, bootswatch = "minty"),
width = 12,
HTML("<h4>Market share of Clients by users Device Display Names</h4>"),
shinycssloaders::withSpinner(plotOutput(ns(
"clientMarketShare"
), height = "900px"))
)
),
HTML("<br/>"))
}
#' client_stats Server Functions
#'
#' @import ggplot2
#' @import plotly
#' @import stringr
#' @import readr
#' @import treemapify
#'
#' @noRd
mod_client_stats_server <- function(id) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
output$clientMarketShare_no_element <- renderPlot({
df = read.csv("/opt/devices_snapshots/datadump.csv", header = FALSE)
p <- df |>
mutate(
Client = case_when(
str_detect(V1, '^.*.element.io') ~ 'Element Web',
str_detect(V1, '^chat.mozilla.org') ~ 'Element Web',
str_detect(V1, '^element.') ~ 'Element Web',
str_detect(V1, '^Riot Desktop') ~ 'Riot Desktop',
str_detect(V1, '^Element Desktop') ~ 'Element Desktop',
str_detect(V1, '^Fluffychat') ~ 'Fluffychat',
str_detect(V1, '^FluffyChat') ~ 'Fluffychat',
str_detect(V1, '^Fluffy') ~ 'Fluffychat',
str_detect(V1, '^RiotX Android') ~ 'RiotX Android',
str_detect(V1, '^Element Android') ~ 'Element Android',
str_detect(V1, '^Element .*Android') ~ 'Element Android',
str_detect(V1, '^Element') ~ 'Element',
str_detect(V1, '^SchildiChat Android') ~ 'SchildiChat Android',
str_detect(V1, '^SchildiChat Desktop') ~ 'SchildiChat Desktop',
str_detect(V1, '^gomuks') ~ 'gomuks',
str_detect(V1, '^Syphon') ~ 'Syphon',
str_detect(V1, '^Hydrogen') ~ 'Hydrogen',
str_detect(V1, '^Mirage') ~ 'Mirage',
str_detect(V1, '^riot.im/') ~ 'Riot.im Web',
str_detect(V1, '^https://riot.im/') ~ 'Riot.im Web',
str_detect(V1, '^Weechat') ~ 'Weechat',
str_detect(V1, '^wechat') ~ 'wechat',
str_detect(V1, '^Nheko') ~ 'Nheko',
str_detect(V1, '^nheko') ~ 'Nheko',
str_detect(V1, '^Beeper login check') ~ 'Beeper login check',
str_detect(V1, '^Beeper Android') ~ 'Beeper Android',
str_detect(V1, '^Beeper Desktop') ~ 'Beeper Desktop',
str_detect(V1, '^talk.chatcloud.net') ~ 'Element Web',
str_detect(V1, '^Cinny Web') ~ 'Cinny Web',
str_detect(V1, '^chat.minds.com') ~ 'Minds.com',
str_detect(V1, '^webchat.kde.org') ~ 'Element Web',
str_detect(V1, '^chat.fosdem.org') ~ 'Element Web',
str_detect(V1, '^purple-matrix') ~ 'purple-matrix',
str_detect(V1, '^pantalaimon') ~ 'pantalaimon',
str_detect(V1, '^chat.tchncs.de') ~ 'Element Web',
str_detect(V1, '^https://chat.mozilla.org/') ~ 'Element Web',
str_detect(V1, '^riot.grin.hu') ~ 'Element Web',
str_detect(V1, '^Sailtrix') ~ 'Sailtrix',
str_detect(V1, '^Fractal Next') ~ 'Fractal Next',
str_detect(V1, '^Fractal$') ~ 'Fractal',
str_detect(V1, '^Pattle Android') ~ 'Pattle Android',
str_detect(V1, '^www.riot.im/') ~ 'Riot.im Web',
str_detect(V1, '^WhatsApp Bridge') ~ 'WhatsApp Bridge',
str_detect(V1, '^Telegram Bridge') ~ 'Telegram Bridge',
str_detect(V1, '^Chatty') ~ 'Chatty',
str_detect(V1, '^app.schildi.chat') ~ 'SchildiChat Web',
str_detect(V1, '^chat.') ~ 'Element Web',
str_detect(V1, '^nerdsin.space') ~ 'Element Web',
str_detect(V1, '^matrix.radicle.community') ~ 'Element Web',
str_detect(V1, '^matrix.radicle.community') ~ 'Element Web',
str_detect(V1, '^matrix-commander') ~ 'matrix-commander',
str_detect(V1, '^Riot Web') ~ 'Riot Web',
str_detect(V1, '^riot.ruhr-uni-bochum.de') ~ 'Element Web',
str_detect(V1, '^https://webchat.kde.org/') ~ 'Element Web',
str_detect(V1, '^https://riot.ruhr-uni-bochum.de/') ~ 'Element Web',
str_detect(V1, '^Facebook Messenger Bridge') ~ 'Facebook Messenger Bridge',
str_detect(V1, '^Famedly Web') ~ 'Famedly Web',
str_detect(V1, '^Discord Puppet Bridge') ~ 'Discord Puppet Bridge',
str_detect(V1, '^iMessage Bridge') ~ 'iMessage Bridge',
str_detect(V1, '^Thunderbird') ~ 'Thunderbird',
str_detect(V1, '^Signal Bridge') ~ 'Signal Bridge',
str_detect(V1, '^SchildiChat .*Android') ~ 'SchildiChat Android',
str_detect(V1, '^Instagram Bridge') ~ 'Instagram Bridge',
str_detect(V1, '^Slack Puppet Bridge') ~ 'Slack Puppet Bridge',
str_detect(V1, '^Famedly android') ~ 'Famedly Android',
str_detect(V1, '^Matrix Recorder') ~ 'Matrix Recorder',
str_detect(V1, '^Hangouts Bridge') ~ 'Hangouts Bridge',
str_detect(V1, '^LinkedIn Messages Bridge') ~ 'LinkedIn Messages Bridge',
str_detect(V1, '^SchildiChat .*(Linux)') ~ 'SchildiChat Desktop',
str_detect(V1, '^Pattle iOS') ~ 'Pattle iOS',
str_detect(V1, '^RiotX') ~ 'RiotX',
str_detect(V1, '^Android Messages Bridge') ~ 'Android Messages Bridge',
str_detect(V1, '^Famedly ios') ~ 'Famedly iOS',
str_detect(V1, '^Synapse Admin') ~ 'Synapse Admin',
str_detect(V1, '^WeeMatrix') ~ 'WeeMatrix',
str_detect(V1, '^Daydream') ~ 'Daydream',
str_detect(V1, '^SchildiChat') ~ 'SchildiChat',
str_detect(V1, '^EachChat Android') ~ 'EachChat Android',
str_detect(V1, '^ponies.im/_matrix/client') ~ 'ponies.im',
str_detect(V1, '^riot.') ~ 'Element Web',
str_detect(V1, '^https://riot.') ~ 'Element Web',
str_detect(V1, 'Element Web') ~ 'Element Web',
str_detect(V1, '^Mobile$') ~ 'Element iOS (presumably)',
str_detect(V1, '^Radical') ~ 'Radical',
str_detect(V1, '^Quaternion') ~ 'Quaternion',
str_detect(V1, '^Blast Android') ~ 'Blast Android',
str_detect(V1, '^matrix-sdk') ~ 'matrix-sdk',
str_detect(V1, '^Maunium') ~ 'Maunium',
str_detect(V1, '^Nextcloud') ~ 'Nextcloud',
str_detect(V1, '^Spectral') ~ 'Spectral',
str_detect(V1, '^NeoChat') ~ 'NeoChat',
str_detect(V1, '^SimpleMatrix') ~ 'SimpleMatrix',
str_detect(V1, '^matrix-tag-manager') ~ 'matrix-tag-manager',
str_detect(V1, '^Blast Desktop') ~ 'Blast Desktop',
str_detect(V1, '^IndieChat android') ~ 'IndieChat android',
str_detect(V1, '^Revolution Desktop') ~ 'Revolution Desktop',
str_detect(V1, '^Riot.im') ~ 'Element Web',
str_detect(V1, '^Beeper') ~ 'Beeper',
str_detect(V1, '^Famedly windows') ~ 'Famedly Windows',
str_detect(V1, '^Riot on Android') ~ 'Riot Android',
str_detect(V1, '^Prometheus') ~ 'Prometheus',
str_detect(V1, '^prometheus') ~ 'Prometheus',
str_detect(V1, '^mautrix-manager') ~ 'mautrix-manager',
str_detect(V1, '^mauPhone') ~ 'mauPhone',
str_detect(V1, '^_nheko_') ~ 'Nheko',
str_detect(V1, '^mirage') ~ 'Mirage',
str_detect(V1, '^Schildi Android') ~ 'SchildiChat Android',
str_detect(V1, '^Schildi') ~ 'SchildiChat',
str_detect(V1, '^Blast Desktop') ~ 'Blast Desktop',
TRUE ~ 'Other'
)
) |>
filter(Client != 'Other') |>
group_by(Client) |>
summarize(total = sum(V2)) |>
filter(Client != 'Element') |>
filter(Client != 'Element Android') |>
filter(Client != 'Element Web') |>
filter(Client != 'Element Desktop') |>
filter(Client != 'Element iOS (presumably)') |>
filter(Client != 'Riot Desktop') |>
filter(Client != 'Riot.im Web') |>
ggplot2::ggplot(ggplot2::aes(
area = total,
fill = Client,
label = Client
)) +
geom_treemap() +
geom_treemap_text(
fontface = "italic",
colour = "white",
place = "centre",
grow = TRUE
)
p
})
output$clientMarketShare <- renderPlot({
df = read.csv("/opt/devices_snapshots/datadump.csv", header = FALSE)
p <- df |>
mutate(
Client = case_when(
str_detect(V1, '^.*.element.io') ~ 'Element Web',
str_detect(V1, '^chat.mozilla.org') ~ 'Element Web',
str_detect(V1, '^element.') ~ 'Element Web',
str_detect(V1, '^Riot Desktop') ~ 'Riot Desktop',
str_detect(V1, '^Element Desktop') ~ 'Element Desktop',
str_detect(V1, '^Fluffychat') ~ 'Fluffychat',
str_detect(V1, '^FluffyChat') ~ 'Fluffychat',
str_detect(V1, '^Fluffy') ~ 'Fluffychat',
str_detect(V1, '^RiotX Android') ~ 'RiotX Android',
str_detect(V1, '^Element Android') ~ 'Element Android',
str_detect(V1, '^Element .*Android') ~ 'Element Android',
str_detect(V1, '^Element') ~ 'Element',
str_detect(V1, '^SchildiChat Android') ~ 'SchildiChat Android',
str_detect(V1, '^SchildiChat Desktop') ~ 'SchildiChat Desktop',
str_detect(V1, '^gomuks') ~ 'gomuks',
str_detect(V1, '^Syphon') ~ 'Syphon',
str_detect(V1, '^Hydrogen') ~ 'Hydrogen',
str_detect(V1, '^Mirage') ~ 'Mirage',
str_detect(V1, '^riot.im/') ~ 'Riot.im Web',
str_detect(V1, '^https://riot.im/') ~ 'Riot.im Web',
str_detect(V1, '^Weechat') ~ 'Weechat',
str_detect(V1, '^wechat') ~ 'wechat',
str_detect(V1, '^Nheko') ~ 'Nheko',
str_detect(V1, '^nheko') ~ 'Nheko',
str_detect(V1, '^Beeper login check') ~ 'Beeper login check',
str_detect(V1, '^Beeper Android') ~ 'Beeper Android',
str_detect(V1, '^Beeper Desktop') ~ 'Beeper Desktop',
str_detect(V1, '^talk.chatcloud.net') ~ 'Element Web',
str_detect(V1, '^Cinny Web') ~ 'Cinny Web',
str_detect(V1, '^chat.minds.com') ~ 'Minds.com',
str_detect(V1, '^webchat.kde.org') ~ 'Element Web',
str_detect(V1, '^chat.fosdem.org') ~ 'Element Web',
str_detect(V1, '^purple-matrix') ~ 'purple-matrix',
str_detect(V1, '^pantalaimon') ~ 'pantalaimon',
str_detect(V1, '^chat.tchncs.de') ~ 'Element Web',
str_detect(V1, '^https://chat.mozilla.org/') ~ 'Element Web',
str_detect(V1, '^riot.grin.hu') ~ 'Element Web',
str_detect(V1, '^Sailtrix') ~ 'Sailtrix',
str_detect(V1, '^Fractal Next') ~ 'Fractal Next',
str_detect(V1, '^Fractal$') ~ 'Fractal',
str_detect(V1, '^Pattle Android') ~ 'Pattle Android',
str_detect(V1, '^www.riot.im/') ~ 'Riot.im Web',
str_detect(V1, '^WhatsApp Bridge') ~ 'WhatsApp Bridge',
str_detect(V1, '^Telegram Bridge') ~ 'Telegram Bridge',
str_detect(V1, '^Chatty') ~ 'Chatty',
str_detect(V1, '^app.schildi.chat') ~ 'SchildiChat Web',
str_detect(V1, '^chat.') ~ 'Element Web',
str_detect(V1, '^nerdsin.space') ~ 'Element Web',
str_detect(V1, '^matrix.radicle.community') ~ 'Element Web',
str_detect(V1, '^matrix.radicle.community') ~ 'Element Web',
str_detect(V1, '^matrix-commander') ~ 'matrix-commander',
str_detect(V1, '^Riot Web') ~ 'Riot Web',
str_detect(V1, '^riot.ruhr-uni-bochum.de') ~ 'Element Web',
str_detect(V1, '^https://webchat.kde.org/') ~ 'Element Web',
str_detect(V1, '^https://riot.ruhr-uni-bochum.de/') ~ 'Element Web',
str_detect(V1, '^Facebook Messenger Bridge') ~ 'Facebook Messenger Bridge',
str_detect(V1, '^Famedly Web') ~ 'Famedly Web',
str_detect(V1, '^Discord Puppet Bridge') ~ 'Discord Puppet Bridge',
str_detect(V1, '^iMessage Bridge') ~ 'iMessage Bridge',
str_detect(V1, '^Thunderbird') ~ 'Thunderbird',
str_detect(V1, '^Signal Bridge') ~ 'Signal Bridge',
str_detect(V1, '^SchildiChat .*Android') ~ 'SchildiChat Android',
str_detect(V1, '^Instagram Bridge') ~ 'Instagram Bridge',
str_detect(V1, '^Slack Puppet Bridge') ~ 'Slack Puppet Bridge',
str_detect(V1, '^Famedly android') ~ 'Famedly Android',
str_detect(V1, '^Matrix Recorder') ~ 'Matrix Recorder',
str_detect(V1, '^Hangouts Bridge') ~ 'Hangouts Bridge',
str_detect(V1, '^LinkedIn Messages Bridge') ~ 'LinkedIn Messages Bridge',
str_detect(V1, '^SchildiChat .*(Linux)') ~ 'SchildiChat Desktop',
str_detect(V1, '^Pattle iOS') ~ 'Pattle iOS',
str_detect(V1, '^RiotX') ~ 'RiotX',
str_detect(V1, '^Android Messages Bridge') ~ 'Android Messages Bridge',
str_detect(V1, '^Famedly ios') ~ 'Famedly iOS',
str_detect(V1, '^Synapse Admin') ~ 'Synapse Admin',
str_detect(V1, '^WeeMatrix') ~ 'WeeMatrix',
str_detect(V1, '^Daydream') ~ 'Daydream',
str_detect(V1, '^SchildiChat') ~ 'SchildiChat',
str_detect(V1, '^EachChat Android') ~ 'EachChat Android',
str_detect(V1, '^ponies.im/_matrix/client') ~ 'ponies.im',
str_detect(V1, '^riot.') ~ 'Element Web',
str_detect(V1, '^https://riot.') ~ 'Element Web',
str_detect(V1, 'Element Web') ~ 'Element Web',
str_detect(V1, '^Mobile$') ~ 'Element iOS (presumably)',
str_detect(V1, '^Radical') ~ 'Radical',
str_detect(V1, '^Quaternion') ~ 'Quaternion',
str_detect(V1, '^Blast Android') ~ 'Blast Android',
str_detect(V1, '^matrix-sdk') ~ 'matrix-sdk',
str_detect(V1, '^Maunium') ~ 'Maunium',
str_detect(V1, '^Nextcloud') ~ 'Nextcloud',
str_detect(V1, '^Spectral') ~ 'Spectral',
str_detect(V1, '^NeoChat') ~ 'NeoChat',
str_detect(V1, '^SimpleMatrix') ~ 'SimpleMatrix',
str_detect(V1, '^matrix-tag-manager') ~ 'matrix-tag-manager',
str_detect(V1, '^Blast Desktop') ~ 'Blast Desktop',
str_detect(V1, '^IndieChat android') ~ 'IndieChat android',
str_detect(V1, '^Revolution Desktop') ~ 'Revolution Desktop',
str_detect(V1, '^Riot.im') ~ 'Element Web',
str_detect(V1, '^Beeper') ~ 'Beeper',
str_detect(V1, '^Famedly windows') ~ 'Famedly Windows',
str_detect(V1, '^Riot on Android') ~ 'Riot Android',
str_detect(V1, '^Prometheus') ~ 'Prometheus',
str_detect(V1, '^prometheus') ~ 'Prometheus',
str_detect(V1, '^mautrix-manager') ~ 'mautrix-manager',
str_detect(V1, '^mauPhone') ~ 'mauPhone',
str_detect(V1, '^_nheko_') ~ 'Nheko',
str_detect(V1, '^mirage') ~ 'Mirage',
str_detect(V1, '^Schildi Android') ~ 'SchildiChat Android',
str_detect(V1, '^Schildi') ~ 'SchildiChat',
str_detect(V1, '^Blast Desktop') ~ 'Blast Desktop',
TRUE ~ 'Other'
)
) |>
filter(Client != 'Other') |>
group_by(Client) |>
summarize(total = sum(V2)) |>
ggplot2::ggplot(ggplot2::aes(
area = total,
fill = Client,
label = Client
)) +
geom_treemap() +
geom_treemap_text(
fontface = "italic",
colour = "white",
place = "centre",
grow = TRUE
)
p
})
})
}
## To be copied in the UI
# mod_client_stats_ui("client_stats_ui_1")
## To be copied in the server
# mod_client_stats_server("client_stats_ui_1")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.