jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/391010 )
Change subject: Init ...................................................................... Init Change-Id: Ifa894d8effc9cf713bf7b36bd23e46f8e7a7b48c --- A server.R A ui.R A www/Wikidata-logo-en.png 3 files changed, 1,554 insertions(+), 0 deletions(-) Approvals: Addshore: Looks good to me, approved jenkins-bot: Verified diff --git a/server.R b/server.R new file mode 100644 index 0000000..5bdfdd6 --- /dev/null +++ b/server.R @@ -0,0 +1,999 @@ +### --------------------------------------------------------------------------- +### --- WDCM Usage Dashboard, v. Beta 0.1 +### --- Script: server.R, v. Beta 0.1 +### --------------------------------------------------------------------------- + +### --- Setup +rm(list = ls()) +### -------------------------------- +### --- general +library(shiny) +library(shinydashboard) +library(RMySQL) +library(data.table) +library(DT) +library(stringr) +library(tidyr) +library(dplyr) +library(reshape2) +### --- compute +library(parallelDist) +### --- visualization +library(RColorBrewer) +library(visNetwork) +library(networkD3) +library(ggplot2) +library(ggrepel) +library(scales) + +### --- Server (Session) Scope +### -------------------------------- + +### --- Credentials +# setwd('/home/goransm/WMDE/WDCM/WDCM_RScripts/WDCM_Dashboard/aux') +setwd('/srv/shiny-server/aux') + +mySQLCreds <- fread("mySQLCreds.csv", + header = T, + drop = 1) + +### -- Connect +con <- dbConnect(MySQL(), + host = "tools.labsdb", + defult.file = "/home/goransm/mySQL_Credentials/replica.my.cnf", + dbname = "u16664__wdcm_p", + user = mySQLCreds$user, + password = mySQLCreds$password) + +### --- list existing tables +q <- "SHOW TABLES;" +res <- dbSendQuery(con, q) +st <- fetch(res, -1) +dbClearResult(res) +colnames(st) <- "tables" + +### --- SET CHARACTER SET utf8 +q <- "SET CHARACTER SET utf8;" +res <- dbSendQuery(con, q) +dbClearResult(res) + +### --- fetch wdcm2_project +q <- "SELECT * FROM wdcm2_project;" +res <- dbSendQuery(con, q) +wdcmProject <- fetch(res, -1) +dbClearResult(res) +colnames(wdcmProject) <- c('Project', 'Usage', 'Project Type') + +### --- fetch wdcm2_project_category +q <- "SELECT * FROM wdcm2_project_category;" +res <- dbSendQuery(con, q) +wdcmProjectCategory <- fetch(res, -1) +dbClearResult(res) +colnames(wdcmProjectCategory) <- c('Project', 'Category', 'Usage', 'Project Type') + +### --- fetch wdcm2_project_item100 +q <- "SELECT * FROM wdcm2_project_item100;" +res <- dbSendQuery(con, q) +wdcmProjectItem100 <- fetch(res, -1) +dbClearResult(res) +colnames(wdcmProjectItem100) <- c('Project', 'EntityID', 'Usage', 'Project Type', 'Label') + +### --- fetch wdcm2_project_category_item100 +q <- "SELECT * FROM wdcm2_project_category_item100;" +res <- dbSendQuery(con, q) +wdcmProjectCategoryItem100 <- fetch(res, -1) +dbClearResult(res) +colnames(wdcmProjectCategoryItem100) <- c('Project', 'Category', 'EntityID', 'Usage', 'Project Type', 'Label') + +### --- fetch wdcm2_category +q <- "SELECT * FROM wdcm2_category;" +res <- dbSendQuery(con, q) +wdcmCategory <- fetch(res, -1) +dbClearResult(res) +colnames(wdcmCategory) <- c('Category', 'Usage') + +### --- fetch wdcm2_category_item100 +q <- "SELECT * FROM wdcm2_category_item100;" +res <- dbSendQuery(con, q) +wdcmCategoryItem100 <- fetch(res, -1) +dbClearResult(res) +colnames(wdcmCategoryItem100) <- c('EntityID', 'Usage', 'Category', 'Label') + +### --- Disconnect +dbDisconnect(con) + +### --- Compute per `Project Type` tables +# - wdcmProjectType +wdcmProjectType <- wdcmProject %>% + group_by(`Project Type`) %>% + summarise(Usage = sum(Usage)) %>% + arrange(desc(Usage)) +# - wdcmProjectTypeCategory +wdcmProjectTypeCategory <- wdcmProjectCategory %>% + group_by(`Project Type`, Category) %>% + summarise(Usage = sum(Usage)) %>% + arrange(desc(Usage)) +# - wdcmProjectTypeItem100 +wdcmProjectTypeItem100 <- wdcmProjectItem100 %>% + select(`Project Type`, EntityID, Label, Usage) %>% + group_by(`Project Type`, EntityID, Label) %>% + summarise(Usage = sum(Usage)) %>% + arrange(`Project Type`, desc(Usage)) + +### --- Compute project similarity structure +projectSimilarity <- wdcmProjectCategory %>% + dplyr::select(Project, Category, Usage) %>% + tidyr::spread(key = Category, + value = Usage, + fill = 0) +projectNames <- projectSimilarity$Project +projectSimilarity$Project <- NULL +# - normalize: +projectSimilarity <- t(apply(projectSimilarity, 1, function(x) {x/sum(x)})) +# projectSimilarity[projectSimilarity > 0] <- 1 +projectSimilarity <- as.matrix(parDist(as.matrix(projectSimilarity), method = "kullback")) +rownames(projectSimilarity) <- projectNames +colnames(projectSimilarity) <- projectNames + +### - Determine Constants +# - determine Projects +projects <- wdcmProject$Project +# - determine present Project Types +projectTypes <- unique(wdcmProject$`Project Type`) +# - and assign Brewer colors +lengthProjectColor <- length(unique(wdcmProject$`Project Type`)) +projectTypeColor <- brewer.pal(lengthProjectColor, "Set1") +names(projectTypeColor) <- unique(wdcmProject$`Project Type`) +# - determine Categories +categories <- wdcmCategory$Category +# - totalUsage +totalUsage <- sum(wdcmProject$Usage) +totalProjects <- length(wdcmProject$Project) +totalCategories <- length(wdcmCategory$Category) +totalProjectTypes <- length(wdcmProjectType$`Project Type`) + +### --- prepare search constants for Tabs/Crosstabs +search_projectTypes <- paste("_", projectTypes, sep = "") +unzip_projectTypes <- lapply(projectTypes, function(x) { + wdcmProject$Project[which(wdcmProject$`Project Type` %in% x)] +}) +names(unzip_projectTypes) <- search_projectTypes + +### --- shinyServer +shinyServer(function(input, output, session) { + + ### ---------------------------------- + ### --- BASIC FACTS + ### ---------------------------------- + + ### --- valueBox: totalUsage + # output$totalUsageBox + output$totalUsageBox <- renderValueBox({ + valueBox( + value = as.character(totalUsage), + subtitle = "Total Wikidata Item Usage", + icon = icon("bars", lib = "font-awesome"), + color = "blue" + ) + }) # END output$totalUsageBox + + ### --- valueBox: totalProjects + # output$totalProjectsBox + output$totalProjectsBox <- renderValueBox({ + valueBox( + value = as.character(totalProjects), + subtitle = "Projects Tracked", + icon = icon("bars", lib = "font-awesome"), + color = "blue" + ) + }) # END output$totalProjectsBox + + ### --- valueBox: totalCategories + # output$totalCategoriesBox + output$totalCategoriesBox <- renderValueBox({ + valueBox( + value = as.character(totalCategories), + subtitle = "Semantic Categories", + icon = icon("bars", lib = "font-awesome"), + color = "blue" + ) + }) # END output$totalCategoriesBox + + ### --- valueBox: totalProjectTypes + # output$totalProjectTypesBox + output$totalProjectTypesBox <- renderValueBox({ + valueBox( + value = as.character(totalProjectTypes), + subtitle = "Project Types", + icon = icon("bars", lib = "font-awesome"), + color = "blue" + ) + }) # END output$totalProjectTypesBox + + ### ---------------------------------- + ### --- CATEGORIES OVERVIEW + ### ---------------------------------- + + ### --- SELECT: update select 'categories' + updateSelectizeInput(session, + 'categories', + choices = categories, + selected = categories[round(runif(1, 1, length(categories)))], + server = TRUE) + + ### --- htmlOutput: categoryProjects_overview_Title + output$categoryProjects_overview_Title <- renderText({ + paste("<b>", input$categories, " top 30 projects:</b>") + }) + + ### --- lineplot: categoryProjects_overview + output$categoryProjects_overview <- renderPlot({ + if (!(input$categories == "")) { + plotFrame <- wdcmProjectCategory %>% + select(Project, Category, Usage) %>% + filter(Category %in% input$categories) %>% + arrange(desc(Usage)) + otherSum <- sum(plotFrame$Usage[31:dim(plotFrame)[1]]) + other <- data.frame(Project = 'Other', + Category = input$categories, + Usage = otherSum, + stringsAsFactors = F) + plotFrame <- rbind(plotFrame[1:30, ], other) + plotFrame$Percent <- paste(round(plotFrame$Usage/sum(plotFrame$Usage)*100, 2), + "%", sep = "") + plotFrame$Project <- factor(plotFrame$Project, + levels = plotFrame$Project[order(plotFrame$Usage)]) + ggplot(plotFrame, aes(x = Usage, y = Project)) + + geom_line(size = .35, color = "firebrick", group = 1) + + geom_point(size = 2, color = "firebrick") + + geom_point(size = 1.5, color = "white") + + geom_text_repel(aes(label = plotFrame$Percent), + size = 3) + + xlab("Item Usage") + ylab("Project") + + scale_x_continuous(labels = comma) + + theme_minimal() + + theme(axis.text.x = element_text(angle = 0, size = 9, hjust = 1)) + + theme(axis.title.x = element_text(size = 12)) + + theme(axis.title.y = element_text(size = 12)) %>% + withProgress(message = 'Generating plot', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + } else { + return(NULL) + } + }) + + ### --- htmlOutput: categoryItems_overview_Title + output$categoryItems_overview_Title <- renderText({ + paste("<b>", input$categories, " top 30 Wikidata items:</b>") + }) + + ### --- lineplot: categoryItems_overview + output$categoryItems_overview <- renderPlot({ + if (!(input$categories == "")) { + plotFrame <- wdcmCategoryItem100 %>% + filter(Category %in% input$categories) %>% + arrange(desc(Usage)) + plotFrame <- plotFrame[1:30, ] + plotFrame$Label <- factor(plotFrame$Label, + levels = plotFrame$Label[order(plotFrame$Usage)]) + ggplot(plotFrame, aes(x = Usage, y = Label)) + + geom_line(size = .35, color = "firebrick", group = 1) + + geom_point(size = 2, color = "firebrick") + + geom_point(size = 1.5, color = "white") + + geom_text_repel(aes(label = plotFrame$EntityID), + size = 3) + + xlab("Item Usage") + ylab("Item") + + scale_x_continuous(labels = comma) + + theme_minimal() + + theme(axis.text.x = element_text(angle = 0, size = 9, hjust = 1)) + + theme(axis.title.x = element_text(size = 12)) + + theme(axis.title.y = element_text(size = 12)) %>% + withProgress(message = 'Generating plot', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + } else { + return(NULL) + } + }) + + ### --- lineplot: basicFacts_CategoryLine + output$basicFacts_CategoryLine <- renderPlot({ + plotFrame <- wdcmCategory + plotFrame$Percent <- paste(round(plotFrame$Usage/sum(plotFrame$Usage)*100, 2), + "%", sep = "") + plotFrame$Category <- factor(plotFrame$Category, + levels = plotFrame$Category[order(plotFrame$Usage)]) + ggplot(plotFrame, aes(x = Usage, y = Category)) + + geom_line(size = .35, color = "firebrick", group = 1) + + geom_point(size = 2, color = "firebrick") + + geom_point(size = 1.5, color = "white") + + geom_text_repel(aes(label = plotFrame$Percent), + size = 3) + + xlab("Item Usage") + ylab("Category") + + scale_x_continuous(labels = comma) + + theme_minimal() + + theme(axis.text.x = element_text(angle = 0, size = 9, hjust = 1)) + + theme(axis.title.x = element_text(size = 12)) + + theme(axis.title.y = element_text(size = 12)) %>% + withProgress(message = 'Generating plot', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + }) + + ### --- barplot: basicFacts_ProjectTypeCategory + output$basicFacts_ProjectTypeCategory <- renderPlot({ + ggplot(wdcmProjectTypeCategory, aes(y = log(Usage), x = Category, color = Category, fill = Category)) + + geom_bar(stat = "identity", width = .15) + + facet_wrap(~wdcmProjectTypeCategory$`Project Type`, ncol = 3) + + xlab("Category") + ylab("log(Item Usage)") + + theme_minimal() + + theme(axis.text.x = element_text(angle = 90, size = 9, hjust = 1)) + + theme(axis.title.x = element_text(size = 12)) + + theme(axis.title.y = element_text(size = 12)) + + theme(legend.position = "top") + + theme(strip.background = element_blank()) + + theme(strip.text = element_text(face = "bold")) %>% + withProgress(message = 'Generating plot', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + }) + + ### ---------------------------------- + ### --- PROJECT OVERVIEW + ### ---------------------------------- + + ### --- SELECT: update select 'projects' + updateSelectizeInput(session, + 'projects', + choices = projects, + selected = projects[round(runif(1, 1, length(projects)))], + server = TRUE) + + ### --- barplot: projectOverview_Category + output$projectOverview_Category <- renderPlot({ + plotFrame <- wdcmProjectCategory %>% + filter(Project %in% input$projects) + ggplot(plotFrame, aes(y = Usage, x = Category, color = Category, fill = Category)) + + geom_bar(stat = "identity", width = .15) + + xlab("Category") + ylab("Item Usage") + + scale_y_continuous(labels = comma) + + theme_minimal() + + theme(axis.text.x = element_text(angle = 90, size = 9, hjust = 1)) + + theme(axis.title.x = element_text(size = 12)) + + theme(axis.title.y = element_text(size = 12)) + + theme(legend.position = "top") + + theme(legend.title = element_blank()) + + withProgress(message = 'Generating plot', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + }) + + ### --- htmlOutput: projectOverview_Report + output$projectOverview_Report <- renderText({ + # - project: + project <- input$projects + # - total project rank: + totalRank <- which(wdcmProject$Project %in% input$projects) + # - total projects: + totalProjects <- length(projects) + # - usage volume: + volume <- wdcmProject$Usage[totalRank] + # - percentage of total Wikidata usage: + percVolume <- paste(round(volume/sum(wdcmProject$Usage)*100, 2), "%", sep = "") + # - rank in its `Project Type` + projectType <- wdcmProject$`Project Type`[totalRank] + rankType <- wdcmProject %>% + filter(`Project Type` %in% projectType) %>% + arrange(desc(Usage)) + rankProjectType <- which(rankType$Project %in% project) + # - total projects of this type + totalProjectType <- dim(rankType)[1] + paste("<p align = \"right\"><br><br><br><br>Wikidata usage on <b>", project, "</b>:<br><br>", "<font size = 2><b>", project, "</b> ", " has a total Wikidata usage volume of <b>", + volume, "</b> items (<b>", percVolume, "</b> of total Wikidata usage across the + client projects).<br>In terms of Wikidata usage, it is ranked <b>", totalRank, "/", totalProjects, "</b> among all client projects, and <b>", + rankProjectType, "/", totalProjectType, ".</b> in + its Project Type (<b><i>", projectType, "</i></b>).</font></p>", sep = "") %>% + withProgress(message = 'Generating report', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + }) + + ### --- htmlOutput: projectOverview_relativeRank_Title + output$projectOverview_relativeRank_Title <- renderText({ + paste("<b>", input$projects, " Wikidata usage rank:</b>") + }) + + ### --- barplot: projectOverview_relativeRank + output$projectOverview_relativeRank <- renderPlot({ + if (!(input$projects == "")) { + ix <- which(wdcmProject$Project %in% input$projects) + ixRange <- seq(ix-10, ix+10, by = 1) + ixRange <- ixRange[which(ixRange > 0 & ixRange <= length(wdcmProject$Project))] + plotFrame <- wdcmProject[ixRange, ] + plotFrame$Rank <- ixRange + plotFrame$Color <- rep('cadetblue3', dim(plotFrame)[1]) + plotFrame$Fill <- rep('white', dim(plotFrame)[1]) + plotFrame$Fill[which(plotFrame$Project %in% input$projects)] <- 'cadetblue3' + plotFrame$Project <- factor(plotFrame$Project, + levels = plotFrame$Project[order(-plotFrame$Usage)]) + ggplot(plotFrame, aes(y = Usage, x = Project, color = Color, fill = Fill, label = Rank)) + + geom_bar(stat = "identity", width = .1, color = plotFrame$Color, fill = plotFrame$Fill) + + xlab("Project") + ylab("Item Usage") + + scale_y_continuous(labels = comma) + + geom_label(fill = "cadetblue3", + colour = "white", + fontface = "bold", + position = position_dodge(width = 1), + size = 4) + + theme_minimal() + + theme(legend.position = "none") + + theme(axis.text.x = element_text(angle = 90, size = 9, hjust = 1)) + + theme(axis.title.x = element_text(size = 12)) + + theme(axis.title.y = element_text(size = 12)) %>% + withProgress(message = 'Generating plot', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + } else { + return(NULL) + } + }) + + ### --- htmlOutput: projectOverview_semantics_Title + output$projectOverview_semantics_Title <- renderText({ + paste("<b>", input$projects, " Semantic Neighbourhood:</b>") + }) + + ### --- visNetwork: projectOverview_semantics + # - output$projectOverview_semantics + output$projectOverview_semantics <- renderVisNetwork({ + + if (!(input$projects == "")) { + # - select project + ix <- which(rownames(projectSimilarity) %in% input$projects) + # - select semantic neighbourhood of 15 projects + neighbourhood <- c(names(sort(projectSimilarity[ix, -ix], decreasing = F)[1:20]), + rownames(projectSimilarity)[ix]) + projectsMat <- projectSimilarity[neighbourhood, neighbourhood] + # - find most proximal neighbours + indexMinDist <- sapply(rownames(projectsMat), function(x) { + w <- which(rownames(projectsMat) %in% x) + y <- sort(projectsMat[w, -w], decreasing = T) + names(y)[length(y)] + }) + id <- 1:length(colnames(projectsMat)) + label <- colnames(projectsMat) + ncolor <- rep("grey", length(colnames(projectsMat))) + w <- which(colnames(projectsMat) %in% input$projects) + ncolor[w] <- "cadetblue" + nodes <- data.frame(id = id, + label = label, + color = ncolor, + stringsAsFactors = F) + conceptsStruct <- data.frame(from = names(indexMinDist), + to = unname(indexMinDist), + stringsAsFactors = F) + conceptsStruct$from <- sapply(conceptsStruct$from, function(x) { + nodes$id[which(nodes$label %in% x)] + }) + conceptsStruct$to <- sapply(conceptsStruct$to, function(x) { + nodes$id[which(nodes$label %in% x)] + }) + conceptsStruct$arrows <- rep("to", length(conceptsStruct$to)) + visNetwork(nodes = nodes, + edges = conceptsStruct, + width = "100%", + height = "100%") %>% + visEvents(type = "once", + startStabilizing = "function() {this.moveTo({scale:0.5})}") %>% + visPhysics(stabilization = FALSE) %>% + withProgress(message = 'Generating plot', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + } else { + return(NULL) + } + }) + + ### --- htmlOutput: projectOverview_topItems_Title + output$projectOverview_topItems_Title <- renderText({ + paste("<b>", input$projects, " top 30 Wikidata items:</b>") + }) + + ### --- lineplot: projectOverview_topItems + output$projectOverview_topItems <- renderPlot({ + if (!(input$projects == "")) { + plotFrame <- wdcmProjectItem100 %>% + filter(Project %in% input$projects) %>% + arrange(desc(Usage)) + w <- which(!duplicated(plotFrame$Label)) + plotFrame <- plotFrame[w, ] + plotFrame <- plotFrame[1:30, ] + plotFrame$Label <- factor(plotFrame$Label, + levels = plotFrame$Label[order(plotFrame$Usage)]) + ggplot(plotFrame, aes(x = Usage, y = Label)) + + geom_line(size = .35, color = "darkblue", group = 1) + + geom_point(size = 2, color = "darkblue") + + geom_point(size = 1.5, color = "white") + + geom_text_repel(aes(label = plotFrame$EntityID), + size = 3) + + xlab("Item Usage") + ylab("Item") + + scale_x_continuous(labels = comma) + + theme_minimal() + + theme(axis.text.x = element_text(angle = 0, size = 9, hjust = 1)) + + theme(axis.title.x = element_text(size = 12)) + + theme(axis.title.y = element_text(size = 12)) %>% + withProgress(message = 'Generating plot', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + } else { + return(NULL) + } + }) + + ### ---------------------------------- + ### --- TABS AND CROSSTABS + ### ---------------------------------- + + ### --- SELECT: update select 'selectProject' + updateSelectizeInput(session, + 'selectProject', + choices = c(projects, paste("_", projectTypes, sep = "")), + selected = c("_Wikipedia", "_Wikinews", "_Wiktionary"), + server = TRUE) + + ### --- SELECT: update select 'selectCategories' + updateSelectizeInput(session, + 'selectCategories', + choices = categories, + selected = categories[round(runif(6, 1, length(categories)))], + server = TRUE) + + tabsDataset <- reactive({ + ### --- selected projects: + selectedProjects <- character() + wUnzip <- which(names(unzip_projectTypes) %in% input$selectProject) + if (length(wUnzip > 0)) { + selectedProjects <- unname(do.call(c, unzip_projectTypes[wUnzip])) + } + wSel <- which(projects %in% input$selectProject) + if (length(wSel > 0)) { + selectedProjects <- c(selectedProjects, projects[wSel]) + } + selectedProjects <- unique(selectedProjects) + output$testSelectedProjects <- renderText({ + paste(selectedProjects, collapse = ", ", sep = "") + }) + ### --- selected categories: + selectedCategories <- input$selectCategories + ### --- output + out <- wdcmProjectCategory %>% + filter(Project %in% selectedProjects & Category %in% selectedCategories) + out + }) + + ### --- OBSERVE: input$applySelection + observeEvent(input$applySelection, { + + #### --- Chart: tabulations_projectsChart + output$tabulations_projectsChart <- renderPlot({ + # - Chart Frame for output$tabulations_projectsChart + plotFrame <- isolate(tabsDataset()) %>% + group_by(Project) %>% + summarise(Usage = sum(Usage)) %>% + arrange(desc(Usage)) + # - top 25 projects: + if (dim(plotFrame)[1] >= 25) { + plotFrame <- plotFrame[1:25, ] + } + plotFrame$Project <- factor(plotFrame$Project, + levels = plotFrame$Project[order(-plotFrame$Usage)]) + # - express labels as K, M: + plotFrame$Label <- sapply(plotFrame$Usage, function(x) { + if (x >= 1e+03 & x < 1e+06) { + out <- paste(round(x/1e+03, 1), "K", sep = "") + } else if (x > 1e+06) { + out <- paste(round(x/1e+06, 1), "M", sep = "") + } else { + out <- as.character(x) + } + return(out) + }) + # - Plot + ggplot(plotFrame, + aes(x = Project, y = Usage, label = Label)) + + geom_bar(stat = "identity", width = .6, fill = "#4c8cff") + + xlab('Projects') + ylab('Entity Usage') + + ylim(0, max(plotFrame$Usage) + .1*max(plotFrame$Usage)) + + scale_y_continuous(labels = comma) + + geom_label(size = 3, vjust = -.1) + + theme_minimal() + + theme(axis.text.x = element_text(angle = 90, size = 12, hjust = 1)) + + theme(axis.title.x = element_text(size = 12)) + + theme(axis.title.y = element_text(size = 12)) + + theme(plot.title = element_text(size = 15)) %>% + withProgress(message = 'Generating plot', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + }) + # - Download Frame: tabulations_projectsChart + tabulations_projectsDownload_Frame <- reactive({ + plotFrame <- isolate(tabsDataset()) %>% + group_by(Project) %>% + summarise(Usage = sum(Usage)) %>% + arrange(desc(Usage)) + plotFrame + }) + # - Download: tabulations_projectsChart + output$tabulations_projectsDownload_Frame <- downloadHandler( + filename = function() { + 'WDCM_Data.csv'}, + content = function(file) { + write.csv(tabulations_projectsDownload_Frame(), + file, + quote = FALSE, + row.names = FALSE) + }, + contentType = "text/csv" + ) + + #### --- Chart: tabulations_categoriesChart + output$tabulations_categoriesChart <- renderPlot({ + # - Chart Frame for output$tabulations_categoriesChart + plotFrame <- isolate(tabsDataset()) %>% + group_by(Category) %>% + summarise(Usage = sum(Usage)) %>% + arrange(desc(Usage)) + # - top 25 categories: + if (dim(plotFrame)[1] > 25) { + plotFrame <- plotFrame[1:25, ] + } + plotFrame$Category <- factor(plotFrame$Category, + levels = plotFrame$Category[order(-plotFrame$Usage)]) + # - express labels as K, M: + plotFrame$Label <- sapply(plotFrame$Usage, function(x) { + if (x >= 1e+03 & x < 1e+06) { + out <- paste(round(x/1e+03, 1), "K", sep = "") + } else if (x > 1e+06) { + out <- paste(round(x/1e+06, 1), "M", sep = "") + } else { + out <- as.character(x) + } + return(out) + }) + # - Plot + ggplot(plotFrame, + aes(x = Category, y = Usage, label = Label)) + + geom_bar(stat = "identity", width = .6, fill = "#4c8cff") + + xlab('Category') + ylab('Entity Usage') + + ylim(0, max(plotFrame$Usage) + .1*max(plotFrame$Usage)) + + scale_y_continuous(labels = comma) + + geom_label(size = 3, vjust = -.1) + + theme_minimal() + + theme(axis.text.x = element_text(angle = 90, size = 12, hjust = 1)) + + theme(axis.title.x = element_text(size = 12)) + + theme(axis.title.y = element_text(size = 12)) + + theme(plot.title = element_text(size = 15)) %>% + withProgress(message = 'Generating plot', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + }) + # - Download Frame: tabulations_categoriesChart + tabulations_categoriesDownload_Frame <- reactive({ + plotFrame <- isolate(tabsDataset()) %>% + group_by(Category) %>% + summarise(Usage = sum(Usage)) %>% + arrange(desc(Usage)) + plotFrame + }) + # - Download: tabulations_categoriesChart + output$tabulations_categoriesDownload_Frame <- downloadHandler( + filename = function() { + 'WDCM_Data.csv'}, + content = function(file) { + write.csv(tabulations_categoriesDownload_Frame(), + file, + quote = FALSE, + row.names = FALSE) + }, + contentType = "text/csv" + ) + + #### --- Chart: tabulations_projectTypesChart + output$tabulations_projectTypesChart <- renderPlot({ + # - Chart Frame for output$tabulations_projectTypesChart + plotFrame <- isolate(tabsDataset()) %>% + group_by(`Project Type`) %>% + summarise(Usage = sum(Usage)) %>% + arrange(desc(Usage)) + # - top 25 categories: + if (dim(plotFrame)[1] > 25) { + plotFrame <- plotFrame[1:25, ] + } + plotFrame$`Project Type` <- factor(plotFrame$`Project Type`, + levels = plotFrame$`Project Type`[order(-plotFrame$Usage)]) + # - express labels as K, M: + plotFrame$Label <- sapply(plotFrame$Usage, function(x) { + if (x >= 1e+03 & x < 1e+06) { + out <- paste(round(x/1e+03, 1), "K", sep = "") + } else if (x > 1e+06) { + out <- paste(round(x/1e+06, 1), "M", sep = "") + } else { + out <- as.character(x) + } + return(out) + }) + # - Plot + ggplot(plotFrame, + aes(x = `Project Type`, y = Usage, label = Label)) + + geom_bar(stat = "identity", width = .6, fill = "#4c8cff") + + xlab('Project Type') + ylab('Entity Usage') + + ylim(0, max(plotFrame$Usage) + .1*max(plotFrame$Usage)) + + scale_y_continuous(labels = comma) + + geom_label(size = 3, vjust = -.1) + + theme_minimal() + + theme(axis.text.x = element_text(angle = 90, size = 12, hjust = 1)) + + theme(axis.title.x = element_text(size = 12)) + + theme(axis.title.y = element_text(size = 12)) + + theme(plot.title = element_text(size = 15)) %>% + withProgress(message = 'Generating plot', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + }) + # - Download Frame: tabulations_projectTypesChart + tabulations_projectTypesChartDownload_Frame <- reactive({ + plotFrame <- isolate(tabsDataset()) %>% + group_by(`Project Type`) %>% + summarise(Usage = sum(Usage)) %>% + arrange(desc(Usage)) + plotFrame + }) + # - Download: tabulations_projectTypesChart + output$tabulations_projectTypesChart_Frame <- downloadHandler( + filename = function() { + 'WDCM_Data.csv'}, + content = function(file) { + write.csv(tabulations_projectTypesChartDownload_Frame(), + file, + quote = FALSE, + row.names = FALSE) + }, + contentType = "text/csv" + ) + + #### --- Chart: crosstabulations_projectsCategoriesChart + output$crosstabulations_projectsCategoriesChart <- renderPlot({ + # - Chart Frame for output$crosstabulations_projectsCategoriessChart + plotFrame <- isolate(tabsDataset()) %>% + arrange(desc(Usage)) + projectOrder <- plotFrame %>% + group_by(Project) %>% + summarise(Usage = sum(Usage)) %>% + arrange(desc(Usage)) + selProj <- projectOrder$Project[1:25] + plotFrame <- plotFrame %>% + filter(Project %in% selProj) + # - express labels as K, M: + plotFrame$Label <- sapply(plotFrame$Usage, function(x) { + if (x >= 1e+03 & x < 1e+06) { + out <- paste(round(x/1e+03, 1), "K", sep = "") + } else if (x > 1e+06) { + out <- paste(round(x/1e+06, 1), "M", sep = "") + } else { + out <- as.character(x) + } + return(out) + }) + plotFrame$Project <- factor(plotFrame$Project, + levels = selProj) + # - Plot + ggplot(plotFrame, + aes(x = Project, y = Usage, label = Label)) + + geom_line(size = .25, color = "#4c8cff", group = 1) + + geom_point(size = 1.5, color = "#4c8cff") + + geom_point(size = 1, color = "white") + + geom_text_repel(data = plotFrame, + aes(x = Project, y = Usage, label = Label), + size = 3) + + facet_wrap(~ Category, ncol = 3, scales = "free_y") + + xlab('Project') + ylab('Entity Usage') + + scale_y_continuous(labels = comma) + + theme_minimal() + + theme(axis.text.x = element_text(angle = 90, size = 12, hjust = 1)) + + theme(axis.title.x = element_text(size = 12)) + + theme(axis.title.y = element_text(size = 12)) + + theme(plot.title = element_text(size = 15)) %>% + withProgress(message = 'Generating plot', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + }) + # - Download Frame: crosstabulations_projectsCategoriesChart + crosstabulations_projectsCategoriesChartDownload_Frame <- reactive({ + plotFrame <- isolate(tabsDataset()) %>% + arrange(desc(Usage)) + plotFrame + }) + # - Download: crosstabulations_projectsCategoriesFrame + output$crosstabulations_projectsCategoriesFrame <- downloadHandler( + filename = function() { + 'WDCM_Data.csv'}, + content = function(file) { + write.csv(crosstabulations_projectsCategoriesChartDownload_Frame(), + file, + quote = FALSE, + row.names = FALSE) + }, + contentType = "text/csv" + ) + + #### --- Chart: crosstabulations_projectTypesCategoriesChart + output$crosstabulations_projectTypesCategoriesChart <- renderPlot({ + # - Chart Frame for output$crosstabulations_projectTypesCategoriesChart + plotFrame <- isolate(tabsDataset()) %>% + group_by(`Project Type`, Category) %>% + summarise(Usage = sum(Usage)) %>% + arrange(desc(Usage)) + projectTypeOrder <- plotFrame %>% + group_by(`Project Type`) %>% + summarise(Usage = sum(Usage)) %>% + arrange(desc(Usage)) + plotFrame$`Project Type` <- factor(plotFrame$`Project Type`, + levels = projectTypeOrder$`Project Type`) + # - express labels as K, M: + plotFrame$Label <- sapply(plotFrame$Usage, function(x) { + if (x >= 1e+03 & x < 1e+06) { + out <- paste(round(x/1e+03, 1), "K", sep = "") + } else if (x > 1e+06) { + out <- paste(round(x/1e+06, 1), "M", sep = "") + } else { + out <- as.character(x) + } + return(out) + }) + # - Plot + ggplot(plotFrame, + aes(x = `Project Type`, y = Usage, label = Label)) + + geom_line(size = .25, color = "#4c8cff", group = 1) + + geom_point(size = 1.5, color = "#4c8cff") + + geom_point(size = 1, color = "white") + + geom_text_repel(data = plotFrame, + aes(x = `Project Type`, y = Usage, label = Label), + size = 3) + + facet_wrap(~ Category, ncol = 3, scales = "free_y") + + xlab('Project Type') + ylab('Entity Usage') + + ylim(0, max(plotFrame$Usage) + .5*max(plotFrame$Usage)) + + scale_y_continuous(labels = comma) + + theme_minimal() + + theme(axis.text.x = element_text(angle = 90, size = 12, hjust = 1)) + + theme(axis.title.x = element_text(size = 12)) + + theme(axis.title.y = element_text(size = 12)) + + theme(plot.title = element_text(size = 15)) %>% + withProgress(message = 'Generating plot', + min = 0, + max = 1, + value = 1, {incProgress(amount = 0)}) + }) + # - Download Frame: crosstabulations_projectTypeCategoriesChart + crosstabulations_projectTypeCategoriesChartDownload_Frame <- reactive({ + plotFrame <- isolate(tabsDataset()) %>% + group_by(`Project Type`, Category) %>% + summarise(Usage = sum(Usage)) %>% + arrange(desc(Usage)) + plotFrame + }) + # - Download: crosstabulations_projectTypeCategoriesChartFrame + output$crosstabulations_projectTypeCategoriesChartFrame <- downloadHandler( + filename = function() { + 'WDCM_Data.csv'}, + content = function(file) { + write.csv(crosstabulations_projectTypeCategoriesChartDownload_Frame(), + file, + quote = FALSE, + row.names = FALSE) + }, + contentType = "text/csv" + ) + + }, ignoreNULL = FALSE) + + + + ### ---------------------------------- + ### --- TABLES + ### ---------------------------------- + + ### --- output$projectTable + output$projectTable <- DT::renderDataTable({ + datatable(wdcmProject, + options = list( + pageLength = 20, + width = '100%', + columnDefs = list(list(className = 'dt-center', targets = "_all")) + ), + rownames = FALSE + ) + }) %>% withProgress(message = 'Generating data', + min = 0, + max = 1, + value = 1, {incProgress(amount = 1)}) + + ### --- output$CategoryTable + output$CategoryTable <- DT::renderDataTable({ + datatable(wdcmCategory, + options = list( + pageLength = 20, + width = '100%', + columnDefs = list(list(className = 'dt-center', targets = "_all")) + ), + rownames = FALSE + ) + }) %>% withProgress(message = 'Generating data', + min = 0, + max = 1, + value = 1, {incProgress(amount = 1)}) + + ### --- output$projectCategoryDataTable + output$projectCategoryDataTable <- DT::renderDataTable({ + datatable(wdcmProjectCategory, + options = list( + pageLength = 20, + width = '100%', + columnDefs = list(list(className = 'dt-center', targets = "_all")) + ), + rownames = FALSE + ) + }) %>% withProgress(message = 'Generating data', + min = 0, + max = 1, + value = 1, {incProgress(amount = 1)}) + + ### --- output$projectType + output$projectType <- DT::renderDataTable({ + datatable(wdcmProjectType, + options = list( + pageLength = 20, + width = '100%', + columnDefs = list(list(className = 'dt-center', targets = "_all")) + ), + rownames = FALSE + ) + }) %>% withProgress(message = 'Generating data', + min = 0, + max = 1, + value = 1, {incProgress(amount = 1)}) + + ### --- output$projectTypeCategory + output$projectTypeCategory <- DT::renderDataTable({ + datatable(wdcmProjectTypeCategory, + options = list( + pageLength = 20, + width = '100%', + columnDefs = list(list(className = 'dt-center', targets = "_all")) + ), + rownames = FALSE + ) + }) %>% withProgress(message = 'Generating data', + min = 0, + max = 1, + value = 1, {incProgress(amount = 1)}) + + +}) +### --- END shinyServer + + + + diff --git a/ui.R b/ui.R new file mode 100644 index 0000000..8a8221b --- /dev/null +++ b/ui.R @@ -0,0 +1,555 @@ +### --------------------------------------------------------------------------- +### --- WDCM Usage Dashboard, v. Beta 0.1 +### --- Script: ui.R, v. Beta 0.1 +### --------------------------------------------------------------------------- + +### --- Setup +rm(list = ls()) +### --- general +library(shiny) +library(shinydashboard) +library(shinycssloaders) +### --- outputs +library(visNetwork) +library(rbokeh) +library(networkD3) +library(DT) + +# - options +options(warn = -1) + +shinyUI( + + fluidPage(title = 'WDCM Projects', + theme = NULL, + + # - fluidRow Title + fluidRow( + column(width = 12, + h2('WDCM Usage Dashboard'), + HTML('<font size="3"><b>Wikidata Concepts Monitor</b></font>') + + ) + ), # - fluidRow Title END + + # - fluidRow Logo + fluidRow( + column(width = 12, + img(src='Wikidata-logo-en.png', + align = "left") + ) + ), # - fluidRow END + + # - hr() + fluidRow( + column(width = 12, + hr() + ) + ), + + # - fluidRow Boxes + fluidRow( + column(width = 12, + tabBox(id = 'MainBox', + selected = 'Dahsboard', + title = '', + width = 12, + height = NULL, + side = 'left', + + # - tabPanel Dahsboard + tabPanel("Dahsboard", + fluidRow( + column(width = 12, + hr(), + tabBox(width = 12, + title = '', + id = "Usage", + selected = "Usage", + tabPanel(title = "Usage", + id = "usage", + fluidRow( + column(width = 6, + br(), + HTML('<font size=2><b>Note:</b> This page follows a columnar organization: <i>Basic Facts</i> and <i>Categories</i> to the left, and <i>Projects</i> to the right. + The Dashboard will initialize a random choice of <i>Category</i> and <i>Project</i> in the <b>Category Report</b> and <b>Project Report</b> areas, + respectively. Use the selection and search fields to select a category or a project that you want to generate a Report + for.</font>') + ) + ), + # - fluidRow: ValueBoxes + fluidRow( + + column(width = 6, + fluidRow( + column(width = 12, + fluidRow( + column(width = 12, + h3('Basic Facts'), + HTML('The total Wikidata item usage, how many sister projects have a client-side Wikidata usage tracking enabled, + how many Wikidata semantic categories of items are encompassed by this analysis, and how many different + Project Types.') + ) + ), + fluidRow( + column(width = 3, + withSpinner(infoBoxOutput("totalUsageBox", width = 12), size = .5) + ), + column(width = 3, + withSpinner(valueBoxOutput("totalProjectsBox", width = 12), size = .5) + ), + column(width = 3, + withSpinner(valueBoxOutput("totalCategoriesBox", width = 12), size = .5) + ), + column(width = 3, + withSpinner(valueBoxOutput("totalProjectTypesBox", width = 12), size = .5) + ) + ), + br(), br() + ) + ), + fluidRow( + column(width = 12, + hr(), + h3('Category Report'), + HTML('Wikidata usage overview for a specific category, including the distribution of usage in category accross projects + and the top Wikidata items per category.'), + br(), br(), + selectizeInput('categories', + 'Select category:', + choices = NULL, + multiple = FALSE + ), + br(), br(), + fluidRow( + column(width = 12, + htmlOutput('categoryProjects_overview_Title'), + br(), br(), + withSpinner(plotOutput('categoryProjects_overview', + width = "700px", + height = "450px") + ) + ) + ), + fluidRow( + column(width = 12, + br(), br(), + htmlOutput('categoryItems_overview_Title'), + HTML("<font size = 2><b>Note: </b>In the absence of English item label the Wikidata item ID + is used in place of it.</font>"), + br(), br(), + withSpinner(plotOutput('categoryItems_overview', + width = "700px", + height = "600px") + ) + ) + ) + ) + ), + fluidRow( + column(width = 12, + hr(), + h3('Categories General Overview'), + HTML('<b>Wikidata item usage per semantic category</b><br> + <font size="2"><b>Note:</b> The current selection of semantic categories does not + encompass all Wikidata items.</font>'), + br(), br(), + withSpinner(plotOutput('basicFacts_CategoryLine', + width = "700px", + height = "500px") + ) + ) + ), + fluidRow( + column(width = 12, + br(), br(), + HTML('<b>Wikidata item usage per semantic category in each project type</b><br> + <font size="2"><b>Note:</b> Item usage count is given on a logarithmic scale.</font>'), + br(), br(), + withSpinner(plotOutput('basicFacts_ProjectTypeCategory', + width = "700px", + height = "900px") + ) + ) + ) + ), + + column(width = 6, + fluidRow( + column(width = 12, + fluidRow( + column(width = 12, + h3('Project Report'), + HTML('Wikidata usage overview for a specific project, including: the distribution of usage in Wikidata semantic categories, + total Wikidata usage volume, similar projects, and the top Wikidata items.'), + br(), br(), + selectizeInput('projects', + 'Search projects:', + choices = NULL, + multiple = FALSE + ), + br(), br(), + fluidRow( + column(width = 4, + withSpinner(htmlOutput('projectOverview_Report')) + ), + column(width = 8, + withSpinner(plotOutput('projectOverview_Category', + width = "550px", + height = "450px") + ) + ) + ), + fluidRow( + column(width = 12, + br(), br(), + htmlOutput('projectOverview_relativeRank_Title'), + br(), br(), + withSpinner(plotOutput('projectOverview_relativeRank', + width = "800px", + height = "350px") + ) + ) + ), + fluidRow( + column(width = 12, + br(), br(), + htmlOutput('projectOverview_semantics_Title'), + HTML("<font size = 2><b>Note: </b>We study the distribution of Wikidata usage across the semantic categories to + determine which client projects use Wikidata in a similar way. In this graph, each project points towards the one + most similar to it. The selected projects has a different color. The results are relevant only in the context + of the current selection: the selected project + its 20 nearest semantic neighboors.</font>"), + withSpinner(visNetwork::visNetworkOutput('projectOverview_semantics', + height = 500)) + ) + + ), + fluidRow( + column(width = 12, + br(), br(), + htmlOutput('projectOverview_topItems_Title'), + HTML("<font size = 2><b>Note: </b>In the absence of English item label the Wikidata item ID + is used in place of it.</font>"), + br(), br(), + withSpinner(plotOutput('projectOverview_topItems', + width = "700px", + height = "600px") + ) + ) + ) + ) + ) + ) + ) + ) + ) + + ), # - tabPanel BasicFacts END + + tabPanel(title = "Tabs/Crosstabs", + id = "tabs", + fluidRow( + column(width = 12, + fluidRow( + column(width = 6, + br(), + HTML('<font size = 2>Here you can make <b>selections</b> of client projects and semantic categories to learn about Wikidata + usage across them.<br> <b>Note:</b> You can search and add projects into the <i>Search projects</i> field by + using (a) <b>project names</b> (e.g. <i>enwiki</i>, <i>dewiki</i>, <i>sawikiquote</i>, and similar or (b) by using + <b>project types</b> that start with <b>"_"</b> (underscore, e.g. <i>_Wikipedia</i>, <i>_Wikisource</i>, <i>_Commons</i>, and + similar; try typing anything into the Select projects field that starts with an underscore). Please note that by selecting + a project type (again: <i>_Wikipedia</i>, <i>_Wikiquote</i>, and similar) you are selecting <b>all</b> client + projects of the respective type, and that\'s potentially a lot of data. The Dashboard will pick unique + projects from whatever you have inserted into the Search projects field. The selection of projects will be intesected + with the selection of semantic categories from the Select categories field, and the obtained results will refer only + to the Wikidata items from the current selection of client projects <i>and</i> semantic categories. + In other words: <i>disjunction</i> operates inside the two search fields, while <i>conjunction</i> operates + across the two search fields.<br> <b>Note:</b> The Dashboard will initialize a choice of three project types + (<i>Wikipedia</i>, <i>Wikinews</i>, and <i>Wiktionary</i>) and a random choice of six semantic categories. All charts will present at + most 25 top projects in respect to the Wikidata usage and relative to the current selection; however, <b>complete + selection data sets</b> are available for download (<i>.csv</i>) beneath each chart.</font>'), + br(), br() + ) + ), + fluidRow( + column(width = 3, + selectizeInput('selectProject', + 'Search projects:', + choices = NULL, + multiple = TRUE) + ), + column(width = 3, + selectizeInput('selectCategories', + 'Search categories:', + choices = NULL, + multiple = TRUE) + ) + ), + fluidRow( + column(width = 2, + actionButton('applySelection', + label = "Apply Selection", + width = '70%', + icon = icon("database", + class = NULL, + lib = "font-awesome") + ) + ) + ), + fluidRow( + column(width = 12, + hr() + ) + ), + fluidRow( + column(width = 6, + h4('Projects'), + withSpinner(plotOutput('tabulations_projectsChart', + height = "600px")), + downloadButton('tabulations_projectsDownload_Frame', + 'Data (csv)') + ), + column(width = 6, + h4('Categories'), + withSpinner(plotOutput('tabulations_categoriesChart', + height = "600px")), + downloadButton('tabulations_categoriesDownload_Frame', + 'Data (csv)') + ) + ), + fluidRow( + column(width = 12, + hr() + ) + ), + fluidRow( + column(width = 6, + h4('Project Types'), + withSpinner(plotOutput('tabulations_projectTypesChart', + height = "600px")), + downloadButton('tabulations_projectTypesChart_Frame', + 'Data (csv)') + ), + column(width = 6 + ) + ), + fluidRow( + column(width = 12, + hr() + ) + ), + fluidRow( + column(width = 12, + h4('Project vs Categories'), + withSpinner(plotOutput('crosstabulations_projectsCategoriesChart', + height = "850px")), + downloadButton('crosstabulations_projectsCategoriesFrame', + 'Data (csv)') + ) + ), + fluidRow( + column(width = 12, + hr() + ) + ), + fluidRow( + column(width = 12, + h4('Project Types vs Categories'), + withSpinner(plotOutput('crosstabulations_projectTypesCategoriesChart', + height = "850px")), + downloadButton('crosstabulations_projectTypeCategoriesChartFrame', + 'Data (csv)') + ) + ) + ) + ), + fluidRow( + column(width = 12, + hr() + ) + ) + ), # - tabPanel Tabs/Crosstabs END + + tabPanel(title = "Tables", + id = "tables", + fluidRow( + column(width = 6, + br(), + HTML('<font size = 2>Here you can access <b> some tabulated and cross-tabulated raw data</b> on Wikidata usage. <br> + All tables can be searched and sorted by any of the respective columns.</font>'), + br(), br() + ) + ), + fluidRow( + column(width = 4, + HTML('<font size = 2><b>Table A. Project Totals.</b></font>'), + br(), br(), + withSpinner(DT::dataTableOutput('projectTable', width = "100%")) + ), + column(width = 4, + HTML('<font size = 2><b>Table B. Category Totals.</b></font>'), + br(), br(), + withSpinner(DT::dataTableOutput('CategoryTable', width = "100%")) + ), + column(width = 4, + HTML('<font size = 2><b>Table C. Project vs Category Cross-Tabulation.</b></font>'), + br(), br(), + withSpinner(DT::dataTableOutput('projectCategoryDataTable', width = "100%")) + ) + ), + fluidRow( + column(width = 12, + hr() + ) + ), + fluidRow( + column(width = 4, + HTML('<font size = 2><b>Table D. Project Type Totals.</b></font>'), + br(), br(), + withSpinner(DT::dataTableOutput('projectType', width = "100%")) + ), + column(width = 6, + HTML('<font size = 2><b>Table E. Project Type vs Category Cross-Tabulation.</b></font>'), + br(), br(), + withSpinner(DT::dataTableOutput('projectTypeCategory', width = "100%")) + ) + ) + ) + ) # - tabBox: Wikidata Usage END + ) + ) + + ), # - tabPanel Dashboard END + + # - tabPanel Description + tabPanel("Description", + fluidRow( + column(width = 8, + HTML('<h2>WDCM Usage Dashboard</h2> + <h4>Description<h4> + <hr> + <h4>Introduction<h4> + <br> + <p><font size = 2>This Dashboard is a part of the <b>Wikidata Concepts Monitor (WDMC)</b>. The WDCM system provides analytics on Wikidata usage + across the Wikimedia sister projects. The WDCM Usage Dashboard focuses on providing the detailed statistics on Wikidata usage in particular sister projects or + the selected subsets of them. Three pages that present analytical results in this Dashboard receive a description here: (1) <b><i>Usage</i></b>, (2) <b><i>Tabs/Crosstabs</i></b>, + and (3) <b><i>Tables</i></b>. But first, definitions.</font></p> + <hr> + <h4>Definitions</h4> + <br> + <p><font size = 2><b>N.B.</b> The current <b>Wikidata item usage statistic</b> definition is <i>the count of the number of pages in a particular client project + where the respective Wikidata item is used</i>. Thus, the current definition ignores the usage aspects completely. This definition is motivated by the currently + present constraints in Wikidata usage tracking across the client projects + (see <a href = "https://www.mediawiki.org/wiki/Wikibase/Schema/wbc_entity_usage" target = "_blank">Wikibase/Schema/wbc entity usage</a>). + With more mature Wikidata usage tracking systems, the definition will become a subject + of change. The term <b>Wikidata usage volume</b> is reserved for total Wikidata usage (i.e. the sum of usage statistics) in a particular + client project, group of client projects, or semantic categories. By a <b>Wikidata semantic category</b> we mean a selection of Wikidata items that is + that is operationally defined by a respective SPARQL query, returning a selection of items that intuitivelly match a human, natural semantic category. + The structure of Wikidata does not necessarily match any intuitive human semantics. In WDCM, an effort is made to select the semantic categories so to match + the intuitive, everyday semantics as much as possible, in order to assist anyone involved in analytical work with this system. However, the choice of semantic + categories in WDCM is not necessarily exhaustive (i.e. they do not necessarily cover all Wikidata items), neither the categories are necessarily + mutually exclusive. The Wikidata ontology is very complex and a product of work of many people, so there is an optimization price to be paid in every attempt to + adapt or simplify its present structure to the needs of a statistical analytical system such as WDCM. The current set of WDCM semantic categories is thus not + normative in any sense and a subject of change in any moment, depending upon the analytical needs of the community.</font></p> + <p><font size = 2>The currently used <b>WDCM Taxonomy</b> of Wikidata items encompasses the following 14 semantic categories: <i>Geographical Object</i>, <i>Organization</i>, <i>Architectural Structure</i>, + <i>Human</i>, <i>Wikimedia</i>, <i>Work of Art</i>, <i>Book</i>, <i>Gene</i>, <i>Scientific Article</i>, <i>Chemical Entities</i>, <i>Astronomical Object</i>, <i>Thoroughfare</i>, <i>Event</i>, + and <i>Taxon</i>.</font></p> + <hr> + <h4>Usage</h4> + <br> + <p><font size = 2>The Usage tab provides elementary statistics on Wikidata usage across the semantic categories (left column) and sister projects + (right column).<br> + <b><i>To the left</b></i>, we first encounter a general overview of <i>Basic Facts</i>: the number of Wikidata items that are encompassed by the current WDCM taxonomy (in effect, + this is the number of items that are encompassed by all WDCM analyses), the number of sister projects that have client-side Wikidata usage tracking enabled (currently, + that means that the <a href = "https://www.mediawiki.org/wiki/Wikibase/Schema/wbc_entity_usage" target = "_blank">Wikibase/Schema/wbc entity usage</a>) is present there), + the number of semantic categories in the current version of the WDCM Taxonomy, and the number of different sister project types (e.g. <i>Wikipedia</i>, <i>Wikinews</i>, etc). + <br> + The <b>Category Report</b> subsection allows you to select a specific semantic category and generate two charts beneath the selection: (a) the category top 30 projects chart, and + (b) the category top 30 Wikidata items chart. The first chart will display 30 sister projects that use Wikidata items from this semantic category the most, with the usage data + represented on the horizontal axis, and the project labels on the vertical axis. The percentages next to the data points in this chart refer to the proportion of total category usage + that takes place in the respective project. The next chart will display the 30 most popular items from the selected semantic category: item usage is again placed on the horizontal axis, + item labels are on the vertical axis, and item IDs are placed next to the data points themselves. + <br> + The <b>Categories General Overview</b> subsection is static and allows no selection; it introduces two concise overviews of Wikidata usage across the semantic categories of + Wikidata items. The <i>Wikidata Usage per Semantic Cateory</i> chart provides semantic categories on the vertical and item usage statistics on the horizontal axis; the percentages + tells us about the proportion of total Wikidata usage that the respective semantic category carries. Beneath, the <i>Wikidata item usage per semantic category in each project type</i> + provides a cross-tabulation of semantic categories vs. sister project types. The categories are color-coded and represented on the horizontal axes, while each chart represents one project + type. The usage scale, represented on the vertical axes, is logarithmic to ease the comparison and enable practical data visualization. + <br> + <b><i>To the right</b></i>, an opportunity to inspect Wikidata usage in a single Wikimedia project is provided. The <b>Project Report</b> section allows you to select a single Wikimedia + project and obtain results on it. The first section that will be generated upon making a selection provides a concise narrative summary of Wikidata usage in the selected project alongside + a chart presenting an overview of Wikidata usage per semantic category. The next chart, <i>Wikidata usage rank</i>, show the rank position of the selected project among other sister projects + in respect to the Wikidata usage volume. Beneath, a more complex structure, <i>Semantic Neighbourhood</i>, is given. In this network, or a directed graph if you prefere, each project points + towards the one most similar to it. The selected projects has a different color. The results are relevant only in the context of the current selection: the selected project and its 20 nearest + semantic neighboors only are presented. Once again: each project points to the one which utilizes Wikidata in a way most similar to it. The <i>top 30 Wikidata items</i> chart presents the top 30 + Wikidata items in the selected project: item labels are given on the vertical axis, Wikidata usage on the horizontal axis, and the item IDs are labeled close to the data points themselves. + </font></p> + <hr> + <h4>Tabs/Crosstabs</h4> + <br> + <p><font size = 2> + Here we have the most direct opportunity to study the Wikidata usage statistics across the sister projects. A selection of projects and semantic categories will be intersected and only results in + the scope of the intersection will be returned. The charts should be self-explanatory: the usage statistic is always represented by the vertical axis, while the horizontal axis and sub-panels play + various roles in the context of whether a category vs project or a category vs project type crosstabulation is provided. Data points are labeled in million (M) or thousand (K) pages (see Wikidata usage) + definition above). While charts can display a limited number of data points only, relative to the size of the selection, each of them is accompanied by a <b>Data (csv)</b> button that will initiate a + download of the full respective data set as a comma separated file. + </font></p> + <hr> + <h4>Tables</h4> + <br> + <p><font size = 2>The section presents searchable and sortable tables and crosstabulations with self-explanatory semantics. Access full WDCM usage datasets from here.</font></p> + + ') + ) + ) + ), # - tabPanel Usage END + + # - tabPanel Navigate + tabPanel("Navigate WDCM", + fluidRow( + column(width = 8, + HTML('<h2>WDCM Navigate</h2> + <h4>Your orientation in the WDCM Dashboards System<h4> + <hr> + <ul> + <li><b><a href = "http://wdcm.wmflabs.org/">WDCM Portal</a></b>.<br> + <font size = "2">The entry point to WDCM Dashboards.</font></li><br> + <li><b><a href = "http://wdcm.wmflabs.org/WDCM_OverviewDashboard/">WDCM Overview</a></b><br> + <font size = "2">The big picture. Fundamental insights in how Wikidata is used across the client projects.</font></li><br> + <li><b><a href = "http://wdcm.wmflabs.org/WDCM_SemanticsDashboard/">WDCM Semantics</a></b><br> + <font size = "2">Detailed insights into the WDCM Taxonomy (a selection of semantic categories from Wikidata), its distributional + semantics, and the way it is used across the client projects. If you are looking for Topic Models - that’s where + they live.</font></li><br> + <li><b><a href = "http://wdcm.wmflabs.org/WDCM_UsageDashboard/">WDCM Usage</a> (current dashboard)</b><br> + <font size = "2">Fine-grained information on Wikidata usage across client projects and project types. Cross-tabulations and similar..</font></li><br> + <li><b>WDCM Items</b><br> + <font size = "2">Fine-grained information on particular Wikidata item usage across the client projects.<b> (Under development)</b></font></li><br> + <li><b><a href = "https://wikitech.wikimedia.org/wiki/Wikidata_Concepts_Monitor">WDCM System Technical Documentation</a></b><br> + <font size = "2">The WDCM Wikitech Page.</font></li> + </ul>' + ) + ) + ) + ) # - tabPanel Structure END + + ) # - tabBox END + + ) # - main column of fluidRow Boxes END + + ), # - # - fluidRow Boxes END + + # - fluidRow Footer + fluidRow( + column(width = 12, + hr(), + HTML('<b>Wikidata Concepts Monitor :: WMDE 2017</b><br>Diffusion: <a href="https://phabricator.wikimedia.org/diffusion/AWCM/" target = "_blank">WDCM</a><br>'), + HTML('Contact: Goran S. Milovanovic, Data Scientist, WMDE<br>e-mail: goran.milovanovic_...@wikimedia.de + <br>IRC: goransm'), + br(), + br() + ) + ) # - fluidRow Footer END + + ) # - fluidPage END + +) # - ShinyUI END diff --git a/www/Wikidata-logo-en.png b/www/Wikidata-logo-en.png new file mode 100644 index 0000000..380ea29 --- /dev/null +++ b/www/Wikidata-logo-en.png Binary files differ -- To view, visit https://gerrit.wikimedia.org/r/391010 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ifa894d8effc9cf713bf7b36bd23e46f8e7a7b48c Gerrit-PatchSet: 1 Gerrit-Project: analytics/wmde/WDCM-Usage-Dashboard Gerrit-Branch: master Gerrit-Owner: GoranSMilovanovic <goran.milovanovic_...@wikimedia.de> Gerrit-Reviewer: Addshore <addshorew...@gmail.com> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits