Christopher Johnson (WMDE) has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/238316

Change subject: first commit
......................................................................

first commit

Change-Id: I7d9abda4d64796bc749a1a33e47f65058bd3a5fd
---
A .gitignore
A README.md
A Wikidata community engagement tracking - Sheet1.ods
A assets/content/wikidata-edits.md
A assets/content/wikidata-pages.md
A assets/content/wikidata-properties.md
A assets/css/custom.css
A server.R
A ui.R
A utils.R
A wdm.Rproj
A wikidata-edits.tsv
A wikidata-pages.tsv
A wikidata-properties.tsv
A www/rainbow.js
A www/stylesheet.css
16 files changed, 516 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/wikidata/analytics/dashboard 
refs/changes/16/238316/1

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..aa7f856
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.Rhistory
+.Rproj.user/
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..571fb08
--- /dev/null
+++ b/README.md
@@ -0,0 +1,19 @@
+## Quick start
+
+Install the dependencies:
+
+```
+$ R
+> install.packages(c("curl", "httpuv", "readr", "xts", "reshape2",
+    "RColorBrewer", "shiny", "shinydashboard", "dygraphs", "markdown",
+    "ggplot2", "toOrdinal", "plyr", "lubridate", "magrittr"))
+```
+
+Run the server:
+
+```
+$ R
+> library(shiny)
+> runApp(launch.browser = 0)
+```
+
diff --git a/Wikidata community engagement tracking - Sheet1.ods b/Wikidata 
community engagement tracking - Sheet1.ods
new file mode 100644
index 0000000..19553bc
--- /dev/null
+++ b/Wikidata community engagement tracking - Sheet1.ods
Binary files differ
diff --git a/assets/content/wikidata-edits.md b/assets/content/wikidata-edits.md
new file mode 100644
index 0000000..6ca2876
--- /dev/null
+++ b/assets/content/wikidata-edits.md
@@ -0,0 +1,8 @@
+Wikidata Edits
+=======
+
+* Type: Aggregate
+* Source:
+* Update Interval:
+* Reliability:
+* Description:
diff --git a/assets/content/wikidata-pages.md b/assets/content/wikidata-pages.md
new file mode 100644
index 0000000..0e2f9e4
--- /dev/null
+++ b/assets/content/wikidata-pages.md
@@ -0,0 +1,8 @@
+Wikidata Pages
+=======
+
+* Type: Aggregate
+* Source:
+* Update Interval:
+* Reliability:
+* Description:
diff --git a/assets/content/wikidata-properties.md 
b/assets/content/wikidata-properties.md
new file mode 100644
index 0000000..f6d317e
--- /dev/null
+++ b/assets/content/wikidata-properties.md
@@ -0,0 +1,8 @@
+Wikidata Properties
+=======
+
+* Type: Aggregate
+* Source:
+* Update Interval:
+* Reliability:
+* Description:
diff --git a/assets/css/custom.css b/assets/css/custom.css
new file mode 100644
index 0000000..fb0d105
--- /dev/null
+++ b/assets/css/custom.css
@@ -0,0 +1,3 @@
+.dygraph-legend {
+  background-color: #ECF0F5 !important;
+}
diff --git a/server.R b/server.R
new file mode 100644
index 0000000..65211da
--- /dev/null
+++ b/server.R
@@ -0,0 +1,46 @@
+## Version 0.2.0
+source("utils.R")
+
+existing_date <- (Sys.Date()-1)
+
+## Read in desktop data and generate means for the value boxes, along with a 
time-series appropriate form for
+## dygraphs.
+read_desktop <- function(){
+  data <- download_set("wikidata-edits.tsv")
+  wikidata_edits <<- data
+  
+  data <- download_set("wikidata-pages.tsv")
+  wikidata_pages <<- data
+  
+  data <- download_set("wikidata-properties.tsv")
+  wikidata_properties <<- data
+  
+  return(invisible())
+}
+
+shinyServer(function(input, output) {
+
+  if(Sys.Date() != existing_date){
+    read_desktop()
+    existing_date <<- Sys.Date()
+  }
+
+  output$wikidata_edits_plot <- renderDygraph({
+    smooth_level <- input$smoothing_wikidata_edits
+    make_dygraph(wikidata_edits,
+                 "Date", "Edits", "Wikidata Edits, by month",
+                 smoothing = ifelse(smooth_level == "global", 
input$smoothing_global, smooth_level))
+  })
+  output$wikidata_pages_plot <- renderDygraph({
+    smooth_level <- input$smoothing_wikidata_pages
+    make_dygraph(wikidata_pages,
+                 "Date", "Pages", "Wikidata Pages, by month", legend_name = 
"pages",
+                 smoothing = ifelse(smooth_level == "global", 
input$smoothing_global, smooth_level))
+  })
+  output$wikidata_properties_plot <- renderDygraph({
+    smooth_level <- input$smoothing_wikidata_properties
+    make_dygraph(wikidata_properties,
+                 "Date", "Properties", "Wikidata Properties, by month", 
legend_name = "properties",
+                 smoothing = ifelse(smooth_level == "global", 
input$smoothing_global, smooth_level))
+  })
+})
diff --git a/ui.R b/ui.R
new file mode 100644
index 0000000..3af7b78
--- /dev/null
+++ b/ui.R
@@ -0,0 +1,52 @@
+library(shiny)
+library(shinydashboard)
+library(dygraphs)
+options(scipen = 500)
+
+#Header elements for the visualisation
+header <- dashboardHeader(title = "Wikidata Metrics", disable = FALSE)
+
+#Sidebar elements for the search visualisations.
+sidebar <- dashboardSidebar(
+  tags$head(
+    tags$link(rel = "stylesheet", type = "text/css", href = "stylesheet.css"),
+    tags$script(src = "rainbow.js")
+  ),
+  sidebarMenu(
+    menuItem(text = "Wikidata",
+             menuSubItem(text = "Edits", tabName = "wikidata_edits"),
+             menuSubItem(text = "Pages", tabName = "wikidata_pages"),
+             menuSubItem(text = "Properties", tabName = 
"wikidata_properties")),    
+    selectInput(inputId = "smoothing_global", label = "Smoothing (Global 
Setting)", selectize = TRUE, selected = "day",
+                choices = c("No Smoothing" = "day", "Moving Average" = 
"moving_avg",
+                            "Weekly Median" = "week", "Monthly Median" = 
"month"))
+  )
+)
+
+# Standardised input selector for smoothing
+smooth_select <- function(input_id, label = "Smoothing") {
+  return(selectInput(inputId = input_id, label = label, selectize = TRUE,
+                     selected = "global", choices = c("Use Global Setting" = 
"global",
+                     "No Smoothing" = "day", "Moving Average" = "moving_avg",
+                     "Weekly Median" = "week", "Monthly Median" = "month")))
+}
+
+#Body elements for the search visualisations.
+body <- dashboardBody(
+  tabItems(
+    tabItem(tabName = "wikidata_edits",
+            smooth_select("smoothing_wikidata_edits"),
+            dygraphOutput("wikidata_edits_plot"),
+            includeMarkdown("./assets/content/wikidata-edits.md")),
+    tabItem(tabName = "wikidata_pages",
+            smooth_select("smoothing_wikidata_pages"),
+            dygraphOutput("wikidata_pages_plot"),
+            includeMarkdown("./assets/content/wikidata-pages.md")),
+    tabItem(tabName = "wikidata_properties",
+            smooth_select("smoothing_wikidata_properties"),
+            dygraphOutput("wikidata_properties_plot"),
+            includeMarkdown("./assets/content/wikidata-properties.md"))
+  )
+)
+
+dashboardPage(header, sidebar, body, skin = "black")
diff --git a/utils.R b/utils.R
new file mode 100644
index 0000000..932daf6
--- /dev/null
+++ b/utils.R
@@ -0,0 +1,196 @@
+#Dependent libs
+library(plyr)
+library(readr)
+library(xts)
+library(reshape2)
+library(RColorBrewer)
+library(ggplot2)
+library(toOrdinal)
+library(lubridate)
+library(magrittr)
+
+#Utility functions for handling particularly common tasks
+download_set <- function(location){
+  location <- paste0("http://localhost/";, location,
+                     "?ts=", gsub(x = Sys.time(), pattern = "(-| )", 
replacement = ""))
+  con <- url(location)
+  return(readr::read_delim(con, delim = "\t"))
+}
+
+# Takes an untidy (read: dygraph-appropriate) dataset and adds
+# columns for each variable consisting of the smoothed, averaged mean
+smoother <- function(dataset, smooth_level = "day", rename = TRUE) {
+
+  # Determine the names and levels of aggregation. By default
+  # a smoothing level of "day" is assumed, which is no smoothing
+  # whatsoever, and so the original dataset is returned.
+  switch(smooth_level,
+         moving_avg = {
+           df <- apply(dataset[, -1, drop = FALSE], 2, function(x) {
+             y <- xts(x, dataset[, 1])
+             return(as.numeric(zoo::rollmean(x, k = 17, fill = NA)))
+           }) %>% as.data.frame %>% cbind(timestamp = dataset[, 1], .)
+           names(df) <- names(dataset)
+           if (rename) names(df)[-1] <- paste(names(df)[-1], " (Moving 
average)")
+           return(df)
+         },
+         week = {
+           dataset$filter_1 <- lubridate::week(dataset[, 1])
+           dataset$filter_2 <- lubridate::year(dataset[, 1])
+           name_append <- ifelse(rename, " (Weekly average)", "")
+         },
+         month = {
+           dataset$filter_1 <- lubridate::month(dataset[, 1])
+           dataset$filter_2 <- lubridate::year(dataset[, 1])
+           name_append <- ifelse(rename, " (Monthly average)", "")
+         },
+         {
+           return(dataset)
+         }
+  )
+
+  # If we're still here it was weekly or monthly. Calculate
+  # the average for each unique permutation of filters
+
+  result <- ddply(.data = dataset,
+                  .variables = c("filter_1", "filter_2"),
+                  .fun = function(df, name_append){
+
+                    # Construct output names for the averages, compute those 
averages, and
+                    # apply said names.
+                    output_names <- paste0(names(df)[2:(ncol(df) - 2)], 
name_append)
+                    holding <- apply(df[, 2:(ncol(df) - 2), drop = FALSE], 2, 
FUN = median) %>%
+                      round %>% t %>% as.data.frame
+                    names(holding) <- output_names
+
+                    # Return the bound original values and averaged values
+                    return(cbind(df[, 1, drop = FALSE], holding))
+                  }, name_append = name_append)
+
+  return(result[, !(names(result) %in% c("filter_1","filter_2"))])
+}
+
+#Create a dygraph using our standard format.
+make_dygraph <- function(data, x, y, title, is_single = FALSE, legend_name = 
NULL, use_si = TRUE, smoothing = "day") {
+  # cat("Making dygraph:", title, "\n"); # Debugging
+  if (is_single) {
+    data <- smoother(as.data.frame(data[, c(1, 3)]), smooth_level = smoothing)
+    data <- xts(data[, 2], data[, 1])
+    if (is.null(legend_name)) {
+      names(data) <- "events"
+    } else {
+      names(data) <- legend_name
+    }
+  } else {
+    data %<>% smoother(smooth_level = smoothing)
+    data <- xts(data[, -1], order.by = data[, 1])
+  }
+  return(dygraph(data, main = title, xlab = x, ylab = y) %>%
+           dyLegend(width = 400, show = "always") %>%
+           dyOptions(strokeWidth = 3,
+                     colors = brewer.pal(max(3, ncol(data)), "Set2"),
+                     drawPoints = FALSE, pointSize = 3, labelsKMB = use_si,
+                     includeZero = TRUE) %>%
+           dyCSS(css = "./assets/css/custom.css"))
+}
+
+# Computes a median absolute deviation
+mad <- function(x) {
+  median(abs(x - median(x)))
+}
+
+compress <- function(x, round.by = 2) {
+  # by StackOverflow user 'BondedDust' : http://stackoverflow.com/a/28160474
+  div <- findInterval(as.numeric(gsub("\\,", "", x)),
+                      c(1, 1e3, 1e6, 1e9, 1e12) )
+  paste(round( as.numeric(gsub("\\,","",x))/10^(3*(div-1)), round.by),
+        c("","K","M","B","T")[div], sep = "" )
+}
+
+# Conditional icon for widget.
+# Returns arrow-up icon on true (if true_direction is 'up'), e.g. load time % 
change > 0
+cond_icon <- function(condition, true_direction = "up") {
+
+  if (true_direction == "up") {
+    return(icon(ifelse(condition, "arrow-up", "arrow-down")))
+  }
+
+  return(icon(ifelse(condition, "arrow-down", "arrow-up")))
+}
+
+# Conditional color for widget
+# Returns 'green' on true, 'red' on false, e.g. api usage % change > 0
+#                                               load time % change < 0
+cond_color <- function(condition, true_color = "green") {
+  if(is.na(condition)){
+    return("black")
+  }
+
+  colours <- c("green","red")
+  return(ifelse(condition, true_color, colours[!colours == true_color]))
+}
+
+# Allows very quickly to get half a vector:
+half <- function(x, which = c("top", "bottom")) {
+  if (which == "top") {
+    return(head(x, n = length(x)/2))
+  }
+  return(tail(x, n = length(x)/2))
+}
+
+# Uses ggplot2 to create a pie chart in bar form. (Will look up actual name)
+gg_prop_bar <- function(data, cols) {
+  # `cols` = list(`item`, `prop`, `label`)
+  data$text_position <- cumsum(data[[cols$prop]]) + (c(0, 
cumsum(data[[cols$prop]])[-nrow(data)]) - cumsum(data[[cols$prop]]))/2
+  ggplot(data, aes_string(x = 1, fill = cols$item)) +
+    geom_bar(aes_string(y = cols$prop), stat="identity") +
+    scale_fill_discrete(guide = FALSE, expand = c(0,0)) +
+    scale_y_continuous(expand = c(0,0)) +
+    scale_x_continuous(expand = c(0,0)) +
+    labs(x = NULL, y = NULL) +
+    coord_flip() +
+    theme_bw() +
+    theme(axis.ticks = element_blank(),
+          axis.text = element_blank(),
+          axis.title = element_blank(),
+          plot.margin = grid::unit(c(0, 0, -0.5, -0.5), "lines"),
+          panel.margin = grid::unit(0, "lines")) +
+    geom_text(aes_string(label = cols$label,
+                  y = "text_position",
+                  x = 1))
+}
+
+# Calculates percent change either in `x` or from `x` to `y`
+percent_change <- function(x, y = NULL) {
+  if(is.null(y)) {
+    return(100 * (x - c(NA, x[-length(x)])) / c(NA, x[-length(x)]))
+  }
+  return(100 * (y - x) / x)
+}
+
+# It's fairly common to need to grab the last N [whatever] of values.
+# The problem with using tail() for this comes in the case where (perhaps
+# due to backfilling) the last rows are not actually the last rows. This
+# function will provide a 'safe' tail mechanism.
+safe_tail <- function(x, n, silent = TRUE) {
+  if (!is.vector(x) && !is.data.frame(x)) {
+    stop("safe_trail() only works with vectors and data frames.")
+  }
+  # \code{silent} suppresses messages which may be used for debugging
+  if (is.vector(x)) {
+    return(tail(sort(x), n))
+  }
+  # Intelligently figure out which column is the date/timestamp column (in 
case it's not the first column):
+  timestamp_column <- names(x)[sapply(x, class) %in% c("Date", "POSIXt", 
"POSIXlt", "POSIXct")]
+  if (length(timestamp_column) == 0) {
+    if (!silent) {
+      message("No date/timestamp column detected for this dataset. It'd be 
faster to use tail().")
+    }
+    return(tail(x, n))
+  }
+  if (length(timestamp_column) > 1) warning("More than one date/timestamp 
column detected. Defaulting to the first one.")
+  if (!silent) {
+    message("Sorting by the date/timestamp column before returning the bottom 
", n, " rows.")
+  }
+  return(tail(x[order(x[[timestamp_column[1]]]), ], n))
+}
diff --git a/wdm.Rproj b/wdm.Rproj
new file mode 100644
index 0000000..8e3c2eb
--- /dev/null
+++ b/wdm.Rproj
@@ -0,0 +1,13 @@
+Version: 1.0
+
+RestoreWorkspace: Default
+SaveWorkspace: Default
+AlwaysSaveHistory: Default
+
+EnableCodeIndexing: Yes
+UseSpacesForTab: Yes
+NumSpacesForTab: 2
+Encoding: UTF-8
+
+RnwWeave: Sweave
+LaTeX: pdfLaTeX
diff --git a/wikidata-edits.tsv b/wikidata-edits.tsv
new file mode 100644
index 0000000..526aba7
--- /dev/null
+++ b/wikidata-edits.tsv
@@ -0,0 +1,44 @@
+date   edits
+2012-03-06     0
+2012-03-16     0
+2012-04-04     0
+2012-05-02     0
+2012-06-01     0
+2012-07-01     0
+2012-07-19     0
+2012-08-01     0
+2012-09-03     0
+2012-10-01     0
+2012-11-01     277282
+2012-12-01     739463
+2013-01-01     3004417
+2013-01-15     4394605
+2013-02-01     5622432
+2013-02-14     6571138
+2013-03-01     8566579
+2013-03-28     16230567
+2013-04-01     18200917
+2013-04-25     31046033
+2013-05-04     35037199
+2013-05-29     48726285
+2013-06-27     53560384
+2013-08-15     67289779
+2013-09-03     69920660
+2013-10-01     75856816
+2013-11-02     85554179
+2013-12-01     93577968
+2014-01-01     100445470
+2014-01-29     109197986
+2014-03-09     118653905
+2014-04-09     123785772
+2014-05-01     128627662
+2014-06-23     144505252
+2014-09-25     164090676
+2014-12-23     182571317
+2015-01-09     186439727
+2015-03-03     200530996
+2015-04-01     208039122
+2015-05-04     213859909
+2015-06-11     221731098
+2015-07-12     229631849
+2015-08-14     241198069
diff --git a/wikidata-pages.tsv b/wikidata-pages.tsv
new file mode 100644
index 0000000..eb3ccee
--- /dev/null
+++ b/wikidata-pages.tsv
@@ -0,0 +1,44 @@
+date   wikidata pages
+2012-03-06     0
+2012-03-16     0
+2012-04-04     0
+2012-05-02     0
+2012-06-01     0
+2012-07-01     0
+2012-07-19     0
+2012-08-01     0
+2012-09-03     0
+2012-10-01     0
+2012-11-01     6291
+2012-12-01     234391
+2013-01-01     2112481
+2013-01-15     2541926
+2013-02-01     3753792
+2013-02-14     4323468
+2013-03-01     5357442
+2013-03-28     8132790
+2013-04-01     8739435
+2013-04-25     11153887
+2013-05-04     11868715
+2013-05-29     12575364
+2013-06-27     12673449
+2013-08-15     13613453
+2013-09-03     13785931
+2013-10-01     13992683
+2013-11-02     14065881
+2013-12-01     14154946
+2014-01-01     14364021
+2014-01-29     14443740
+2014-03-09     14634453
+2014-04-09     14934793
+2014-05-01     15342199
+2014-06-23     15722130
+2014-09-25     16320307
+2014-12-23     16871369
+2015-01-09     16917814
+2015-03-03     17624158
+2015-04-01     17952489
+2015-05-04     18056326
+2015-06-11     18284555
+2015-07-12     18846361
+2015-08-14     19000343
diff --git a/wikidata-properties.tsv b/wikidata-properties.tsv
new file mode 100644
index 0000000..898b7e7
--- /dev/null
+++ b/wikidata-properties.tsv
@@ -0,0 +1,44 @@
+date   properties
+2012-03-06     0
+2012-03-16     0
+2012-04-04     0
+2012-05-02     0
+2012-06-01     0
+2012-07-01     0
+2012-07-19     0
+2012-08-01     0
+2012-09-03     0
+2012-10-01     0
+2012-11-01     0
+2012-12-01     0
+2013-01-01     0
+2013-01-15     0
+2013-02-01     0
+2013-02-14     0
+2013-03-01     127
+2013-03-28     255
+2013-04-01     261
+2013-04-25     328
+2013-05-04     345
+2013-05-29     411
+2013-06-27     486
+2013-08-15     629
+2013-09-03     656
+2013-10-01     740
+2013-11-02     793
+2013-12-01     825
+2014-01-01     840
+2014-01-29     855
+2014-03-09     962
+2014-04-09     
+2014-05-01     
+2014-06-23     1122
+2014-09-25     1196
+2014-12-23     1191
+2015-01-09     1188
+2015-03-03     1188
+2015-04-01     1188
+2015-05-04     1186
+2015-06-11     1186
+2015-07-12     1186
+2015-08-14     1210
diff --git a/www/rainbow.js b/www/rainbow.js
new file mode 100644
index 0000000..7f65bc0
--- /dev/null
+++ b/www/rainbow.js
@@ -0,0 +1,25 @@
+$(function() {
+
+    // Enables linking to specific tabs:
+    if (window.location.hash){
+      var hash = $.trim(window.location.hash);
+      var tab = decodeURI(hash.substring(1, 100));
+      $('a[data-value=\"'+tab+'\"]').click();
+    }
+
+    // Enables clicking on a kpi summary value box to view the time series:
+    $('div[id^=kpi_summary_box_]').click(function(){
+        var parent_id = $(this).closest('div').attr('id');
+        var parent_target = parent_id.replace('_summary_box', '');
+        $('a[data-value=\"'+parent_target+'\"]').click();
+    });
+
+    // Visual feedback that the value box is now something you can click:
+    $('div[id^=kpi_summary_box_]').hover(function() {
+        $(this).css('cursor','pointer');
+    });
+
+    // Reveals the KPI dropdown menu at launch:
+    $('ul.sidebar-menu li.treeview').first().addClass('active');
+
+});
diff --git a/www/stylesheet.css b/www/stylesheet.css
new file mode 100644
index 0000000..2451b16
--- /dev/null
+++ b/www/stylesheet.css
@@ -0,0 +1,3 @@
+.kpi_date {
+       margin-top: 0px;
+}

-- 
To view, visit https://gerrit.wikimedia.org/r/238316
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I7d9abda4d64796bc749a1a33e47f65058bd3a5fd
Gerrit-PatchSet: 1
Gerrit-Project: wikidata/analytics/dashboard
Gerrit-Branch: master
Gerrit-Owner: Christopher Johnson (WMDE) <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to