arrgh

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 12, 2018 License: BSD-3-Clause Imports: 13 Imported by: 0

README

arrgh (Pronunciation: /ɑː/ or /är/) is an interface to the OpenCPU R server system.

Build Status Coverage Status GoDoc

Overview

The arrgh package provides API interfaces to remote or local OpenCPU R servers.

Go is a well established network systems language and has seen increasing use in data science and other fields of scientific software development. The arrgh package allows developers to leverage the rich statistical analysis environment available through R that is lacking in the Go ecosystem.

Example

package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/kortschak/arrgh"
)

func main() {
	r, err := arrgh.NewRemoteSession("http://public.opencpu.org", "", 10*time.Second)
	if err != nil {
		log.Fatal(err)
	}
	defer r.Close()

	// Send a query to get a session result for the linear
	// regression: coef(lm(speed~dist, data=cars)).
	resp, err := r.Post(
		"library/base/R/identity",
		"application/x-www-form-urlencoded",
		nil,
		strings.NewReader("x="+url.QueryEscape("coef(lm(speed ~ dist, data = cars))")),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	// Get each part of the session result and display it,
	// keeping the location of the linear regression.
	sc := bufio.NewScanner(resp.Body)
	var val string
	for sc.Scan() {
		// API root path stripping here depends on consistency
		// between os.Separator and the URL path separator.
		p, err := filepath.Rel(r.Root(), sc.Text())
		if err != nil {
			log.Fatal(err)
		}
		if path.Base(p) == ".val" {
			val = p
		}
		fmt.Printf("%s:\n", p)

		resp, err := r.Get(p, nil)
		if err != nil {
			log.Fatal(err)
		}
		io.Copy(os.Stdout, resp.Body)
		fmt.Print("\n\n")
		resp.Body.Close()
	}

	// Get the linear regression result as JSON.
	res, err := r.Get(path.Join(val, "json"), url.Values{"digits": []string{"10"}})
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()

	// Decode the result into a [2]float64.
	var lm [2]float64
	dec := json.NewDecoder(res.Body)
	err = dec.Decode(&lm)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("lm: intercept=%f dist=%f\n", lm[0], lm[1])
}

Output:

tmp/x0113a3ca85/R/identity:
function (x) 
x
<bytecode: 0x55d13e1f40a0>
<environment: namespace:base>


tmp/x0113a3ca85/R/.val:
(Intercept)        dist 
  8.2839056   0.1655676 


tmp/x0113a3ca85/stdout:
(Intercept)        dist 
  8.2839056   0.1655676 


tmp/x0113a3ca85/source:
identity(x = coef(lm(speed ~ dist, data = cars)))

tmp/x0113a3ca85/console:
> identity(x = coef(lm(speed ~ dist, data = cars)))
(Intercept)        dist 
  8.2839056   0.1655676 

tmp/x0113a3ca85/info:
R version 3.4.1 (2017-06-30)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 16.04.2 LTS

Matrix products: default
BLAS: /usr/lib/openblas-base/libblas.so.3
LAPACK: /usr/lib/libopenblasp-r0.2.18.so

locale:
 [1] LC_CTYPE=en_US.UTF-8    LC_NUMERIC=C            LC_TIME=en_US.UTF-8    
 [4] LC_COLLATE=en_US.UTF-8  LC_MONETARY=en_US.UTF-8 LC_MESSAGES=C          
 [7] LC_PAPER=C              LC_NAME=C               LC_ADDRESS=C           
[10] LC_TELEPHONE=C          LC_MEASUREMENT=C        LC_IDENTIFICATION=C    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] opencpu_2.0.3.1

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.11     lattice_0.20-35  mime_0.5         plyr_1.8.4      
 [5] grid_3.4.1       gtable_0.2.0     sys_1.4          jsonlite_1.5    
 [9] unix_1.3         magrittr_1.5     scales_0.4.1     evaluate_0.10.2 
[13] ggplot2_2.2.1    rlang_0.1.1      stringi_1.1.5    curl_2.7        
[17] lazyeval_0.2.0   webutils_0.6     tools_3.4.1      stringr_1.2.0   
[21] munsell_0.4.3    parallel_3.4.1   sendmailR_1.2-1  compiler_3.4.1  
[25] colorspace_1.3-2 base64enc_0.1-3  openssl_0.9.6    tibble_1.3.3    


tmp/x0113a3ca85/files/DESCRIPTION:
Package: x0113a3ca85
Type: Session
Version: 2.0.3.1
Author: OpenCPU
Date: 2017-07-07
Description: This file is automatically generated by OpenCPU.


lm: intercept=8.283906 dist=0.165568

Installation

arrgh requires a Go installation, and if using a local R instance OpenCPU (tested on v1.6 and v2.0) and semver must be installed as R packages.

go get github.com/kortschak/arrgh

See the OpenCPU CRAN page for a complete description of OpenCPU R and system dependencies and this page for instructions for installing OpenCPU from source.

Documentation

http://godoc.org/github.com/kortschak/arrgh

Getting help

Help or similar requests can be asked on the bug tracker, or for more general OpenCPU questions at the OpenCPU google groups.

https://groups.google.com/forum/#!forum/opencpu

Contributing

If you find any bugs, feel free to file an issue on the github issue tracker. Pull requests are welcome.

License

arrgh is distributed under a modified BSD license.

Documentation

Overview

Package arrgh provides an interface to R via an OpenCPU server.

Interaction with the OpenCPU system is via the OpenCPU API https://www.opencpu.org/api.html. Data serialisation and deserialisation at the R end is performed by jsonlite, see http://cran.r-project.org/web/packages/jsonlite/jsonlite.pdf for the jsonlite manual.

Example (Linear)
package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/kortschak/arrgh"
)

func main() {
	r, err := arrgh.NewRemoteSession("http://public.opencpu.org", "", 10*time.Second)
	if err != nil {
		log.Fatal(err)
	}
	defer r.Close()

	// Send a query to get a session result for the linear
	// regression: coef(lm(speed~dist, data=cars)).
	resp, err := r.Post(
		"library/base/R/identity",
		"application/x-www-form-urlencoded",
		nil,
		strings.NewReader("x="+url.QueryEscape("coef(lm(speed ~ dist, data = cars))")),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	// Get each part of the session result and display it,
	// keeping the location of the linear regression.
	sc := bufio.NewScanner(resp.Body)
	var val string
	for sc.Scan() {
		// API root path stripping here depends on consistency
		// between os.Separator and the URL path separator.
		p, err := filepath.Rel(r.Root(), sc.Text())
		if err != nil {
			log.Fatal(err)
		}
		if path.Base(p) == ".val" {
			val = p
		}
		fmt.Printf("%s:\n", p)

		resp, err := r.Get(p, nil)
		if err != nil {
			log.Fatal(err)
		}
		io.Copy(os.Stdout, resp.Body)
		fmt.Print("\n\n")
		resp.Body.Close()
	}

	// Get the linear regression result as JSON.
	res, err := r.Get(path.Join(val, "json"), url.Values{"digits": []string{"10"}})
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()

	// Decode the result into a [2]float64.
	var lm [2]float64
	dec := json.NewDecoder(res.Body)
	err = dec.Decode(&lm)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("lm: intercept=%f dist=%f\n", lm[0], lm[1])
}
Output:

Example (Local)
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/kortschak/arrgh"
)

func main() {
	r, err := arrgh.NewLocalSession("", "", 3000, 10*time.Second, os.Stderr)
	if err != nil {
		log.Fatal(err)
	}
	defer r.Close()

	// Send a query to get a JSON representation of results
	// from rnorm(n=10, mean=10, sd=10).
	resp, err := r.Post(
		"library/stats/R/rnorm/json",
		"application/json",
		url.Values{"digits": []string{"10"}},
		strings.NewReader(`{"n":10, "mean": 10, "sd":10}`),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	// Decode the results in to a slice of float64.
	var rnorm []float64
	dec := json.NewDecoder(resp.Body)
	err = dec.Decode(&rnorm)

	fmt.Println(rnorm, err)
}
Output:

Example (Upload)
package main

import (
	"bytes"
	"io"
	"log"
	"os"
	"regexp"
	"time"

	"github.com/kortschak/arrgh"
)

func mask(r io.Reader) io.Reader {
	re := regexp.MustCompile("x[0-9a-f]{10}")
	var buf bytes.Buffer
	io.Copy(&buf, r)
	return bytes.NewReader(re.ReplaceAll(buf.Bytes(), []byte("xXXXXXXXXXX")))
}

func main() {
	r, err := arrgh.NewRemoteSession("http://public.opencpu.org", "", 10*time.Second)
	if err != nil {
		log.Fatal(err)
	}
	defer r.Close()

	// Upload the contents of the file "mydata.csv" and send
	// it to the read.csv function.
	f, err := os.Open("mydata.csv")
	if err != nil {
		log.Fatal(err)
	}
	content, body, err := arrgh.Multipart(
		arrgh.Params{"header": "FALSE"},
		arrgh.Files{"file": f},
	)
	f.Close()
	if err != nil {
		log.Fatal(err)
	}
	resp, err := r.Post(
		"library/utils/R/read.csv",
		content,
		nil,
		body,
	)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	io.Copy(os.Stdout, mask(resp.Body))

}
Output:


/ocpu/tmp/xXXXXXXXXXX/R/read.csv
/ocpu/tmp/xXXXXXXXXXX/R/.val
/ocpu/tmp/xXXXXXXXXXX/stdout
/ocpu/tmp/xXXXXXXXXXX/source
/ocpu/tmp/xXXXXXXXXXX/console
/ocpu/tmp/xXXXXXXXXXX/info
/ocpu/tmp/xXXXXXXXXXX/files/DESCRIPTION
/ocpu/tmp/xXXXXXXXXXX/files/mydata.csv

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Multipart

func Multipart(parameters Params, files Files) (content string, body io.Reader, err error)

Multipart constructs a MIME multipart body and associated content type from the provided parameters and files.

Types

type Files

type Files map[string]NamedReader

Params is a collection of parameter names and file objects to be passed using Multipart.

type NamedReader

type NamedReader interface {
	io.Reader
	Name() string
}

NamedReader allows an io.Reader to be passed as a named data file object.

type Params

type Params map[string]string

Params is a collection of parameter names and values to be passed using Multipart.

type Session

type Session struct {
	// contains filtered or unexported fields
}

Session holds OpenCPU session connection information.

func NewLocalSession

func NewLocalSession(path, root string, port int, timeout time.Duration, log io.Writer) (*Session, error)

NewLocalSession starts an R instance using the executable in the given path or the executable "R" in the user's $PATH if path is empty. An OpenCPU server is started using the provided port and connection is tested before returning. If no connection is possible within the timeout, a nil session and an error are returned. The root of the OpenCPU API is set to "/ocpu" if it is left empty. The OpenCPU server's logs are written to log.

It is important that Close() be called on sessions returned by NewLocalSession.

func NewRemoteSession

func NewRemoteSession(host, root string, timeout time.Duration) (*Session, error)

NewRemoteSession connects to the OpenCPU server at the specified host. The root of the OpenCPU API is set to "/ocpu" if it is left empty.

func (*Session) Close

func (s *Session) Close() error

Close shuts down a running local session, terminating the OpenCPU server and the R session. It is a no-op on a remote session.

func (*Session) Get

func (s *Session) Get(path string, params url.Values) (*http.Response, error)

Get retrieves the given OpenCPU path using the GET method. The URL parameters specify GET parameters which are interpreted by jsonlite.

See https://www.opencpu.org/api.html#api-methods for details.

func (*Session) Post

func (s *Session) Post(path, content string, params url.Values, query io.Reader) (*http.Response, error)

Post sends the query content to the given OpenCPU path as the specified content type using the POST method. The URL parameters specify additional POST parameters. These parameters are interpreted by jsonlite.

See https://www.opencpu.org/api.html#api-methods and https://www.opencpu.org/api.html#api-arguments for details.

func (*Session) Root

func (s *Session) Root() string

Root returns the OpenCPU root path.

Directories

Path Synopsis
paper
example/nuccore
The nuccore program summarises the lengths of sequences in the nuccore database in Entrez that are linked from genomes studies.
The nuccore program summarises the lengths of sequences in the nuccore database in Entrez that are linked from genomes studies.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL