Revision: 562
          http://rpy.svn.sourceforge.net/rpy/?rev=562&view=rev
Author:   lgautier
Date:     2008-06-12 02:06:37 -0700 (Thu, 12 Jun 2008)

Log Message:
-----------
rinterface:
  - functions evaluated in R_GlobalEnv

robjects:
  - methods __setitem__, getNames and setNames for RVector
  - method getNames for RArray
  - docstring for "RObjectMixin.rclass()"

doc:
  - robjects: minor editing, list the classes RArray and RMatrix
  - rinterface: more about vector element names
  - notes on the design

demos:
  - improved the R GTK console
  - fixed listing of graphical devices

Modified Paths:
--------------
    branches/rpy_nextgen/demos/radmin.py
    branches/rpy_nextgen/doc/source/overview.rst
    branches/rpy_nextgen/doc/source/rinterface.rst
    branches/rpy_nextgen/doc/source/robjects.rst
    branches/rpy_nextgen/rpy/rinterface/rinterface.c
    branches/rpy_nextgen/rpy/robjects/__init__.py
    branches/rpy_nextgen/rpy/robjects/tests/testRArray.py
    branches/rpy_nextgen/rpy/robjects/tests/testRFunction.py
    branches/rpy_nextgen/rpy/robjects/tests/testRVector.py

Modified: branches/rpy_nextgen/demos/radmin.py
===================================================================
--- branches/rpy_nextgen/demos/radmin.py        2008-06-10 17:35:25 UTC (rev 
561)
+++ branches/rpy_nextgen/demos/radmin.py        2008-06-12 09:06:37 UTC (rev 
562)
@@ -252,11 +252,11 @@
         except:
             return
         for dev, name in itertools.izip(devices, names):
-            if current_device == dev[0]:
+            if current_device == dev:
                 cur = "X"
             else:
                 cur = ""
-            row = [cur, dev[0], name[0], ""]
+            row = [cur, dev, name, ""]
             self._table.append(row)
 
     def searchOpenedDevices(self, widget, data = None):
@@ -354,7 +354,7 @@
         self._rpad.show()
         s_window.add(self._rpad)
         self.add(s_window)
-        evalButton = gtk.Button("Evaluate")
+        evalButton = gtk.Button("Evaluate highlighted code")
         evalButton.connect("clicked", self.evaluateAction, "evaluate")
         evalButton.show()
         self.pack_start(evalButton, False, False, 0)
@@ -422,6 +422,12 @@
 
 class ConsolePanel(gtk.VBox):
 
+    tag_table = None
+    _buffer = None
+    _view = None
+    _evalButton = None
+    _start_mark = None
+
     def __init__(self):
         super(ConsolePanel, self).__init__()
         s_window = gtk.ScrolledWindow()
@@ -452,7 +458,7 @@
         self.add(s_window)
         evalButton = gtk.Button("Evaluate")
         evalButton.connect("clicked", self.evaluateAction, "evaluate")
-        evalButton.show()
+        #evalButton.show()
         self.pack_start(evalButton, False, False, 0)
         self._evalButton = evalButton
         self.append("> ", "input")
@@ -461,8 +467,13 @@
         self._start_mark = self._buffer.create_mark("beginCode",
                                                     location, 
left_gravity=True)
 
+        self._firstEnter = False
+
     def actionKeyPress(self, view, event):
-        pass
+        if (event.keyval == gtk.gdk.keyval_from_name("Return")):
+            self.append("\n", "input")
+            self.evaluateAction(self._evalButton)
+            return True
 
     def append(self, text, tag="input"):
         tag = self.tag_table.lookup(tag)
@@ -477,6 +488,7 @@
     def evaluateAction(self, widget, data=None):
         buffer = self._buffer
         start_iter = buffer.get_iter_at_mark(self._start_mark)
+
         stop_iter = buffer.get_iter_at_offset(buffer.get_char_count())
         rcode = buffer.get_text(start_iter, stop_iter)
 
@@ -496,10 +508,13 @@
 
         self.append("\n> ", "input")
 
-        buffer.move_mark(self._start_mark,
-                         buffer.get_iter_at_offset(buffer.get_char_count()))
+        textIter = buffer.get_iter_at_offset(buffer.get_char_count())
+        buffer.move_mark(self._start_mark, textIter)
+        buffer.move_mark_by_name("insert",
+                                 textIter)
+        buffer.move_mark_by_name("selection_bound",
+                                 textIter)
 
-
 class Main(object):
 
     def __init__(self):

Modified: branches/rpy_nextgen/doc/source/overview.rst
===================================================================
--- branches/rpy_nextgen/doc/source/overview.rst        2008-06-10 17:35:25 UTC 
(rev 561)
+++ branches/rpy_nextgen/doc/source/overview.rst        2008-06-12 09:06:37 UTC 
(rev 562)
@@ -58,3 +58,21 @@
 API.
 
 
+
+Design notes
+------------
+
+:mod:`rpy2.robjects` implements an extension to the interface in
+:mod:`rpy2.rinterface` by extending the classes for R
+objects defined there with child classes.
+
+The choice of inheritance was made to facilitate the implementation
+of mostly inter-exchangeable classes between :mod:`rpy2.rinterface`
+and :mod:`rpy2.robjects`: an :class:`rpy2.rinterface.SexpClosure`
+can be given any :class:`rpy2.robjects.RObject` as a parameter while
+any :class:`rpy2.robjects.RFunction` can be given any 
+:class:`rpy2.rinterface.Sexp`.
+
+The module :mod:`rpy2.rpy_classic` is using delegation, letting us
+demonstrate how to extend :mod:`rpy2.rinterface` with an alternative
+to inheritance.
\ No newline at end of file

Modified: branches/rpy_nextgen/doc/source/rinterface.rst
===================================================================
--- branches/rpy_nextgen/doc/source/rinterface.rst      2008-06-10 17:35:25 UTC 
(rev 561)
+++ branches/rpy_nextgen/doc/source/rinterface.rst      2008-06-12 09:06:37 UTC 
(rev 562)
@@ -185,31 +185,54 @@
 .. note::
    The *__getitem__* operator *[*
    is returning a Python scalar. Casting
-   an *SexpVector* into a list is only a matter of calling
-   the constructor *list*.
+   an *SexpVector* into a list is only a matter 
+   either iterating through it, or simply calling
+   the constructor :func:`list`.
 
 
+Common attributes
+-----------------
+
+.. index::
+   single: names
+
 Names
------
+^^^^^
 
 In R, vectors can be named, that is each value in the vector
 can be given a name (that is be associated a string).
 The names are added to the other as an attribute (conveniently
-called names), and can be accessed as such:
+called `names`), and can be accessed as such:
 
 >>> options = rinterface.globalEnv.get("options")()
 >>> option_names = options.do_slot("names")
 >>> [x for x in options_names]
 
+.. note::
+   Elements in a vector of names do not have to be unique.
 
 .. index::
+   single: dim
+   single: dimnames
+
+
+Dim and dimnames
+^^^^^^^^^^^^^^^^
+
+In the case of an `array`, the names across the
+respective dimensions of the object are accessible
+through the slot named `dimnames`.
+
+
+
+.. index::
    pair: SexpVector; numpy
 
 Numpy
 -----
 
-The SexpVector objects are made to behave like arrays as defined
-in the Python package numpy.
+The :class:`SexpVector` objects are made to behave like arrays as defined
+in the Python package :mod:`numpy`.
 
 The functions *array* and *asarray* is all that is needed:
 
@@ -220,7 +243,7 @@
 
 
 .. note::
-   when using *asarray*, the data are not copied.
+   when using :meth:`asarray`, the data are not copied.
 
 >>> nx_nc[2] = 42
 >>> rx[2]
@@ -325,6 +348,9 @@
 >>>
 
 
+
+
+
 Misc. variables
 ===============
 

Modified: branches/rpy_nextgen/doc/source/robjects.rst
===================================================================
--- branches/rpy_nextgen/doc/source/robjects.rst        2008-06-10 17:35:25 UTC 
(rev 561)
+++ branches/rpy_nextgen/doc/source/robjects.rst        2008-06-12 09:06:37 UTC 
(rev 562)
@@ -31,6 +31,8 @@
 - no CONVERSION mode in :mod:`rpy2`, the design has made this unnecessary
 
 
+
+
 `r`: the instance of `R`
 ==============================
 
@@ -45,8 +47,8 @@
 embedded R process, and the elements that would be accessible
 from an equivalent R environment are accessible as attributes
 of the instance.
-Readers familiar with the ctypes module for Python will note
-the similarity with ctypes.
+Readers familiar with the :mod:`ctypes` module for Python will note
+the similarity with it.
 
 R vectors:
 
@@ -59,19 +61,33 @@
 >>> plot = robjects.r.plot
 >>> dir = robjects.r.dir
 
-Just like it was the case with RPy-1.x, on-the-fly
+
+Strings as R code
+-----------------
+
+Just like it is the case with RPy-1.x, on-the-fly
 evaluation of R code contained in a string can be performed
-by calling the r instance:
+by calling the `r` instance:
 
->>> robjects.r('1:2')
+>>> robjects.r('1+2')
 3
 >>> sqr = ro.r('function(x) x^2)
+
 >>> sqr
 function (x)
 x^2
 >>> sqr(2)
 4
 
+The astute reader will quickly realize that R objects named
+by python variables can
+be plugged into code by their string representation:
+
+>>> x = robjects.r.rnorm(100)
+>>> robjects.r('hist(%s, xlab="x", main="hist(x)")' %x.__repr__())
+
+
+
 .. index::
    pair: robjects;RObject
 
@@ -107,9 +123,9 @@
 Operators
 ---------
 
-Mathematical operations on vectors: the following operations
-are performed element-wise, recycling the shortest vector if
-necessary.
+Mathematical operations on two vectors: the following operations
+are performed element-wise, recycling the shortest vector if, and
+as much as, necessary.
 
 +--------+---------+
 | ``+``  | Add     |
@@ -122,6 +138,10 @@
 +--------+---------+
 | ``**`` | Power   |
 +--------+---------+
+| ``or`` | Or      |
++--------+---------+
+| ``and``| And     |
++--------+---------+
 
 .. index::
    pair: RVector;indexing
@@ -145,6 +165,9 @@
 integer(0)
 >>> x.subset(1)
 1L
+
+The two next examples demonstrate features of `R` regarding indexing,
+respectively element exclusion and recycling rule:
 >>> x.subset(-1)
 2:10
 >>> x.subset(True)
@@ -175,6 +198,19 @@
    pair: robjects;REnvironment
    pair: robjects;globalEnv
 
+:class:`RArray`
+---------------
+
+In `R`, arrays are simply vectors with a dimension attribute. That fact
+was reflected in the class hierarchy with :class:`robjects.RArray` inheriting
+from :class:`robjects.RVector`.
+
+:class:`RMatrix`
+----------------
+
+A :class:`RMatrix` is a special case of :class:`RArray`.
+
+
 R environments
 ==============
 
@@ -200,15 +236,15 @@
 
 
 Care must be taken when assigning objects into an environment
-such as the Global Environment, as it can hide other objects
+such as the Global Environment, as this can hide other objects
 with an identical name.
-For example:
+The following example should make one measure that this can mean
+trouble if no care is taken:
 
 >>> globalEnv["pi"] = 123
 >>> robjects.r.pi
 123L
 >>>
-
 >>> robjects.r.rm("pi")
 >>> robjects.r.pi
 3.1415926535897931

Modified: branches/rpy_nextgen/rpy/rinterface/rinterface.c
===================================================================
--- branches/rpy_nextgen/rpy/rinterface/rinterface.c    2008-06-10 17:35:25 UTC 
(rev 561)
+++ branches/rpy_nextgen/rpy/rinterface/rinterface.c    2008-06-12 09:06:37 UTC 
(rev 562)
@@ -771,8 +771,8 @@
   }
   
 //FIXME: R_GlobalContext ?
-  //PROTECT(res_R = do_eval_expr(call_R, R_GlobalEnv));
-  PROTECT(res_R = do_eval_expr(call_R, CLOENV(fun_R)));
+  PROTECT(res_R = do_eval_expr(call_R, R_GlobalEnv));
+  //PROTECT(res_R = do_eval_expr(call_R, CLOENV(fun_R)));
 
 /*   if (!res) { */
 /*     UNPROTECT(2); */

Modified: branches/rpy_nextgen/rpy/robjects/__init__.py
===================================================================
--- branches/rpy_nextgen/rpy/robjects/__init__.py       2008-06-10 17:35:25 UTC 
(rev 561)
+++ branches/rpy_nextgen/rpy/robjects/__init__.py       2008-06-12 09:06:37 UTC 
(rev 562)
@@ -105,6 +105,7 @@
         return repr_robject(self)
 
     def rclass(self):
+        """ Return the name of the R class for the object. """
         return baseNameSpaceEnv["class"](self)
 
 
@@ -150,12 +151,24 @@
         res = r["["](*([self, ] + [x for x in args]), **kwargs)
         return res
 
+    def assign(self, *args):
+        #FIXME: value must be the last argument, but this can be
+        # challenging in since python kwargs do not enforce any order
+        args = [py2ro(x) for x in args]
+        res = r["[<-"](*([self, ] + [x for x in args]))
+
+        return res
+
     def __getitem__(self, i):
         res = super(RVector, self).__getitem__(i)
         if isinstance(res, rinterface.Sexp):
             res = ri2py(res)
         return res
 
+    def __setitem__(self, i, value):
+        value = py2ri(value)
+        res = super(RVector, self).__setitem__(i, value)
+
     def __add__(self, x):
         res = r.get("+")(self, x)
         return res
@@ -188,13 +201,20 @@
         res = r.names(self)
         return res
 
+    def setNames(self, value):
+        """ Return a vector of names
+        (like the R function 'names' does it)."""
+
+        res = r["names<-"](self, value)
+        return res
+
 class RArray(RVector):
     """ An R array """
     def __init__(self, o):
         super(RArray, self).__init__(o)
         #import pdb; pdb.set_trace()
         if not r["is.array"](self)[0]:
-            raise(TypeError("The object must be reflecting an R array"))
+            raise(TypeError("The object must be representing an R array"))
 
     def __getattr__(self, name):
         if name == 'dim':
@@ -206,6 +226,13 @@
         if name == 'dim':
             value = py2ro(value)
             res = r["dim<-"](value)
+
+    def getNames(self):
+        """ Return a list of name vectors
+        (like the R function 'dimnames' does it)."""
+
+        res = r.dimnames(self)
+        return res
         
 
 class RMatrix(RArray):

Modified: branches/rpy_nextgen/rpy/robjects/tests/testRArray.py
===================================================================
--- branches/rpy_nextgen/rpy/robjects/tests/testRArray.py       2008-06-10 
17:35:25 UTC (rev 561)
+++ branches/rpy_nextgen/rpy/robjects/tests/testRArray.py       2008-06-12 
09:06:37 UTC (rev 562)
@@ -20,8 +20,17 @@
         self.assertEquals(5, d[0])
         self.assertEquals(3, d[1])
 
+    def testGetNames(self):
+        dimnames = robjects.r.list(['a', 'b', 'c'],
+                                   ['d', 'e'])
+        m = robjects.r.matrix(1, nrow=3, ncol=2,
+                              dimnames = dimnames)
+        a = robjects.RArray(m)
+        res = a.getNames()
+        r_identical = robjects.r.identical
+        self.assertTrue(r_identical(dimnames[0], res[0]))
+        self.assertTrue(r_identical(dimnames[1], res[1]))
 
-
 def suite():
     suite = unittest.TestLoader().loadTestsFromTestCase(RArrayTestCase)
     return suite

Modified: branches/rpy_nextgen/rpy/robjects/tests/testRFunction.py
===================================================================
--- branches/rpy_nextgen/rpy/robjects/tests/testRFunction.py    2008-06-10 
17:35:25 UTC (rev 561)
+++ branches/rpy_nextgen/rpy/robjects/tests/testRFunction.py    2008-06-12 
09:06:37 UTC (rev 562)
@@ -22,7 +22,21 @@
         
         s = ro_f(ro_v)
 
+    def testCallWithSexp(self):
+        ro_f = robjects.baseNameSpaceEnv["sum"]
+        ri_vec = robjects.rinterface.SexpVector([1,2,3], 
+                                                robjects.rinterface.INTSXP)
+        res = ro_f(ri_vec)
+        self.assertEquals(6, res[0])
 
+    def testCallClosureWithRObject(self):
+        ri_f = rinterface.baseNameSpaceEnv["sum"]
+        ro_vec = robjects.RVector(array.array('i', [1,2,3]))
+        res = ri_f(ro_vec)
+        self.assertEquals(6, res[0])
+
+
+
 def suite():
     suite = unittest.TestLoader().loadTestsFromTestCase(RFunctionTestCase)
     return suite

Modified: branches/rpy_nextgen/rpy/robjects/tests/testRVector.py
===================================================================
--- branches/rpy_nextgen/rpy/robjects/tests/testRVector.py      2008-06-10 
17:35:25 UTC (rev 561)
+++ branches/rpy_nextgen/rpy/robjects/tests/testRVector.py      2008-06-12 
09:06:37 UTC (rev 562)
@@ -33,7 +33,7 @@
             self.assertEquals(mySeq[i] * 2, mySeqAdd[i])
 
         
-    def testSubset(self):
+    def testSubsetByIndex(self):
         seq_R = robjects.baseNameSpaceEnv["seq"]
         mySeq = seq_R(0, 10)
         # R indexing starts at one
@@ -43,6 +43,39 @@
         for i, si in enumerate(myIndex):
             self.assertEquals(mySeq[si-1], mySubset[i])
 
+    def testSubsetByName(self):
+        seq_R = robjects.baseNameSpaceEnv["seq"]
+        mySeq = seq_R(0, 25)
+
+        letters = robjects.baseNameSpaceEnv["letters"]
+        mySeq = robjects.baseNameSpaceEnv["names<-"](mySeq, 
+                                                     letters)
+
+        # R indexing starts at one
+        myIndex = robjects.RVector(letters[2])
+
+        mySubset = mySeq.subset(myIndex)
+
+        for i, si in enumerate(myIndex):
+            self.assertEquals(2, mySubset[i])
+
+    def testSubsetIndexError(self):
+        seq_R = robjects.baseNameSpaceEnv["seq"]
+        mySeq = seq_R(0, 10)
+        # R indexing starts at one
+        myIndex = robjects.RVector(['a', 'b', 'c'])
+
+        self.assertRaises(ri.RRuntimeError, mySeq.subset, myIndex)
+
+
+    def testAssign(self):
+        vec = robjects.r.seq(1, 10)
+        vec = vec.assign(array.array('i', [1, 3, 5]), 20)
+        self.assertEquals(20, vec[0])
+        self.assertEquals(20, vec[2])
+        self.assertEquals(20, vec[4])
+
+    
     def testSubsetRecyclingRule(self):
         # recycling rule
         v = robjects.RVector(array.array('i', range(1, 23)))
@@ -50,7 +83,7 @@
         col = m.subset(True, 1)
         self.assertEquals(11, len(col))
 
-    def testSubsetLiet(self):
+    def testSubsetList(self):
         # list
         letters = robjects.baseNameSpaceEnv["letters"]
         myList = rlist(l=letters, f="foo")
@@ -67,6 +100,15 @@
         letters = robjects.baseNameSpaceEnv["letters"]
         self.assertRaises(IndexError, letters.__getitem__, 26)
 
+    def testSetItem(self):
+        vec = robjects.r.seq(1, 10)
+        vec[0] = 20
+        self.assertEquals(20, vec[0])
+
+    def testSetItemOutOfBounds(self):
+        vec = robjects.r.seq(1, 10)
+        self.assertRaises(IndexError, vec.__setitem__, 20, 20)
+
     def getItemList(self):
         mylist = rlist(letters, "foo")
         idem = robjects.baseNameSpaceEnv["identical"]
@@ -78,10 +120,20 @@
         v_names = [robjects.baseNameSpaceEnv["letters"][x] for x in (0,1,2)]
         #FIXME: simplify this
         r_names = robjects.baseNameSpaceEnv["c"](*v_names)
-        vec = robjects.r["names<-"](vec, r_names)
+        vec = robjects.baseNameSpaceEnv["names<-"](vec, r_names)
         for i in xrange(len(vec)):
             self.assertEquals(v_names[i], vec.getNames()[i])
 
+        vec.getNames()[0] = 'x'
+
+    def testSetNames(self):
+        vec = robjects.RVector(array.array('i', [1,2,3]))
+        names = ['x', 'y', 'z']
+        #FIXME: simplify this
+        vec = vec.setNames(names)
+        for i in xrange(len(vec)):
+            self.assertEquals(names[i], vec.getNames()[i])
+
 def suite():
     suite = unittest.TestLoader().loadTestsFromTestCase(RVectorTestCase)
     return suite


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
rpy-list mailing list
rpy-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/rpy-list

Reply via email to