-
Notifications
You must be signed in to change notification settings - Fork 0
/
simpler.py
113 lines (97 loc) · 3.06 KB
/
simpler.py
1
2
3
4
5
6
7
8
9
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import numpy as np
import sys
import rpy2.rinterface as ri
import rpy2.robjects as ro
from rpy2.robjects.numpy2ri import numpy2ri
ro.conversion.py2ri = numpy2ri
from IPython.extensions.rmagic import RInterpreterError, Rconverter
from IPython.utils.py3compat import str_to_unicode, unicode_to_str, PY3
__all__ = ['r']
class _RMagic(object):
"""
Stripped down version of IPython's RMagic, suitable for use
outside of ipython.
"""
def __init__(self, pyconverter=np.asarray):
self._Rstdout_cache = []
self._r = ro.R()
self._pyconverter = pyconverter
self._Rconverter = Rconverter
def push(self, **kwargs):
"""Send values to the R interpreter
Usage
-----
>>> r.push(a=12) # set r's a equal to 1
>>> r.eval('print(a)')
[1] 12
"""
for k,v in kwargs.iteritems():
self._r.assign(k, self._pyconverter(v))
def get(self, key, as_dataframe=True):
"""Get a value from the R interpreter
Parameters
----------
key : str
The name of the varaible to pull from r
Usage
-----
>>> r.push(a=12)
>>> print r.get('a')
[12]
"""
return self._Rconverter(self._r[key], dataframe=as_dataframe)
def eval(self, line):
"""Evaluate a line or block of code in R
Parameters
----------
line : str
The code to execute
Examples
--------
>>> r.eval('''
... x = 1:5
... df = data.frame(x=x, y=x^2)
... print(df)
... ''')
x y
1 1 1
2 2 4
3 3 9
4 4 16
5 5 25
"""
old_writeconsole = ri.get_writeconsole()
ri.set_writeconsole(self._write_console)
try:
value = ri.baseenv['eval'](ri.parse(line))
except (ri.RRuntimeError, ValueError) as exception:
warning_or_other_msg = self._flush() # otherwise next return seems to have copy of error
raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg)
text_output = self._flush()
ri.set_writeconsole(old_writeconsole)
if text_output:
sys.stdout.write(unicode_to_str(text_output, 'utf-8'))
def _write_console(self, output):
'''
A hook to capture R's stdout in a cache.
'''
self._Rstdout_cache.append(output)
def _flush(self):
'''
Flush R's stdout cache to a string, returning the string.
'''
value = ''.join([str_to_unicode(s, 'utf-8') for s in self._Rstdout_cache])
self._Rstdout_cache = []
return value
# create an instance of the class that can be imported
r = _RMagic()
if __name__ == '__main__':
x = np.arange(10)
r.push(x=x)
r.eval('''
library(ggplot2)
df = data.frame(x=x, y=x^2)
ggplot(data=df, aes(x=x, y=y)) + geom_line()
ggsave('plot.png')
system('open plot.png')
''')