diff --git a/.gitignore b/.gitignore index c899710..b56ad23 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,11 @@ listings/lp-output/* cache cache-lt +# Plotting artifacts +/etc/rooms.json +/etc/plots +.Rhistory + # Local tests .test log.txt diff --git a/etc/plot-staff.r b/etc/plot-staff.r new file mode 100755 index 0000000..b211f7b --- /dev/null +++ b/etc/plot-staff.r @@ -0,0 +1,147 @@ +#!/bin/env Rscript +library('jsonlite') +library('purrr') +library('RcppColors') + +dummy <- function(x) { x } +srcdir <- getSrcDirectory(dummy)[1] +if (is.na(srcdir)) { + args <- commandArgs() + selfarg <- args[startsWith(args, "--file=")] + srcdir <- dirname(sub('^--file=', '', selfarg)) +} +setwd(srcdir) + +rooms <- read_json('rooms.json', simplifyVector = TRUE) +rooms <- rooms[rooms$write, ] +rooms <- rooms[rooms$read, ] +servers <- unique(data.frame(id=rooms$server_id,base_url=rooms$base_url)) +servers$hostname <- sub('^https?://', '', servers$base_url) +servers$pch = rep_len(seq(15, 18), nrow(servers)) +servers$col = rep_len(c("orange",2,3,4,5,6,8), nrow(servers)) + +rooms$staff = map_vec(rooms$moderators, length) + map_vec(rooms$admins, length) + +dir.exists("plots") || dir.create("plots") + +for (i in 1:nrow(servers)) { + +server <- servers[i, ] + +rooms.current <- rooms[rooms$server_id == server$id, ] +rooms.current <- rooms.current[order(rooms.current$active_users), ] +rooms.current$pch = rep_len(seq(15, 18), nrow(rooms.current)) +rooms.current$col = rep_len(c(3,4,5,6,8), nrow(rooms.current)) + +rooms.space = min(10,nrow(rooms.current)) + +minwau <- min(rooms.current$active_users) +maxwau <- max(rooms.current$active_users) +maxstaff <- max(rooms.current$staff) +maxstaff.shown <- max(1, maxstaff*1.05^rooms.space * 1.3) + +png( + filename=paste("plots/", server$hostname, ".plot.png", sep=""), + width=1080, height=1080, pointsize=30 +) + +if (maxwau-minwau < 10) { + xlim <- c(minwau*0.95, maxwau*1.05) + x.smol <- TRUE +} else { + xlim <- c(minwau, maxwau) + x.smol <- FALSE +} + +#e <- exp(1) + +# nice to have +#line <- function(x) 2 + floor(log(x, base=7)^1.1) +line <- function(x) ceiling(pmax(2,x^0.25)) + +# low bar (higher base) +line2 <- function(x) 1 + pmax(1,round((0.38*log(x))^1.15)) + +plot( + function(x) line(pmax(1,x)), + main=server$hostname, + sub=paste("black: ", deparse(body(line)), "; red: ", deparse(body(line2)), sep=""), + xlim=xlim, + log=ifelse(minwau==0,"","x"), + ylab="# of visible staff", + xlab="# of weekly readers", + ylim=c(0,maxstaff.shown), + yaxt="n", + cex.sub=0.8 +) + +plot( + function(x) line2(pmax(1,x)), + xlim=xlim, col="red", add=TRUE, lwd=2 +) + +wau.ceil.log <- ceiling(max(0, log10(maxwau))) +maxstaff.ceil.log <- ceiling(max(0, log10(maxstaff))) + +grid.col <- "#777777" +grid.col.extra <- "#BBBBBB" + +if (x.smol) { + vlines <- seq(floor(0.9*minwau),ceiling(1.1*maxwau),1) +} else { +vlines <- as.vector(outer(c(1,2,3,5), 10 ^ seq(0, wau.ceil.log))) +vlines.extra <- as.vector(outer(c(1.2,1.4,1.6,1.8,2.25,2.5,2.75,3.5,4,4.5,6,7,8,9), 10 ^ seq(0, wau.ceil.log))) +vlines.extra <- vlines.extra[vlines.extra == floor(vlines.extra)] +abline(v=vlines.extra, col=grid.col.extra, lty="dotted") +} +abline(v=vlines, col=grid.col, lty="dotted") + +hlab.gap=ceiling(maxstaff.shown/5) +hlab.gap.logwise.floor = 10^floor(log10(hlab.gap)) +hlines.extra <- c() +if (hlab.gap.logwise.floor * 5 < hlab.gap * 1.75) { + hlab.gap <- hlab.gap.logwise.floor * 5 + hlines.extra <- seq(1,maxstaff.shown,hlab.gap/5) +} else { + hlab.gap <- hlab.gap.logwise.floor + if(hlab.gap %% 10 == 0) { + hlines.extra <- seq(hlab.gap/2,maxstaff.shown,hlab.gap) + } +} +hlab=seq(0, maxstaff * 1.5, hlab.gap) +axis(2, at=hlab) + +hlines=seq(0,maxstaff.shown,hlab.gap) +abline(h=seq(0, maxstaff.shown, hlab.gap), col=grid.col, lty="dotted") +abline(h=hlines.extra, col=grid.col.extra, lty="dotted") + +# pch = servers[match(rooms.current$server_id, servers$id), 'pch'] +points( + rooms.current$active_users, + pmin(rooms.current$staff,maxstaff), + pch=rooms.current$pch, + # col=servers[match(rooms.current$server_id, servers$id), 'col'], + col=rooms.current$col, + cex=ifelse(rooms.current$pch==18,1.7,1.5) +) + +for (i in 0:2) { + chunk <- rooms.current[((i*10)+1):((i+1)*10), ] + chunk <- chunk[!is.na(chunk$token), ] + if (nrow(chunk) == 0) { + break + } + legend( + x=(c("topleft","top","topright")[i+1]), + legend = chunk$token, + pch=chunk$pch, + col=chunk$col, + cex=0.99^rooms.space, + pt.cex = ifelse(chunk$pch==18,1.2,1) + ) +} + +dev.off() + + +} diff --git a/etc/rooms.sh b/etc/rooms.sh new file mode 100755 index 0000000..365bc2b --- /dev/null +++ b/etc/rooms.sh @@ -0,0 +1,3 @@ +#!/bin/sh +cd "$(dirname "$0")" || exit 1; +jq 'map(. as {$server_id, $base_url, $pubkey} | . + {rooms: .rooms | map(. + {$server_id, $base_url, $pubkey})}) | map(.rooms) | flatten' -Mc '../output/servers.json' > rooms.json diff --git a/etc/staff-interpolation.r b/etc/staff-interpolation.r new file mode 100644 index 0000000..4f52f4b --- /dev/null +++ b/etc/staff-interpolation.r @@ -0,0 +1,44 @@ +#!/bin/env Rscript +#staff <- function(x) round(pmax(2,log(x,base=4)^1.2)) +staff <- function(x) pmax(2,ceiling(x^0.25)) +#staff <- function(x) pmax(2,round(x/50)) +xlim=c(1,15000) +plot(staff,xlim=xlim,ylim=c(0,10),log="x",axes=FALSE,ylab="") +axis(1, at=as.vector(outer(c(1,2,5), 10^c(0,1,2,3,4)))) +axis(2) +plot(function(x) pmax(2,1 + round((0.38*log(x))^1.15)),xlim=xlim,add=TRUE,col="red") +plot(function(x) pmax(2,1 + round(log(x, base=8))),xlim=xlim,add=TRUE,col="blue") +grid() +pts = rbind( + c(1,2), + c(2,2), + c(3,2), + c(5,2), + c(10,2), + c(20,2), + c(30,2), + c(40,2), + c(50,3), + c(100,3), + c(200,4), + c(500,5), + c(1000,5), + c(2000,6), + c(5000,8), + c(10000,10), + c(20000,15), + c(50000,20) +) +points(pts); +if(0) { +par(new=TRUE) +plot( + function(x) staff(x)/x, + log="xy", + xlim=xlim, + col="red", + axes=FALSE, + ylab="" +) +axis(4, col="red") +}