├── .gitignore ├── pics └── pocker.png ├── .gitattributes ├── .dockerignore ├── pocker.Rproj ├── gitlabCI ├── simple_configuration.yml ├── scripts │ ├── simple_script.py │ ├── simple_rcpp.cpp │ ├── style.css │ └── simple_markdown.Rmd ├── complete_configuration.yml └── build.R ├── Dockerfile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | 6 | *.html 7 | -------------------------------------------------------------------------------- /pics/pocker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linogaliana/pocker/HEAD/pics/pocker.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.html linguist-documentation 2 | *.css linguist-documentation 3 | *.js linguist-documentation 4 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .Rproj.user 3 | .Rhistory 4 | .RData 5 | .Ruserdata 6 | pocker.Rproj 7 | 8 | /pics/* 9 | /gitlabCI/* -------------------------------------------------------------------------------- /pocker.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 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 | -------------------------------------------------------------------------------- /gitlabCI/simple_configuration.yml: -------------------------------------------------------------------------------- 1 | image: linogaliana/pocker 2 | 3 | before_script: 4 | - export PATH="/opt/conda/bin:$PATH" 5 | 6 | article: 7 | stage: deploy 8 | script: 9 | - Rscript ./gitlabCI/build.R 10 | artifacts: 11 | paths: 12 | - html 13 | when: always 14 | -------------------------------------------------------------------------------- /gitlabCI/scripts/simple_script.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import datetime 3 | import statistics 4 | 5 | def test(n = 1000): 6 | start = datetime.datetime.now() 7 | x = np.random.uniform(0,1,n) 8 | for i in range(1,n): 9 | x[i] += x[i-1] 10 | end = datetime.datetime.now() 11 | c = end - start 12 | return(c.microseconds/1000) 13 | 14 | exec_time_python = [test(100000) for k in range(100)] 15 | 16 | print("Time for a cumulative sum over a vector of size 1000 (milliseconds):") 17 | print(statistics.median(exec_time_python)) 18 | 19 | -------------------------------------------------------------------------------- /gitlabCI/scripts/simple_rcpp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace Rcpp; 5 | 6 | // [[Rcpp::export]] 7 | double cumsum_cpp(int n) { 8 | 9 | // start the timer 10 | Timer timer; 11 | timer.step("start"); // record the starting point 12 | 13 | NumericVector x = runif(n); 14 | 15 | for (int i = 1 ; i < x.length() ; i++){ 16 | x[i] += x[i-1]; 17 | } 18 | 19 | timer.step("end"); // record the final step 20 | 21 | 22 | NumericVector res(timer); // 23 | for (int i=0; i> ~/.bashrc 18 | - python --version 19 | - echo $PATH 20 | - echo "source activate base" > ~/.bashrc 21 | - echo 'RETICULATE_PYTHON = "/opt/conda/bin' > .Renviron 22 | - conda info --envs 23 | - Rscript -e 'install.packages("reticulate")' 24 | - Rscript ./build.R 25 | artifacts: 26 | paths: 27 | - html 28 | when: always 29 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rocker/verse:3.5.1 2 | MAINTAINER Lino Galiana 3 | 4 | # WE EXPORT PATH FOR CONDA 5 | ENV PATH="/opt/conda/bin:${PATH}" 6 | 7 | # UPDATE A SERIES OF PACKAGES 8 | RUN apt-get update --fix-missing && apt-get install -y ca-certificates libglib2.0-0 libxext6 libsm6 libxrender1 libxml2-dev 9 | 10 | # INSTALL PYTHON 3 AND ANACONDA 11 | RUN apt-get install -y python3-pip python3-dev && pip3 install virtualenv \ 12 | && wget --quiet https://repo.anaconda.com/archive/Anaconda3-5.3.0-Linux-x86_64.sh -O ~/anaconda.sh \ 13 | && /bin/bash ~/anaconda.sh -b -p /opt/conda && rm ~/anaconda.sh \ 14 | && ln -s /opt/conda/etc/profile.d/conda.sh /etc/profile.d/conda.sh \ 15 | && echo ". /opt/conda/etc/profile.d/conda.sh" >> ~/.bashrc 16 | 17 | # CHECK PYTHON VERSION IF WANTED 18 | # RUN python --version 19 | 20 | # CHECK PATH IF WANTED 21 | # RUN echo $PATH 22 | 23 | # CHECK CONDA 24 | # RUN conda info --envs 25 | 26 | # ACTIVATE CONDA ENVIRONMENT 27 | RUN echo "source activate base" > ~/.bashrc 28 | 29 | # WRITE RETICULATE_PYTHON VARIABLE IN .Renviron 30 | RUN echo "RETICULATE_PYTHON = '/opt/conda/bin'" > .Renviron 31 | 32 | 33 | # INSTALL R PACKAGE reticulate 34 | RUN Rscript -e 'install.packages("reticulate")' 35 | 36 | # SCRIPT WOULD BE RUN AS: 37 | # RUN Rscript ./build.R 38 | -------------------------------------------------------------------------------- /gitlabCI/build.R: -------------------------------------------------------------------------------- 1 | 2 | print("=============================================") 3 | print("CHECKING RETICULATE WORKS FINE") 4 | 5 | 6 | # First, check it works in R files 7 | # --------------------------------------- 8 | 9 | Sys.setenv(RETICULATE_PYTHON = "/opt/conda/bin") 10 | 11 | print(" ---------- PYTHON PATH IN RSESSION:") 12 | print(Sys.which("python")) 13 | print(reticulate::py_config()) 14 | 15 | 16 | 17 | ### METHOD 1: INTERACTIVE SESSION 18 | 19 | print(" ---------- CHECK 1: OPEN PYTHON INTERPRETER INSIDE RSESSION") 20 | 21 | reticulate::repl_python() 22 | import numpy as np 23 | import datetime 24 | import statistics 25 | def test(n = 1000): 26 | start = datetime.datetime.now() 27 | x = np.random.uniform(0,1,n) 28 | for i in range(1,n): 29 | x[i] += x[i-1] 30 | end = datetime.datetime.now() 31 | c = end - start 32 | return(c.microseconds/1000) 33 | 34 | exec_time_python = [test(100000) for k in range(100)] 35 | 36 | print("Time for a cumulative sum over a vector of size 1000 (milliseconds):") 37 | print(statistics.median(exec_time_python)) 38 | quit 39 | 40 | ### METHOD 2: SOURCING FILE 41 | 42 | print(" ---------- CHECK 2: SOURCE PYTHON FILES INSIDE R") 43 | 44 | 45 | reticulate::source_python("./gitlabCI/scripts/simple_script.py") 46 | 47 | 48 | 49 | ### METHOD 3: RMARKDOWN 50 | 51 | print(" ---------- CHECK 3: EXECUTE PYTHON INSIDE RMARKDOWNS") 52 | 53 | f = list.files(getwd(), 'Rmd$', full.names = TRUE, recursive = TRUE) 54 | o = sapply(f, function(f) rmarkdown::render(f, output_options = list(self_contained = TRUE))) 55 | dir.create('html') 56 | copied = file.copy(o, 'html') 57 | stopifnot(all(copied)) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `PockeR` 2 | 3 | 4 | 5 | 6 | Nothing related with poker game. `PockeR` is a `docker` container with both `Python` and `R`. They can interact with `Reticulate`, either using `R` source files or `Rmarkdown` engine. 7 | 8 | To execute only `Python` programs, this is not the most appropriate docker container. This repository is useful when expecting `Python` and `R` to work together. This container is an extension of `rocker/verse` container that integrates `Python 3.7` (using anaconda), `R` 3.5.1. version and also supports `C++` through `Rcpp`. To be able to use `python` output into Rsession, you need to execute `library(reticulate)` package. If you don't need to handle output from `python` within `R` (e.g. because you export results into textfile), there is no need to load reticulate package. 9 | 10 | The automatically built `Rmarkdown` is available [here](https://gitlab.com/linogaliana/pocker/-/jobs/artifacts/master/download?job=article). 11 | 12 | Examples of scripts (both source codes and markdown) are available in `/gitlabCI` and `/gitlabCI` directories. 13 | 14 | # How to use `pocker` image in continuous integration 15 | 16 | This repository proposes two files that can be used as `.gitlab-ci.yml` in `gitlabCI` directory: 17 | 18 | * `complete_configuration.yml`: if you want your CI in gitlab to start from the scratch (rocker image). This rebuilds the 19 | * `simple_configuration.yml`: if you want to skip the configuration. This is the one I use to generate [html files](https://gitlab.com/linogaliana/pocker/-/jobs/artifacts/master/download?job=article) testing `pocker` image 20 | 21 | At this stage, when using `pocker` image, you should set `RETICULATE_PYTHON` environment variable before trying to use `reticulate`. The following command in the beginning of a script should work: 22 | 23 | ``` 24 | Sys.setenv(RETICULATE_PYTHON = "/opt/conda/bin") 25 | ``` 26 | 27 | The `build.R` script is an example file that can be modified. 28 | 29 | # Installing a new `Python` module 30 | 31 | Assuming you use gitlab CI, when you need to install a new module in `Python`, you have two possibilities: 32 | 33 | * Run shell command in `.gitlab-ci.yml`: `conda install PACKAGENAME` 34 | * Using reticulate within `R` or `Rmd` script: `reticulate::conda_install(packages = "PACKAGENAME")` 35 | 36 | You can also, either using command line or reticulate functions, create new conda environments and switch between them. -------------------------------------------------------------------------------- /gitlabCI/scripts/simple_markdown.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "`Rmarkdown` in `PockeR`: an example" 3 | author: "Lino Galiana" 4 | date: "`r format(Sys.Date(), format = '%d %B %Y')` " 5 | output: 6 | html_document: 7 | css: ./style.css 8 | --- 9 | 10 | ```{r setup, include=FALSE} 11 | knitr::opts_chunk$set(echo = TRUE) 12 | knitr::knit_engines$set(python = reticulate::eng_python) 13 | ``` 14 | 15 | This `markdown` is used to test if `Python` works in `PockeR` repository. It is automatically built using continuous integration. 16 | 17 | This `markdown` is also the occasion to compare `Rcpp`, `Python` and `R` speed on the same program, a cumulative sum. I use, in the three cases, loops even if I know it is inefficient. 18 | 19 | To be able to export `Python` output into `R`, we need to load `reticulate` package 20 | 21 | ```{r, include=FALSE} 22 | library(reticulate) 23 | ``` 24 | 25 | 26 | 27 | # Python 28 | 29 | 30 | 31 | ```{python, eval = TRUE} 32 | import numpy as np 33 | import datetime 34 | import statistics 35 | 36 | def cumsum_py(n = 1000): 37 | start = datetime.datetime.now() 38 | x = np.random.uniform(0,1,n) 39 | for i in range(1,n): 40 | x[i] += x[i-1] 41 | end = datetime.datetime.now() 42 | c = end - start 43 | return(c.microseconds/1000) 44 | 45 | exec_time_python = [cumsum_py(100000) for k in range(100)] 46 | 47 | print("Time for a cumulative sum over a vector of size 1000 (milliseconds):") 48 | print(statistics.median(exec_time_python)) 49 | 50 | ``` 51 | 52 | # `R` 53 | 54 | ```{r} 55 | 56 | cumsum_R <- function(n = 1000){ 57 | start <- Sys.time() 58 | x = runif(n) 59 | for (i in seq(from = 3, to = n)){ 60 | x[i] <- x[i] + x[i-1] 61 | } 62 | end <- Sys.time() 63 | c <- as.numeric(difftime(end, start, units="secs")) 64 | return(c*1000) 65 | } 66 | 67 | exec_time_R = replicate(100, cumsum_R(100000)) 68 | 69 | print("Time for a cumulative sum over a vector of size 1000 (milliseconds):") 70 | print(median(exec_time_R)) 71 | 72 | ``` 73 | 74 | # `Rcpp` 75 | 76 | ```{Rcpp, eval = FALSE} 77 | #include 78 | #include 79 | 80 | using namespace Rcpp; 81 | 82 | // [[Rcpp::export]] 83 | double cumsum_cpp(int n) { 84 | 85 | // start the timer 86 | Timer timer; 87 | timer.step("start"); // record the starting point 88 | 89 | NumericVector x = runif(n); 90 | 91 | for (int i = 1 ; i < x.length() ; i++){ 92 | x[i] += x[i-1]; 93 | } 94 | 95 | timer.step("end"); // record the final step 96 | 97 | 98 | NumericVector res(timer); // 99 | for (int i=0; i