├── inst └── app │ ├── data │ └── .gitignore │ ├── www │ ├── app_images │ │ └── .gitignore │ ├── img_size.js │ └── taipan.css │ ├── ui.R │ └── server.R ├── LICENSE ├── vignettes ├── .gitignore ├── taipan-vignette.R └── taipan-vignette.Rmd ├── tests ├── testthat.R └── testthat │ └── test-taipan.R ├── man ├── figures │ └── taipan.png ├── taipanQuestions.Rd └── buildTaipan.Rd ├── NEWS.md ├── docs ├── articles │ ├── Taipan4editings.png │ ├── Taipan5plotting.png │ ├── Taipan1imageInformation.png │ ├── Taipan2selectionInformation.png │ ├── Taipan3selectionInformation.png │ ├── index.html │ └── taipan-vignette.html ├── reference │ ├── figures │ │ └── taipan.png │ ├── index.html │ ├── reexports.html │ ├── sampleQuestions.html │ ├── tennisQuestions.html │ ├── tennisQuestionsSmall.html │ ├── taipan-package.html │ ├── launchTaipan.html │ └── buildTaipan.html ├── pkgdown.yml ├── link.svg ├── docsearch.js ├── jquery.sticky-kit.min.js ├── pkgdown.js ├── LICENSE-text.html ├── authors.html ├── pkgdown.css ├── news │ └── index.html ├── LICENSE.html ├── index.html └── docsearch.css ├── .Rbuildignore ├── .gitignore ├── NAMESPACE ├── sample_images ├── 2016_HSA_R01_BTomic_AUS_vs_DIstomin_UZB_MS157_clip.0013.png ├── 2016_CT6_R01_CGarcia_FRA_vs_BStrycova_CZE_WS145_clip.0015.png ├── 2016_CT6_R02_ABeck_GER_vs_TBacsinszky_SUI_WS220_clip.0017.png ├── 2016_CT6_R01_EKulichkova_RUS_vs_APetkovic_GER_WS128_clip.0080.png └── 2016_CT6_R01_JMillman_AUS_vs_DSchwartzman_ARG_MS159_clip.0013.png ├── taipan.Rproj ├── DESCRIPTION ├── LICENSE.md ├── README.md ├── README.Rmd └── R ├── questions.R └── build.R /inst/app/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /inst/app/www/app_images/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2018 2 | COPYRIGHT HOLDER: Stephanie Kobakian 3 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | taipan-vignette_cache 2 | *.html 3 | *.pdf -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(taipan) 3 | 4 | test_check("taipan") 5 | -------------------------------------------------------------------------------- /tests/testthat/test-taipan.R: -------------------------------------------------------------------------------- 1 | context("taipan") 2 | 3 | test_that("Taipan unit tests", { 4 | }) 5 | -------------------------------------------------------------------------------- /man/figures/taipan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Solve-Geosolutions/taipan/HEAD/man/figures/taipan.png -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # taipan 0.1.0.9000 2 | 3 | * Added a `NEWS.md` file to track changes to the package. 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/articles/Taipan4editings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Solve-Geosolutions/taipan/HEAD/docs/articles/Taipan4editings.png -------------------------------------------------------------------------------- /docs/articles/Taipan5plotting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Solve-Geosolutions/taipan/HEAD/docs/articles/Taipan5plotting.png -------------------------------------------------------------------------------- /docs/reference/figures/taipan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Solve-Geosolutions/taipan/HEAD/docs/reference/figures/taipan.png -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^LICENSE\.md$ 4 | ^\.travis\.yml$ 5 | ^README\.Rmd$ 6 | ^docs$ 7 | ^sample_images$ 8 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 1.19.2.1 2 | pkgdown: 1.1.0 3 | pkgdown_sha: ~ 4 | articles: 5 | taipan-vignette: taipan-vignette.html 6 | 7 | -------------------------------------------------------------------------------- /docs/articles/Taipan1imageInformation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Solve-Geosolutions/taipan/HEAD/docs/articles/Taipan1imageInformation.png -------------------------------------------------------------------------------- /docs/articles/Taipan2selectionInformation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Solve-Geosolutions/taipan/HEAD/docs/articles/Taipan2selectionInformation.png -------------------------------------------------------------------------------- /docs/articles/Taipan3selectionInformation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Solve-Geosolutions/taipan/HEAD/docs/articles/Taipan3selectionInformation.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | symbols.rds 4 | .Rhistory 5 | .Rproj.user 6 | .travis.yml 7 | revdep 8 | tests/testthat/Rplots.pdf 9 | inst/doc 10 | SolveSpecificData.R 11 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(buildTaipan) 4 | export(taipanQuestions) 5 | importFrom(downloader,download) 6 | importFrom(shiny,div) 7 | importFrom(shiny,runApp) 8 | -------------------------------------------------------------------------------- /sample_images/2016_HSA_R01_BTomic_AUS_vs_DIstomin_UZB_MS157_clip.0013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Solve-Geosolutions/taipan/HEAD/sample_images/2016_HSA_R01_BTomic_AUS_vs_DIstomin_UZB_MS157_clip.0013.png -------------------------------------------------------------------------------- /sample_images/2016_CT6_R01_CGarcia_FRA_vs_BStrycova_CZE_WS145_clip.0015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Solve-Geosolutions/taipan/HEAD/sample_images/2016_CT6_R01_CGarcia_FRA_vs_BStrycova_CZE_WS145_clip.0015.png -------------------------------------------------------------------------------- /sample_images/2016_CT6_R02_ABeck_GER_vs_TBacsinszky_SUI_WS220_clip.0017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Solve-Geosolutions/taipan/HEAD/sample_images/2016_CT6_R02_ABeck_GER_vs_TBacsinszky_SUI_WS220_clip.0017.png -------------------------------------------------------------------------------- /sample_images/2016_CT6_R01_EKulichkova_RUS_vs_APetkovic_GER_WS128_clip.0080.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Solve-Geosolutions/taipan/HEAD/sample_images/2016_CT6_R01_EKulichkova_RUS_vs_APetkovic_GER_WS128_clip.0080.png -------------------------------------------------------------------------------- /sample_images/2016_CT6_R01_JMillman_AUS_vs_DSchwartzman_ARG_MS159_clip.0013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Solve-Geosolutions/taipan/HEAD/sample_images/2016_CT6_R01_JMillman_AUS_vs_DSchwartzman_ARG_MS159_clip.0013.png -------------------------------------------------------------------------------- /inst/app/www/img_size.js: -------------------------------------------------------------------------------- 1 | Shiny.addCustomMessageHandler('get_dim', function(id) { 2 | var img = document.getElementById("taipan_current_img"); 3 | if(img !== null){ 4 | Shiny.setInputValue("taipan_img_dim", [img.naturalWidth, img.naturalHeight]); 5 | } 6 | }); 7 | -------------------------------------------------------------------------------- /inst/app/www/taipan.css: -------------------------------------------------------------------------------- 1 | .taipan_image_div { 2 | position:relative; 3 | } 4 | img { 5 | max-width: 100%; 6 | } 7 | #out_img_overlay { 8 | position:absolute; 9 | top:0; 10 | left:0; 11 | z-index: 1; 12 | } 13 | 14 | .nav > li > a { 15 | font-size:19px; 16 | } 17 | -------------------------------------------------------------------------------- /vignettes/taipan-vignette.R: -------------------------------------------------------------------------------- 1 | ## ----setup, include = FALSE---------------------------------------------- 2 | knitr::opts_chunk$set( 3 | collapse = TRUE, 4 | comment = "#>", 5 | fig.align = "centre", 6 | eval = FALSE) 7 | library(taipan) 8 | 9 | ## ---- eval = FALSE------------------------------------------------------- 10 | # # install.packages("devtools") 11 | # devtools::install_github("srkobakian/taipan") 12 | 13 | -------------------------------------------------------------------------------- /taipan.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace,vignette 22 | -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: taipan 2 | Version: 0.1.0.9000 3 | Title: Taipan For R 4 | Authors@R: c(person("Stephanie", "Kobakian", email = "stephanie.kobakian@gmail.com", role = c("aut", "cre")), 5 | person("Mitchell", "O'Hara-Wild", email = "mail@mitchelloharawild.com", role = c("aut"))) 6 | Description: Taipan is a tool for annotating images in preparation for analysis. 7 | It allows users to annotate images in an interactive environment. 8 | Users supply images, questions and the possible answers. 9 | When Images are displayed, survey takers can select the appropriate responses. 10 | The answers are stored in a tidy format for analysis. 11 | Depends: 12 | R (>= 3.2.0) 13 | Imports: 14 | shiny, 15 | downloader 16 | Suggests: 17 | testthat, 18 | knitr, 19 | rmarkdown, 20 | tidyverse 21 | URL: https://github.com/srkob1/taipan 22 | BugReports: https://github.com/srkob1/taipan/issues 23 | License: MIT + file LICENSE 24 | Encoding: UTF-8 25 | LazyData: true 26 | ByteCompile: true 27 | RoxygenNote: 6.0.1.9000 28 | VignetteBuilder: knitr 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2018 Stephanie Kobakian 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Taipan 4 | ========================================================= 5 | 6 | [![Travis-CI Build Status](https://travis-ci.org/srkob1/taipan.svg?branch=master)](https://travis-ci.org/srkob1/taipan) 7 | 8 | Taipan is a Tool for Annotating Images in Preparation for ANalysis. 9 | 10 | The Taipan package creates simple shiny surveys. The web applications can be used locally or deployed and allow people to save survey results as tidy data that is ready to use for analysis. 11 | 12 | The app was initially created to streamline the process of manually tagging images to create a training set. It allows users to provide information regarding entire images, and smaller regions within. It is a survey style tool, with questions being posed for each image and area identified. 13 | 14 | Installation 15 | ------------ 16 | 17 | You can install the development version from Github using: 18 | 19 | ``` r 20 | # install.packages("devtools") 21 | devtools::install_github("srkobakian/taipan") 22 | ``` 23 | 24 | Usage: coming soon... 25 | --------------------- 26 | -------------------------------------------------------------------------------- /vignettes/taipan-vignette.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Taipan Vignette" 3 | author: "Stephanie Kobakian" 4 | date: "`r Sys.Date()`" 5 | output: rmarkdown::html_vignette 6 | vignette: > 7 | %\VignetteIndexEntry{Taipan Vignette} 8 | %\VignetteEncoding{UTF-8} 9 | %\VignetteEngine{knitr::rmarkdown} 10 | editor_options: 11 | chunk_output_type: console 12 | --- 13 | 14 | ```{r setup, include = FALSE} 15 | knitr::opts_chunk$set( 16 | collapse = TRUE, 17 | comment = "#>", 18 | fig.align = "centre", 19 | eval = FALSE) 20 | library(taipan) 21 | ``` 22 | 23 | The Taipan package creates simple shiny surveys. The web applications can be used locally or deployed and allow people to save survey results as tidy data that is ready to use for analysis. 24 | 25 | The app was initially created to streamline the process of manually tagging images to create a training set. 26 | It allows users to provide information regarding entire images, and smaller regions within. It is a survey style tool, with questions being posed for each image and area identified. 27 | 28 | 29 | ## Installation 30 | 31 | You can install the development version from Github using: 32 | 33 | ```{r, eval = FALSE} 34 | # install.packages("devtools") 35 | devtools::install_github("srkobakian/taipan") 36 | ``` 37 | 38 | ## Usage: coming soon... 39 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, echo = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "README-" 12 | ) 13 | ``` 14 | 15 | # Taipan 16 | 17 | [![Travis-CI Build Status](https://travis-ci.org/srkob1/taipan.svg?branch=master)](https://travis-ci.org/srkob1/taipan) 18 | 19 | Taipan is a Tool for Annotating Images in Preparation for ANalysis. 20 | 21 | The Taipan package creates simple shiny surveys. The web applications can be used locally or deployed and allow people to save survey results as tidy data that is ready to use for analysis. 22 | 23 | The app was initially created to streamline the process of manually tagging images to create a training set. 24 | It allows users to provide information regarding entire images, and smaller regions within. It is a survey style tool, with questions being posed for each image and area identified. 25 | 26 | 27 | ## Installation 28 | 29 | You can install the development version from Github using: 30 | 31 | ```{r, eval = FALSE} 32 | # install.packages("devtools") 33 | devtools::install_github("srkobakian/taipan") 34 | ``` 35 | 36 | ## Usage: coming soon... 37 | -------------------------------------------------------------------------------- /inst/app/ui.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(shinydashboard) 3 | 4 | shinyUI( 5 | dashboardPage( 6 | dashboardHeader( 7 | title = "taipan", 8 | tags$li(class = "dropdown", actionLink("SpecHelp",span(icon("question-circle")," Program specific help"))), 9 | tags$li(class = "dropdown", downloadLink("btn_export", span(icon("download"), " Export Responses"))), 10 | tags$li(class = "dropdown", a(href="https://github.com/srkob1/taipan", target="_blank", span(icon("github"), " GitHub"))) 11 | ), 12 | dashboardSidebar( 13 | disable = TRUE 14 | ), 15 | dashboardBody( 16 | includeScript("www/img_size.js"), 17 | includeCSS("www/taipan.css"), 18 | column(6, 19 | box( 20 | title = textOutput("out_img_info"), 21 | div(class = "taipan_image_div", 22 | imageOutput("out_img_overlay", 23 | click = clickOpts(id = "img_click"), 24 | dblclick = dblclickOpts(id = "img_dblclick"), 25 | brush = brushOpts(id = "img_brush"), 26 | inline=TRUE), 27 | imageOutput("out_img", 28 | inline = TRUE) 29 | ), 30 | width = 12, 31 | status = "primary", 32 | collapsible = TRUE 33 | ), 34 | uiOutput("ui_instructions")), 35 | 36 | column(6, 37 | uiOutput("ui_questions"), 38 | actionLink( 39 | "btn_prev", 40 | box( 41 | "Previous", 42 | width = 3, 43 | background = "green" 44 | ) 45 | ), 46 | uiOutput("ui_deleteSelection"), 47 | uiOutput("ui_saveSelection"), 48 | actionLink( 49 | "btn_next", 50 | box( 51 | "Next", 52 | width = 3, 53 | background = "green", 54 | offset = 1 55 | ) 56 | ) 57 | ) 58 | ) 59 | ) 60 | ) 61 | -------------------------------------------------------------------------------- /docs/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /docs/jquery.sticky-kit.min.js: -------------------------------------------------------------------------------- 1 | /* Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | */ 2 | /* 3 | Source: https://github.com/leafo/sticky-kit 4 | License: MIT 5 | */ 6 | (function(){var b,f;b=this.jQuery||window.jQuery;f=b(window);b.fn.stick_in_parent=function(d){var A,w,J,n,B,K,p,q,k,E,t;null==d&&(d={});t=d.sticky_class;B=d.inner_scrolling;E=d.recalc_every;k=d.parent;q=d.offset_top;p=d.spacer;w=d.bottoming;null==q&&(q=0);null==k&&(k=void 0);null==B&&(B=!0);null==t&&(t="is_stuck");A=b(document);null==w&&(w=!0);J=function(a,d,n,C,F,u,r,G){var v,H,m,D,I,c,g,x,y,z,h,l;if(!a.data("sticky_kit")){a.data("sticky_kit",!0);I=A.height();g=a.parent();null!=k&&(g=g.closest(k)); 7 | if(!g.length)throw"failed to find stick parent";v=m=!1;(h=null!=p?p&&a.closest(p):b("
"))&&h.css("position",a.css("position"));x=function(){var c,f,e;if(!G&&(I=A.height(),c=parseInt(g.css("border-top-width"),10),f=parseInt(g.css("padding-top"),10),d=parseInt(g.css("padding-bottom"),10),n=g.offset().top+c+f,C=g.height(),m&&(v=m=!1,null==p&&(a.insertAfter(h),h.detach()),a.css({position:"",top:"",width:"",bottom:""}).removeClass(t),e=!0),F=a.offset().top-(parseInt(a.css("margin-top"),10)||0)-q, 8 | u=a.outerHeight(!0),r=a.css("float"),h&&h.css({width:a.outerWidth(!0),height:u,display:a.css("display"),"vertical-align":a.css("vertical-align"),"float":r}),e))return l()};x();if(u!==C)return D=void 0,c=q,z=E,l=function(){var b,l,e,k;if(!G&&(e=!1,null!=z&&(--z,0>=z&&(z=E,x(),e=!0)),e||A.height()===I||x(),e=f.scrollTop(),null!=D&&(l=e-D),D=e,m?(w&&(k=e+u+c>C+n,v&&!k&&(v=!1,a.css({position:"fixed",bottom:"",top:c}).trigger("sticky_kit:unbottom"))),eb&&!v&&(c-=l,c=Math.max(b-u,c),c=Math.min(q,c),m&&a.css({top:c+"px"})))):e>F&&(m=!0,b={position:"fixed",top:c},b.width="border-box"===a.css("box-sizing")?a.outerWidth()+"px":a.width()+"px",a.css(b).addClass(t),null==p&&(a.after(h),"left"!==r&&"right"!==r||h.append(a)),a.trigger("sticky_kit:stick")),m&&w&&(null==k&&(k=e+u+c>C+n),!v&&k)))return v=!0,"static"===g.css("position")&&g.css({position:"relative"}), 10 | a.css({position:"absolute",bottom:d,top:"auto"}).trigger("sticky_kit:bottom")},y=function(){x();return l()},H=function(){G=!0;f.off("touchmove",l);f.off("scroll",l);f.off("resize",y);b(document.body).off("sticky_kit:recalc",y);a.off("sticky_kit:detach",H);a.removeData("sticky_kit");a.css({position:"",bottom:"",top:"",width:""});g.position("position","");if(m)return null==p&&("left"!==r&&"right"!==r||a.insertAfter(h),h.remove()),a.removeClass(t)},f.on("touchmove",l),f.on("scroll",l),f.on("resize", 11 | y),b(document.body).on("sticky_kit:recalc",y),a.on("sticky_kit:detach",H),setTimeout(l,0)}};n=0;for(K=this.length;n max_length) { 32 | max_length = length; 33 | pos = i; 34 | } 35 | } 36 | 37 | // Add class to parent
  • , and enclosing
  • if in dropdown 38 | if (pos >= 0) { 39 | var menu_anchor = $(links[pos]); 40 | menu_anchor.parent().addClass("active"); 41 | menu_anchor.closest("li.dropdown").addClass("active"); 42 | } 43 | }); 44 | 45 | function paths(pathname) { 46 | var pieces = pathname.split("/"); 47 | pieces.shift(); // always starts with / 48 | 49 | var end = pieces[pieces.length - 1]; 50 | if (end === "index.html" || end === "") 51 | pieces.pop(); 52 | return(pieces); 53 | } 54 | 55 | function prefix_length(needle, haystack) { 56 | if (needle.length > haystack.length) 57 | return(0); 58 | 59 | // Special case for length-0 haystack, since for loop won't run 60 | if (haystack.length === 0) { 61 | return(needle.length === 0 ? 1 : 0); 62 | } 63 | 64 | for (var i = 0; i < haystack.length; i++) { 65 | if (needle[i] != haystack[i]) 66 | return(i); 67 | } 68 | 69 | return(haystack.length); 70 | } 71 | 72 | /* Clipboard --------------------------*/ 73 | 74 | function changeTooltipMessage(element, msg) { 75 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 76 | element.setAttribute('data-original-title', msg); 77 | $(element).tooltip('show'); 78 | element.setAttribute('data-original-title', tooltipOriginalTitle); 79 | } 80 | 81 | if(Clipboard.isSupported()) { 82 | $(document).ready(function() { 83 | var copyButton = ""; 84 | 85 | $(".examples, div.sourceCode").addClass("hasCopyButton"); 86 | 87 | // Insert copy buttons: 88 | $(copyButton).prependTo(".hasCopyButton"); 89 | 90 | // Initialize tooltips: 91 | $('.btn-copy-ex').tooltip({container: 'body'}); 92 | 93 | // Initialize clipboard: 94 | var clipboardBtnCopies = new Clipboard('[data-clipboard-copy]', { 95 | text: function(trigger) { 96 | return trigger.parentNode.textContent; 97 | } 98 | }); 99 | 100 | clipboardBtnCopies.on('success', function(e) { 101 | changeTooltipMessage(e.trigger, 'Copied!'); 102 | e.clearSelection(); 103 | }); 104 | 105 | clipboardBtnCopies.on('error', function() { 106 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 107 | }); 108 | }); 109 | } 110 | })(window.jQuery || window.$) 111 | -------------------------------------------------------------------------------- /docs/LICENSE-text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | License • taipan 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 44 | 45 | 46 | 47 | 48 | 49 |
    50 |
    51 | 105 | 106 | 107 |
    108 | 109 |
    110 |
    111 | 114 | 115 |
    YEAR: 2018
    116 | COPYRIGHT HOLDER: Stephanie Kobakian
    117 | 
    118 | 119 |
    120 | 121 |
    122 | 123 | 124 |
    125 | 128 | 129 |
    130 |

    Site built with pkgdown.

    131 |
    132 | 133 |
    134 |
    135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /docs/articles/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Articles • taipan 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 44 | 45 | 46 | 47 | 48 | 49 |
    50 |
    51 | 105 | 106 | 107 |
    108 | 109 |
    110 |
    111 | 114 | 115 |
    116 |

    All vignettes

    117 |

    118 | 119 | 122 |
    123 |
    124 |
    125 | 126 |
    127 | 130 | 131 |
    132 |

    Site built with pkgdown.

    133 |
    134 | 135 |
    136 |
    137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /docs/authors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Authors • taipan 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 44 | 45 | 46 | 47 | 48 | 49 |
    50 |
    51 | 105 | 106 | 107 |
    108 | 109 |
    110 |
    111 | 114 | 115 |
      116 |
    • 117 |

      Stephanie Kobakian. Author, maintainer. 118 |

      119 |
    • 120 |
    • 121 |

      Mitchell O'Hara-Wild. Author. 122 |

      123 |
    • 124 |
    125 | 126 |
    127 | 128 |
    129 | 130 | 131 |
    132 | 135 | 136 |
    137 |

    Site built with pkgdown.

    138 |
    139 | 140 |
    141 |
    142 | 143 | 144 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /docs/pkgdown.css: -------------------------------------------------------------------------------- 1 | /* Sticky footer */ 2 | 3 | /** 4 | * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ 5 | * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css 6 | * 7 | * .Site -> body > .container 8 | * .Site-content -> body > .container .row 9 | * .footer -> footer 10 | * 11 | * Key idea seems to be to ensure that .container and __all its parents__ 12 | * have height set to 100% 13 | * 14 | */ 15 | 16 | html, body { 17 | height: 100%; 18 | } 19 | 20 | body > .container { 21 | display: flex; 22 | height: 100%; 23 | flex-direction: column; 24 | 25 | padding-top: 60px; 26 | } 27 | 28 | body > .container .row { 29 | flex: 1 0 auto; 30 | } 31 | 32 | footer { 33 | margin-top: 45px; 34 | padding: 35px 0 36px; 35 | border-top: 1px solid #e5e5e5; 36 | color: #666; 37 | display: flex; 38 | flex-shrink: 0; 39 | } 40 | footer p { 41 | margin-bottom: 0; 42 | } 43 | footer div { 44 | flex: 1; 45 | } 46 | footer .pkgdown { 47 | text-align: right; 48 | } 49 | footer p { 50 | margin-bottom: 0; 51 | } 52 | 53 | img.icon { 54 | float: right; 55 | } 56 | 57 | img { 58 | max-width: 100%; 59 | } 60 | 61 | /* Typographic tweaking ---------------------------------*/ 62 | 63 | .contents h1.page-header { 64 | margin-top: calc(-60px + 1em); 65 | } 66 | 67 | /* Section anchors ---------------------------------*/ 68 | 69 | a.anchor { 70 | margin-left: -30px; 71 | display:inline-block; 72 | width: 30px; 73 | height: 30px; 74 | visibility: hidden; 75 | 76 | background-image: url(./link.svg); 77 | background-repeat: no-repeat; 78 | background-size: 20px 20px; 79 | background-position: center center; 80 | } 81 | 82 | .hasAnchor:hover a.anchor { 83 | visibility: visible; 84 | } 85 | 86 | @media (max-width: 767px) { 87 | .hasAnchor:hover a.anchor { 88 | visibility: hidden; 89 | } 90 | } 91 | 92 | 93 | /* Fixes for fixed navbar --------------------------*/ 94 | 95 | .contents h1, .contents h2, .contents h3, .contents h4 { 96 | padding-top: 60px; 97 | margin-top: -40px; 98 | } 99 | 100 | /* Static header placement on mobile devices */ 101 | @media (max-width: 767px) { 102 | .navbar-fixed-top { 103 | position: absolute; 104 | } 105 | .navbar { 106 | padding: 0; 107 | } 108 | } 109 | 110 | 111 | /* Sidebar --------------------------*/ 112 | 113 | #sidebar { 114 | margin-top: 30px; 115 | } 116 | #sidebar h2 { 117 | font-size: 1.5em; 118 | margin-top: 1em; 119 | } 120 | 121 | #sidebar h2:first-child { 122 | margin-top: 0; 123 | } 124 | 125 | #sidebar .list-unstyled li { 126 | margin-bottom: 0.5em; 127 | } 128 | 129 | .orcid { 130 | height: 16px; 131 | vertical-align: middle; 132 | } 133 | 134 | /* Reference index & topics ----------------------------------------------- */ 135 | 136 | .ref-index th {font-weight: normal;} 137 | 138 | .ref-index td {vertical-align: top;} 139 | .ref-index .alias {width: 40%;} 140 | .ref-index .title {width: 60%;} 141 | 142 | .ref-index .alias {width: 40%;} 143 | .ref-index .title {width: 60%;} 144 | 145 | .ref-arguments th {text-align: right; padding-right: 10px;} 146 | .ref-arguments th, .ref-arguments td {vertical-align: top;} 147 | .ref-arguments .name {width: 20%;} 148 | .ref-arguments .desc {width: 80%;} 149 | 150 | /* Nice scrolling for wide elements --------------------------------------- */ 151 | 152 | table { 153 | display: block; 154 | overflow: auto; 155 | } 156 | 157 | /* Syntax highlighting ---------------------------------------------------- */ 158 | 159 | pre { 160 | word-wrap: normal; 161 | word-break: normal; 162 | border: 1px solid #eee; 163 | } 164 | 165 | pre, code { 166 | background-color: #f8f8f8; 167 | color: #333; 168 | } 169 | 170 | pre code { 171 | overflow: auto; 172 | word-wrap: normal; 173 | white-space: pre; 174 | } 175 | 176 | pre .img { 177 | margin: 5px 0; 178 | } 179 | 180 | pre .img img { 181 | background-color: #fff; 182 | display: block; 183 | height: auto; 184 | } 185 | 186 | code a, pre a { 187 | color: #375f84; 188 | } 189 | 190 | a.sourceLine:hover { 191 | text-decoration: none; 192 | } 193 | 194 | .fl {color: #1514b5;} 195 | .fu {color: #000000;} /* function */ 196 | .ch,.st {color: #036a07;} /* string */ 197 | .kw {color: #264D66;} /* keyword */ 198 | .co {color: #888888;} /* comment */ 199 | 200 | .message { color: black; font-weight: bolder;} 201 | .error { color: orange; font-weight: bolder;} 202 | .warning { color: #6A0366; font-weight: bolder;} 203 | 204 | /* Clipboard --------------------------*/ 205 | 206 | .hasCopyButton { 207 | position: relative; 208 | } 209 | 210 | .btn-copy-ex { 211 | position: absolute; 212 | right: 0; 213 | top: 0; 214 | visibility: hidden; 215 | } 216 | 217 | .hasCopyButton:hover button.btn-copy-ex { 218 | visibility: visible; 219 | } 220 | 221 | /* mark.js ----------------------------*/ 222 | 223 | mark { 224 | background-color: rgba(255, 255, 51, 0.5); 225 | border-bottom: 2px solid rgba(255, 153, 51, 0.3); 226 | padding: 1px; 227 | } 228 | 229 | /* vertical spacing after htmlwidgets */ 230 | .html-widget { 231 | margin-bottom: 10px; 232 | } 233 | -------------------------------------------------------------------------------- /docs/news/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Changelog • taipan 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 44 | 45 | 46 | 47 | 48 | 49 |
    50 |
    51 | 105 | 106 | 107 |
    108 | 109 |
    110 |
    111 | 115 | 116 |
    117 |

    118 | taipan 0.1.0.9000

    119 |
      120 |
    • Added a NEWS.md file to track changes to the package.
    • 121 |
    122 |
    123 |
    124 | 125 | 133 | 134 |
    135 | 136 |
    137 | 140 | 141 |
    142 |

    Site built with pkgdown.

    143 |
    144 | 145 |
    146 |
    147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /docs/reference/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Function reference • taipan 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 44 | 45 | 46 | 47 | 48 | 49 |
    50 |
    51 | 105 | 106 | 107 |
    108 | 109 |
    110 |
    111 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 129 | 130 | 131 | 132 | 135 | 136 | 137 | 138 |
    126 |

    All functions

    127 |

    128 |
    133 |

    buildTaipan()

    134 |

    buildTaipan

    139 |
    140 | 141 | 147 |
    148 | 149 |
    150 | 153 | 154 |
    155 |

    Site built with pkgdown.

    156 |
    157 | 158 |
    159 |
    160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /R/build.R: -------------------------------------------------------------------------------- 1 | #' buildTaipan 2 | #' 3 | #' @param questions a taipan Questions list of scene and selection questions 4 | #' @param images a vector of image locations, can be local or URLs 5 | #' @param appdir location to export the completed app 6 | #' @param launch launch the app from the new directory after build is completed 7 | #' @param overwrite replace the contents of the supplied location with the completed app 8 | #' @param additionalHelp allow for contextual help on the survey as a modal dialog. 9 | #' 10 | #' @examples 11 | #' \dontrun{ 12 | #' library(shiny) 13 | #' library(taipan) 14 | #' 15 | #' questions <- taipanQuestions( 16 | #' scene = div(radioButtons("graphic", label = ("2D Graphic"), 17 | #' choices = list("Live image", "2D Graphic")), 18 | #' radioButtons("bg", label = ("Background"), 19 | #' choices = list("Crowd", 20 | #' "Court", "Logo wall", "Not applicable")), 21 | #' radioButtons("person", label = ("Detectable Person"), 22 | #' choices = list("Yes", "No")), 23 | #' radioButtons("shotangle", label = ("Shot angle"), 24 | #' choices = list("Level with players", 25 | #' "Birds eye", 26 | #' "Upward angle")), 27 | #' radioButtons("situation", label = ("Situation"), 28 | #' choices = list("Court in play", 29 | #' "Court player close-up", 30 | #' "Court close-up not player", 31 | #' "Crowd", 32 | #' "Off court close up of player", 33 | #' "Transition"))), 34 | #' selection = div(radioButtons("detect", label = ("Detect Face"), 35 | #' choices = list("Player" , 36 | #' "Other staff on court", "Fan", "None")), 37 | #' radioButtons("obscured", label = ("Face obscured"), 38 | #' choices = list("Yes", "No")), 39 | #' radioButtons("lighting", label = ("Lighting"), 40 | #' choices = list("Direct sunlight", "Shaded", "Partially shaded")), 41 | #' radioButtons("headangle", label = ("Head angle"), 42 | #' choices = list("Front on", "Back of head", 43 | #' "Profile", "Other")), 44 | #' radioButtons("glasses", label = ("Glasses"), 45 | #' choices = list("Yes", "No")), 46 | #' radioButtons("visorhat", label = ("Visor/hat"), 47 | #' choices = list("Yes", "No"))) 48 | #' ) 49 | #' 50 | #' additionalHelp <- paste(h4("Program Specific Help"), br(), 51 | #' p("This is some specific text, about something specific to your application"), br(), 52 | #' br(), 53 | #' "For more information on how to use this tool, contact either information-at-information.com or 54 | #' John.Smith-at-information.com") 55 | #' 56 | #' 57 | #' buildTaipan( 58 | #' questions = questions, 59 | #' "https://raw.githubusercontent.com/srkob1/taipan/master/sample_images/2016_CT6_R01_CGarcia_FRA_vs_BStrycova_CZE_WS145_clip.0015.png", 60 | #' file.path(tempdir(), "taipan") 61 | #' ) 62 | #' 63 | #' } 64 | #' 65 | #' @importFrom shiny runApp 66 | #' @importFrom downloader download 67 | #' 68 | #' @export 69 | 70 | buildTaipan <- function(questions, images, appdir, launch = TRUE, overwrite = FALSE, additionalHelp = NULL){ 71 | # images <- tools::file_path_as_absolute(images) 72 | if(!inherits(questions, "taipanQuestions")){ 73 | stop("Questions must be created using the taipanQuestions() function.") 74 | } 75 | 76 | if(overwrite){ 77 | message(paste0("Are you sure you want to overwrite '", appdir, "'? All files in this folder will be deleted!\nYes: Delete ALL of these files!\nNo: Keep it the way it is!")) 78 | auth <- readline() 79 | if(toupper(auth)!="YES"){ 80 | message("Aborted building of taipan app.") 81 | return(invisible(NULL)) 82 | } 83 | unlink(appdir, recursive = TRUE) 84 | } 85 | if(dir.exists(appdir)){ 86 | if(length(list.files(appdir))>0){ 87 | stop(sprintf('Output appdir "%s" already exists, please provide a different location to save app', 88 | appdir)) 89 | } 90 | } 91 | else{ 92 | dir.create(appdir) 93 | } 94 | appdir <- tools::file_path_as_absolute(appdir) 95 | 96 | if (is.null(additionalHelp)) { 97 | additionalHelp="There is no help specific for this project" 98 | } 99 | 100 | 101 | 102 | # WRITE APPDIR 103 | app_files <- list.files(file.path(system.file(package="taipan"), "app")) 104 | file.copy(file.path(system.file(package="taipan"), "app", app_files), appdir, recursive = TRUE) 105 | 106 | # SAVE QUESTIONS 107 | saveRDS(questions, file = file.path(appdir, "data", "questions.rds")) 108 | 109 | # SAVE HELP 110 | saveRDS(additionalHelp, file = file.path(appdir, "data", "additionalHelp.rds")) 111 | 112 | # CONSTRUCT IMAGE DIR 113 | if(dir.exists(images)){ 114 | images <- list.files(images, full.names = TRUE) 115 | } 116 | img_success <- file.copy(images, file.path(appdir, "www", "app_images", basename(images))) 117 | if(any(!img_success)){ 118 | download(images[!img_success], file.path(appdir, "www", "app_images", basename(images)), mode = "wb") 119 | } 120 | 121 | # LAUNCH APP 122 | if(launch){ 123 | runApp(appdir) 124 | } 125 | } 126 | 127 | -------------------------------------------------------------------------------- /docs/LICENSE.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | MIT License • taipan 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 44 | 45 | 46 | 47 | 48 | 49 |
    50 |
    51 | 105 | 106 | 107 |
    108 | 109 |
    110 |
    111 | 114 | 115 |
    116 | 117 |

    Copyright (c) 2018 Stephanie Kobakian

    118 |

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

    119 |

    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    120 |

    THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

    121 |
    122 | 123 |
    124 | 125 |
    126 | 127 | 128 |
    129 | 132 | 133 |
    134 |

    Site built with pkgdown.

    135 |
    136 | 137 |
    138 |
    139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /docs/reference/reexports.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Objects exported from other packages — reexports • taipan 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 39 | 40 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 55 | 56 | 57 | 58 | 59 | 60 |
    61 |
    62 | 116 | 117 | 118 |
    119 | 120 |
    121 |
    122 | 127 | 128 |
    129 | 130 |

    These objects are imported from other packages. Follow the links 131 | below to see their documentation.

    132 |
    133 |
    dplyr

    %>%

    134 | 135 |
    readr

    read_csv, write_csv

    136 | 137 |
    tidyr

    spread

    138 |
    139 | 140 |
    141 | 142 | 143 | 144 |
    145 | 151 |
    152 | 153 |
    154 | 157 | 158 |
    159 |

    Site built with pkgdown.

    160 |
    161 | 162 |
    163 |
    164 | 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /docs/reference/sampleQuestions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Nested list of a sample of Questions — sampleQuestions • taipan 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | 50 | 51 | 52 | 53 |
    54 |
    55 | 109 | 110 | 111 |
    112 | 113 |
    114 |
    115 | 120 | 121 |
    122 | 123 |

    A nested list containing two sets of questions and the information needed 124 | to create shiny objects for each question.

    125 | 126 |
    127 | 128 |
    sampleQuestions
    129 | 130 |

    Format

    131 | 132 |
      133 |
    • scene: located in the top level list, contains a list of questions 134 | to be asked about the entire image.

    • 135 |
    • selection: located in the top level list, contains a list of 136 | questions regarding selected areas within an image.

    • 137 |
    • qType: A character string of the function name of the shiny question 138 | object to be produced.

    • 139 |
    • label: The question that will be displayed in the shiny app.

    • 140 |
    • choices: A character vector of options to be chosen.

    • 141 |
    • selected: An optional argument, when a particular answer should be a 142 | default selection.

    • 143 |
    144 | 145 | 146 |
    147 | 155 |
    156 | 157 |
    158 | 161 | 162 |
    163 |

    Site built with pkgdown.

    164 |
    165 | 166 |
    167 |
    168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /docs/articles/taipan-vignette.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Taipan Vignette • taipan 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 |
    22 |
    76 | 77 | 78 | 79 |
    80 |
    81 | 91 | 92 | 93 | 94 |

    The Taipan package creates simple shiny surveys. The web applications can be used locally or deployed and allow people to save survey results as tidy data that is ready to use for analysis.

    95 |

    The app was initially created to streamline the process of manually tagging images to create a training set. It allows users to provide information regarding entire images, and smaller regions within. It is a survey style tool, with questions being posed for each image and area identified.

    96 |
    97 |

    98 | Installation

    99 |

    You can install the development version from Github using:

    100 |
    # install.packages("devtools")
    101 | devtools::install_github("srkobakian/taipan")
    102 |
    103 |
    104 |

    105 | Usage: coming soon…

    106 |
    107 |
    108 | 109 | 119 | 120 |
    121 | 122 | 123 |
    126 | 127 |
    128 |

    Site built with pkgdown.

    129 |
    130 | 131 |
    132 |
    133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /docs/reference/tennisQuestions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Nested list of all questions used to manually annotate Australian Open images — tennisQuestions • taipan 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | 50 | 51 | 52 | 53 |
    54 |
    55 | 109 | 110 | 111 |
    112 | 113 |
    114 |
    115 | 120 | 121 |
    122 | 123 |

    A nested list structure containing questions regarding the images 124 | provided by Tennis Australia of the Australian Open 2016:

    125 | 126 |
    127 | 128 |
    tennisQuestions
    129 | 130 |

    Format

    131 | 132 |
      133 |
    • scene: A list of questions regarding the background, angle of the 134 | shot and the situation occuring.

    • 135 |
    • selection: A list of questions regarding the face captured. Whether 136 | it is completely visible, the angle of the face, how the face is lit, and 137 | the accessories being worn.

    • 138 |
    • qType: A character string of the function name of the shiny question 139 | object to be produced.

    • 140 |
    • label: The question that will be displayed in the shiny app.

    • 141 |
    • choices: A character vector of options to be chosen.

    • 142 |
    • selected: An option argument, when a particular answer should be a 143 | default selection.

    • 144 |
    145 | 146 | 147 |
    148 | 156 |
    157 | 158 |
    159 | 162 | 163 |
    164 |

    Site built with pkgdown.

    165 |
    166 | 167 |
    168 |
    169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/reference/tennisQuestionsSmall.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Nested list of some questions used to manually annotate Australian Open images — tennisQuestionsSmall • taipan 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | 50 | 51 | 52 | 53 |
    54 |
    55 | 109 | 110 | 111 |
    112 | 113 |
    114 |
    115 | 120 | 121 |
    122 | 123 |

    A nested list structure containing questions regarding the images 124 | provided by Tennis Australia of the Australian Open 2016:

    125 | 126 |
    127 | 128 |
    tennisQuestionsSmall
    129 | 130 |

    Format

    131 | 132 |
      133 |
    • scene: A list of questions regarding the background, angle of the 134 | shot and the situation occuring.

    • 135 |
    • selection: A list of questions regarding the face captured. Whether 136 | it is completely visible, the angle of the face, how the face is lit, and 137 | the accessories being worn.

    • 138 |
    • qType: A character string of the function name of the shiny question 139 | object to be produced.

    • 140 |
    • label: The question that will be displayed in the shiny app.

    • 141 |
    • choices: A character vector of options to be chosen.

    • 142 |
    • selected: An option argument, when a particular answer should be a 143 | default selection.

    • 144 |
    145 | 146 | 147 |
    148 | 156 |
    157 | 158 |
    159 | 162 | 163 |
    164 |

    Site built with pkgdown.

    165 |
    166 | 167 |
    168 |
    169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/reference/taipan-package.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | taipan: Taipan For R — taipan-package • taipan 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 52 | 53 | 54 | 55 | 56 |
    57 |
    58 | 112 | 113 | 114 |
    115 | 116 |
    117 |
    118 | 123 | 124 |
    125 | 126 |

    Taipan is a tool for annotating images in preparation for analysis. 127 | It allows users to annotate images in an interactive environment. 128 | Users supply images, questions and the possible answers. 129 | When Images are displayed, survey takers can select the appropriate responses. 130 | The answers are stored in a tidy format for analysis.

    131 | 132 |
    133 | 134 | 135 |

    See also

    136 | 137 |

    Useful links:

    141 | 142 | 143 |
    144 | 162 |
    163 | 164 |
    165 | 168 | 169 |
    170 |

    Site built with pkgdown.

    171 |
    172 | 173 |
    174 |
    175 | 176 | 177 | 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Taipan For R • taipan 9 | 10 | 11 | 12 | 13 | 18 | 19 | 23 | 24 | 25 |
    26 |
    80 | 81 | 82 | 83 |
    84 |
    85 | 86 | 87 | 88 | 89 | 90 |
    91 | 94 | 95 |

    Taipan is a Tool for Annotating Images in Preparation for ANalysis.

    96 |

    The Taipan package creates simple shiny surveys. The web applications can be used locally or deployed and allow people to save survey results as tidy data that is ready to use for analysis.

    97 |

    The app was initially created to streamline the process of manually tagging images to create a training set. It allows users to provide information regarding entire images, and smaller regions within. It is a survey style tool, with questions being posed for each image and area identified.

    98 |
    99 |

    100 | Installation

    101 |

    You can install the development version from Github using:

    102 |
    # install.packages("devtools")
    103 | devtools::install_github("srkobakian/taipan")
    104 |
    105 |
    106 |

    107 | Usage: coming soon…

    108 |
    109 |
    110 |
    111 | 112 | 144 | 145 |
    146 | 147 | 148 |
    151 | 152 |
    153 |

    Site built with pkgdown.

    154 |
    155 | 156 |
    157 |
    158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /docs/reference/launchTaipan.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Launch Taipan — launchTaipan • taipan 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 47 | 48 | 49 | 50 | 51 | 52 |
    53 |
    54 | 108 | 109 | 110 |
    111 | 112 |
    113 |
    114 | 119 | 120 |
    121 | 122 |

    This launches the app

    123 | 124 |
    125 | 126 |
    launchTaipan(questions = sampleQuestions, loadCache = FALSE,
    127 |   images = list.files("images"))
    128 | 129 |

    Arguments

    130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 |
    questions

    A taipan structured list object containing the questions to be asked in the app, see the global environment object sampleQuestions.

    loadCache

    If a cache.Rda object is found in the working directory and loadCache = TRUE, data from previous use of the app will be made avaiable. if there is no object the app will proceed from the beinnning of the image set. The default for this is FALSE.

    images

    The list of images located within the image folder.

    145 | 146 | 147 |

    Examples

    148 |
    149 |
    # NOT RUN { 150 | library(taipan) 151 | tennisQuestionsSmall <- list(scene = list( 152 | 153 | bg = list(qType = "radio", 154 | label = "What is the background?", 155 | choices = c("Crowd", "Court", "Logo wall", "Not applicable")), 156 | shotangle = list(qType = "radio", 157 | label = "What angle was the image taken from?", 158 | choices = c("Level with players","Birds eye", "Upward angle")), 159 | situation = list(qType = "radio", 160 | label = "What is the siutation occurring?", 161 | choices = c("Court in play", "Court player close-up","Court close-up not player", 162 | "Crowd", "Off court close up of player","Transition"))), 163 | 164 | selection = list(detect = list(qType = "radio", 165 | label = "Who is the person selected?", 166 | choices = c("Player","Other staff on court", "Fan")), 167 | glasses = list(qType = "radio", 168 | label = "Is the person wearing glasses?", 169 | choices = c("No", "Yes")), 170 | visorhat = list(qType = "radio", 171 | label = "Is the person wearing a visor or hat?", 172 | choices = c("No", "Yes")))) 173 | 174 | 175 | launchTaipan(tennisQuestionsSmall) 176 | # }
    177 |
    178 |
    179 | 188 |
    189 | 190 |
    191 | 194 | 195 |
    196 |

    Site built with pkgdown.

    197 |
    198 | 199 |
    200 |
    201 | 202 | 203 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /docs/docsearch.css: -------------------------------------------------------------------------------- 1 | /* Docsearch -------------------------------------------------------------- */ 2 | /* 3 | Source: https://github.com/algolia/docsearch/ 4 | License: MIT 5 | */ 6 | 7 | .algolia-autocomplete { 8 | display: block; 9 | -webkit-box-flex: 1; 10 | -ms-flex: 1; 11 | flex: 1 12 | } 13 | 14 | .algolia-autocomplete .ds-dropdown-menu { 15 | width: 100%; 16 | min-width: none; 17 | max-width: none; 18 | padding: .75rem 0; 19 | background-color: #fff; 20 | background-clip: padding-box; 21 | border: 1px solid rgba(0, 0, 0, .1); 22 | box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .175); 23 | } 24 | 25 | @media (min-width:768px) { 26 | .algolia-autocomplete .ds-dropdown-menu { 27 | width: 175% 28 | } 29 | } 30 | 31 | .algolia-autocomplete .ds-dropdown-menu::before { 32 | display: none 33 | } 34 | 35 | .algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-] { 36 | padding: 0; 37 | background-color: rgb(255,255,255); 38 | border: 0; 39 | max-height: 80vh; 40 | } 41 | 42 | .algolia-autocomplete .ds-dropdown-menu .ds-suggestions { 43 | margin-top: 0 44 | } 45 | 46 | .algolia-autocomplete .algolia-docsearch-suggestion { 47 | padding: 0; 48 | overflow: visible 49 | } 50 | 51 | .algolia-autocomplete .algolia-docsearch-suggestion--category-header { 52 | padding: .125rem 1rem; 53 | margin-top: 0; 54 | font-size: 1.3em; 55 | font-weight: 500; 56 | color: #00008B; 57 | border-bottom: 0 58 | } 59 | 60 | .algolia-autocomplete .algolia-docsearch-suggestion--wrapper { 61 | float: none; 62 | padding-top: 0 63 | } 64 | 65 | .algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column { 66 | float: none; 67 | width: auto; 68 | padding: 0; 69 | text-align: left 70 | } 71 | 72 | .algolia-autocomplete .algolia-docsearch-suggestion--content { 73 | float: none; 74 | width: auto; 75 | padding: 0 76 | } 77 | 78 | .algolia-autocomplete .algolia-docsearch-suggestion--content::before { 79 | display: none 80 | } 81 | 82 | .algolia-autocomplete .ds-suggestion:not(:first-child) .algolia-docsearch-suggestion--category-header { 83 | padding-top: .75rem; 84 | margin-top: .75rem; 85 | border-top: 1px solid rgba(0, 0, 0, .1) 86 | } 87 | 88 | .algolia-autocomplete .ds-suggestion .algolia-docsearch-suggestion--subcategory-column { 89 | display: block; 90 | padding: .1rem 1rem; 91 | margin-bottom: 0.1; 92 | font-size: 1.0em; 93 | font-weight: 400 94 | /* display: none */ 95 | } 96 | 97 | .algolia-autocomplete .algolia-docsearch-suggestion--title { 98 | display: block; 99 | padding: .25rem 1rem; 100 | margin-bottom: 0; 101 | font-size: 0.9em; 102 | font-weight: 400 103 | } 104 | 105 | .algolia-autocomplete .algolia-docsearch-suggestion--text { 106 | padding: 0 1rem .5rem; 107 | margin-top: -.25rem; 108 | font-size: 0.8em; 109 | font-weight: 400; 110 | line-height: 1.25 111 | } 112 | 113 | .algolia-autocomplete .algolia-docsearch-footer { 114 | width: 110px; 115 | height: 20px; 116 | z-index: 3; 117 | margin-top: 10.66667px; 118 | float: right; 119 | font-size: 0; 120 | line-height: 0; 121 | } 122 | 123 | .algolia-autocomplete .algolia-docsearch-footer--logo { 124 | background-image: url("data:image/svg+xml;utf8,"); 125 | background-repeat: no-repeat; 126 | background-position: 50%; 127 | background-size: 100%; 128 | overflow: hidden; 129 | text-indent: -9000px; 130 | width: 100%; 131 | height: 100%; 132 | display: block; 133 | transform: translate(-8px); 134 | } 135 | 136 | .algolia-autocomplete .algolia-docsearch-suggestion--highlight { 137 | color: #FF8C00; 138 | background: rgba(232, 189, 54, 0.1) 139 | } 140 | 141 | 142 | .algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight { 143 | box-shadow: inset 0 -2px 0 0 rgba(105, 105, 105, .5) 144 | } 145 | 146 | .algolia-autocomplete .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content { 147 | background-color: rgba(192, 192, 192, .15) 148 | } 149 | -------------------------------------------------------------------------------- /inst/app/server.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(ggplot2) 3 | library(purrr) 4 | 5 | getInputID <- function(input){ 6 | if(!inherits(input, "shiny.tag")){ 7 | return() 8 | } 9 | c( 10 | if(!is.null(input$attribs$id)){list(list(id=input$attribs$id, type = input$name))}else{NULL}, 11 | do.call("c", map(input$children, getInputID)) 12 | ) 13 | } 14 | 15 | shinyServer( 16 | function(input, output, session) { 17 | questions <- readRDS("data/questions.rds") 18 | additionalHelp <- readRDS("data/additionalHelp.rds") 19 | 20 | image_list <- list.files("www/app_images", full.names = TRUE) 21 | 22 | v <- reactiveValues( 23 | imageNum = 1, 24 | current_sel = NULL, 25 | editing = F, 26 | responses = list() 27 | ) 28 | 29 | current_img <- reactive({ 30 | image_list[v$imageNum] 31 | }) 32 | current_sel <- reactive({ 33 | v$current_sel 34 | }) 35 | current_area <- reactive({ 36 | if(!is.null(input$img_brush)){ 37 | input$img_brush[c("xmin", "xmax", "ymin", "ymax")] 38 | } 39 | else if(!is.null(current_sel())){ 40 | sel_val <- v$responses[[basename(current_img())]][["selection"]][[current_sel()]] 41 | list( 42 | xmin = sel_val$pos$xmin, 43 | xmax = sel_val$pos$xmax, 44 | ymin = sel_val$pos$ymin, 45 | ymax = sel_val$pos$ymax 46 | ) 47 | } 48 | else{ 49 | NULL 50 | } 51 | }) 52 | 53 | output$out_img_overlay <- renderImage({ 54 | session$sendCustomMessage("get_dim","taipan_current_img") 55 | if(is.null(input$taipan_img_dim)){ 56 | out_width <- 100 57 | out_height <- 100 58 | xlim <- NULL 59 | ylim <- NULL 60 | } 61 | else{ 62 | out_width <- input$taipan_img_dim[1] 63 | out_height <- input$taipan_img_dim[2] 64 | xlim <- c(0, out_width) 65 | ylim <- c(-out_height, 0) 66 | } 67 | selection_data <- do.call("rbind", 68 | c(list(data.frame(xmin=numeric(), xmax=numeric(), ymin=numeric(), ymax=numeric())), 69 | map(v$responses[[basename(current_img())]][["selection"]], 70 | function(x) as.data.frame(x$pos)) 71 | ) 72 | ) 73 | selection_data <- transform(selection_data, current = seq_len(NROW(selection_data)) %in% current_sel()) 74 | p <- ggplot(selection_data, aes(xmin=xmin, xmax=xmax, ymin=-ymax, ymax=-ymin, colour = current)) + 75 | scale_x_continuous(limits = xlim, expand=c(0,0)) + 76 | scale_y_continuous(limits = ylim, expand=c(0,0)) + 77 | geom_rect(fill="transparent") + 78 | theme_void()+ 79 | theme( 80 | panel.background = element_rect(fill = "transparent") # bg of the panel 81 | , plot.background = element_rect(fill = "transparent", colour = NA) # bg of the plot 82 | , legend.background = element_rect(fill = "transparent") # get rid of legend bg 83 | , legend.box.background = element_rect(fill = "transparent") # get rid of legend panel bg 84 | ) + 85 | guides(colour = "none") 86 | ggsave(overlay_img <- tempfile(), p, png, width = out_width, 87 | height = out_height, limitsize = FALSE, bg = "transparent") 88 | list(src = overlay_img) 89 | }) 90 | 91 | output$out_img <- renderImage({ 92 | list(src = current_img(), id = "taipan_current_img") 93 | }, deleteFile = FALSE) 94 | 95 | output$out_img_info <- renderText({ 96 | sprintf("Image: %s (%i/%i)", 97 | basename(current_img()), 98 | v$imageNum, 99 | length(image_list)) 100 | }) 101 | 102 | sceneInputs <- getInputID(questions$scene) 103 | selectionInputs <- getInputID(questions$selection) 104 | 105 | scene_vals <- reactive({ 106 | vals <- map(sceneInputs, function(id){input[[id$id]]}) 107 | names(vals) <- map_chr(sceneInputs, "id") 108 | vals 109 | }) 110 | 111 | selection_vals <- reactive({ 112 | vals <- map(selectionInputs, function(id){input[[id$id]]}) 113 | names(vals) <- map_chr(selectionInputs, "id") 114 | vals 115 | }) 116 | 117 | output$ui_instructions <- renderUI({ 118 | box( 119 | title = "Instructions", 120 | h4("Welcome to your survey."), br(), 121 | p("The", strong("Scene"), 122 | "section asks questions regarding the whole image, and will be saved when you continue to the next image.", "To answer questions about the current image, 123 | respond to the questions below."), br(), 124 | br(), 125 | "Next step is to select an area. Hold down on the image to create a cornerof the selected area, 126 | drag the crosshairs vertically and horizontally to create a rectangle around your area of interest.", br(), 127 | p("The", strong("Selection"), "questions now appear. 128 | These questions relate only to the location you have currently selected."), br(), 129 | p("Save these answers by clicking the", strong("Save Selection"), "button, 130 | when you have completed the answers for this area."), br(), 131 | "Repeat for all areas of interest.", br(), 132 | "It is possible to view or edit the answers provided by double clicking within the area.", 133 | status = "warning", 134 | solidHeader = TRUE, 135 | collapsible = TRUE, 136 | collapsed = TRUE, 137 | width = 12 138 | ) 139 | }) 140 | 141 | output$ui_questions <- renderUI({ 142 | if(!is.null(current_sel())){ 143 | box( 144 | title = "Selection", 145 | questions$selection, 146 | width = 12, 147 | status = "primary", 148 | collapsible = TRUE 149 | ) 150 | } 151 | else{ 152 | box( 153 | title = "Scene", 154 | questions$scene, 155 | width = 12, 156 | status = "primary", 157 | collapsible = TRUE 158 | ) 159 | } 160 | }) 161 | 162 | output$ui_saveSelection <- renderUI({ 163 | if(!is.null(current_sel())){ 164 | actionLink( 165 | "btn_saveSelection", 166 | box( 167 | "Save Selection", 168 | width = 3, 169 | background = "blue", offset=1 170 | ) 171 | ) 172 | } else { 173 | column(3) 174 | } 175 | }) 176 | 177 | 178 | observeEvent(v$editing, { 179 | output$ui_deleteSelection <- renderUI({ 180 | if(!is.null(current_sel()) & v$editing){ 181 | actionLink( 182 | "btn_deleteSelection", 183 | box( 184 | "Delete Selection", 185 | width = 3, 186 | background = "red", offset=1 187 | ) 188 | ) 189 | } else { 190 | column(3) 191 | } 192 | })}) 193 | 194 | observeEvent(input$img_brush, { 195 | if(is.null(input$img_brush)){ 196 | v$current_sel <- NULL 197 | } 198 | else{ 199 | v$current_sel <- length(v$responses[[basename(current_img())]][["selection"]]) + 1 200 | } 201 | }) 202 | 203 | # Additional test for removing brush 204 | observeEvent(input$img_click, { 205 | if(is.null(input$img_brush)){ 206 | v$current_sel <- NULL 207 | } 208 | }) 209 | 210 | observeEvent(input$img_dblclick, { 211 | xpos <- input$img_dblclick$x 212 | ypos <- input$img_dblclick$y 213 | match <- map_lgl(v$responses[[basename(current_img())]][["selection"]], 214 | function(sel){ 215 | (xpos >= sel$pos$xmin) && 216 | (xpos <= sel$pos$xmax) && 217 | (ypos >= sel$pos$ymin) && 218 | (ypos <= sel$pos$ymax) 219 | } 220 | ) 221 | sel_match <- which(match) 222 | if(length(sel_match) == 1){ 223 | v$current_sel <- sel_match 224 | v$editing <- T 225 | 226 | # Update selection inputs 227 | map(selectionInputs, 228 | function(io){ 229 | val <- v$responses[[basename(current_img())]][["selection"]][[sel_match]][["inputs"]][[io$id]] 230 | session$sendInputMessage( 231 | io$id, 232 | list( 233 | value = val, 234 | selected = val 235 | ) 236 | ) 237 | } 238 | ) 239 | } 240 | else{ 241 | showNotification(h3("Could not find matching selection, please select a unique area of a square."), 242 | type = "error") 243 | } 244 | }) 245 | 246 | # Update the scene values when images change 247 | observeEvent(current_img(), { 248 | map(sceneInputs, 249 | function(io){ 250 | # Update scene inputs 251 | val <- v$responses[[basename(current_img())]][["scene"]][[io$id]] 252 | if(!is.null(val)){ 253 | session$sendInputMessage( 254 | io$id, 255 | list( 256 | value = val, 257 | selected = val 258 | ) 259 | ) 260 | } 261 | else{ 262 | # Trigger re-build of UI 263 | v$current_sel <- 1 264 | v$current_sel <- NULL 265 | } 266 | } 267 | ) 268 | }) 269 | 270 | observeEvent(scene_vals(), { 271 | v$responses[[basename(current_img())]][["scene"]] <- scene_vals() 272 | }) 273 | 274 | observeEvent(input$btn_prev, { 275 | v$responses[[basename(current_img())]][["scene"]] <- scene_vals() 276 | session$resetBrush("img_brush") 277 | v$current_sel <- NULL 278 | v$imageNum <- pmax(1, v$imageNum - 1) 279 | }) 280 | 281 | observeEvent(input$btn_next, { 282 | v$responses[[basename(current_img())]][["scene"]] <- scene_vals() 283 | session$resetBrush("img_brush") 284 | v$current_sel <- NULL 285 | v$imageNum <- pmin(length(image_list), v$imageNum + 1) 286 | v$editing <- F 287 | out <<- suppressWarnings( # hide coercion warnings 288 | v$responses %>% 289 | imap_dfr( 290 | function(img, image_name){ 291 | scene_vals <- img$scene %>% 292 | map(paste0, collapse = ", ") 293 | selection_vals <- img$selection %>% 294 | map_dfr(function(sel_val){ 295 | c(sel_val$pos, 296 | sel_val$inputs %>% 297 | map(paste0, collapse = ", ") 298 | ) %>% 299 | as.data.frame 300 | }) 301 | as.data.frame(c(image_name = image_name, scene_vals, selection_vals)) 302 | } 303 | ) 304 | ) 305 | }) 306 | 307 | observeEvent(input$btn_saveSelection, { 308 | v$responses[[basename(current_img())]][["selection"]][[current_sel()]] <- 309 | list(pos = current_area(), 310 | inputs = selection_vals() 311 | ) 312 | session$resetBrush("img_brush") 313 | v$current_sel <- NULL 314 | v$editing <- F 315 | }) 316 | 317 | observeEvent(input$btn_deleteSelection, { 318 | v$responses[[basename(current_img())]][["selection"]][[current_sel()]] <- NULL 319 | v$current_sel <- NULL 320 | v$editing <- F 321 | }) 322 | 323 | output$btn_export <- downloadHandler( 324 | filename = function() { 325 | paste('taipan-export-', Sys.Date(), '.csv', sep='') 326 | }, 327 | content = function(con){ 328 | v$responses[[basename(current_img())]][["scene"]] <- scene_vals() 329 | out <- suppressWarnings( # hide coercion warnings 330 | v$responses %>% 331 | imap_dfr( 332 | function(img, image_name){ 333 | scene_vals <- img$scene %>% 334 | map(paste0, collapse = ", ") 335 | selection_vals <- img$selection %>% 336 | map_dfr(function(sel_val){ 337 | c(sel_val$pos, 338 | sel_val$inputs %>% 339 | map(paste0, collapse = ", ") 340 | ) %>% 341 | as.data.frame 342 | }) 343 | as.data.frame(c(image_name = image_name, scene_vals, selection_vals)) 344 | } 345 | ) 346 | ) 347 | write.csv(out, con, row.names = FALSE) 348 | } 349 | ) 350 | 351 | observeEvent(input$SpecHelp, { 352 | showModal(modalDialog(additionalHelp,icon=icon("question-circle"))) 353 | }) 354 | } 355 | ) 356 | -------------------------------------------------------------------------------- /docs/reference/buildTaipan.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | buildTaipan — buildTaipan • taipan 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 47 | 48 | 49 | 50 | 51 | 52 |
    53 |
    54 | 108 | 109 | 110 |
    111 | 112 |
    113 |
    114 | 119 | 120 |
    121 | 122 |

    buildTaipan

    123 | 124 |
    125 | 126 |
    buildTaipan(questions, images, appdir, launch = TRUE, overwrite = FALSE)
    127 | 128 |

    Arguments

    129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 |
    questions

    a taipan Questions list of scene and selection questions

    images

    a vector of image locations, can be local or URLs

    appdir

    location to export the completed app

    launch

    launch the app from the new directory after build is completed

    overwrite

    replace the contents of the supplied location with the completed app

    152 | 153 | 154 |

    Examples

    155 |
    # NOT RUN {
    156 | library(shiny)
    157 | library(taipan)
    158 | 
    159 | questions <- taipanQuestions(
    160 |   scene = div(radioButtons("graphic", label = ("2D Graphic"),
    161 |                            choices = list("Live image", "2D Graphic")),
    162 |               radioButtons("bg", label = ("Background"),
    163 |                            choices = list("Crowd",
    164 |                                           "Court", "Logo wall", "Not applicable")),
    165 |               radioButtons("person", label = ("Detectable Person"),
    166 |                            choices = list("Yes", "No")),
    167 |               radioButtons("shotangle", label = ("Shot angle"),
    168 |                            choices = list("Level with players",
    169 |                                           "Birds eye",
    170 |                                           "Upward angle")),
    171 |               radioButtons("situation", label = ("Situation"),
    172 |                            choices = list("Court in play",
    173 |                                           "Court player close-up",
    174 |                                           "Court close-up not player",
    175 |                                           "Crowd",
    176 |                                           "Off court close up of player",
    177 |                                           "Transition"))),
    178 |   selection = div(radioButtons("detect", label = ("Detect Face"),
    179 |                                choices = list("Player" ,
    180 |                                               "Other staff on court", "Fan", "None")),
    181 |                   radioButtons("obscured", label = ("Face obscured"),
    182 |                                choices = list("Yes", "No")),
    183 |                   radioButtons("lighting", label = ("Lighting"),
    184 |                                choices = list("Direct sunlight", "Shaded", "Partially shaded")),
    185 |                   radioButtons("headangle", label = ("Head angle"),
    186 |                                choices = list("Front on", "Back of head",
    187 |                                               "Profile", "Other")),
    188 |                   radioButtons("glasses", label = ("Glasses"),
    189 |                                choices = list("Yes", "No")),
    190 |                   radioButtons("visorhat", label = ("Visor/hat"),
    191 |                                choices = list("Yes", "No")))
    192 | )
    193 | 
    194 | buildTaipan(
    195 |   questions = questions,
    196 |   "https://raw.githubusercontent.com/srkob1/taipan/master/sample_images/2016_CT6_R01_CGarcia_FRA_vs_BStrycova_CZE_WS145_clip.0015.png",
    197 |   file.path(tempdir(), "taipan")
    198 | )
    199 | 
    200 | # }
    201 |
    202 |
    203 | 212 |
    213 | 214 | 224 |
    225 | 226 | 227 | 228 | 229 | 230 | 231 | --------------------------------------------------------------------------------