Ticket #3121: trac-3121-input-grid.patch

File trac-3121-input-grid.patch, 12.3 KB (added by jason, 13 years ago)
  • sage/server/notebook/all.py

    # HG changeset patch
    # User Jason Grout <jason-sage@creativetrax.com>
    # Date 1210210110 18000
    # Node ID f5ebd8f2f8995085b4645b456ab13d4b9596ed70
    # Parent  23d0e6b6a67514295103c8fecd63a9ec0a5c77db
    [mq]: trac-3121-input-grid.patch
    
    diff -r 23d0e6b6a675 -r f5ebd8f2f899 sage/server/notebook/all.py
    a b  
    1414
    1515from sagetex import sagetex
    1616
    17 from interact import interact, input_box, slider, selector, checkbox
     17from interact import interact, input_box, slider, selector, checkbox, input_grid
  • sage/server/notebook/interact.py

    diff -r 23d0e6b6a675 -r f5ebd8f2f899 sage/server/notebook/interact.py
    a b  
    1313
    1414AUTHORS:
    1515    -- William Stein (2008-03-02): version 1.0 at Sage/Enthought Days 8 in Texas
    16     -- Jason Grout (2008-03): discussion, and first few prototypes
     16    -- Jason Grout (2008-03): discussion and first few prototypes
     17    -- Jason Grout (2008-05): input_grid control
    1718"""
    1819
    1920"""
     
    144145# Sage libraries
    145146from sage.misc.all import srange, sage_eval
    146147from sage.plot.misc import Color
     148from sage.structure.element import is_Matrix
    147149
    148150# SAGE_CELL_ID is a module scope variable that is always set equal to
    149151# the current cell id (of the executing cell).  Code that sets this is
     
    568570                     change=self.interact(0), input_change=self.interact(1),
    569571                     default=self.default_value().html_color())
    570572
     573
     574
     575class InputGrid(InteractControl):
     576    def __init__(self, var, rows, columns, default_value=None, label=None, to_value=lambda x: x, width=4):
     577        """
     578        A grid interact control.
     579
     580        INPUT
     581            var -- the variable
     582            rows -- the number of rows
     583            columns -- the number of columns
     584            default_value -- if this is a scalar, it is put in every
     585                cell; if it is a list, it is filled into the cells row by
     586                row; if it is a nested list, then it is filled into the
     587                cells according to the nesting structure.
     588            label -- the label for the control
     589            to_value -- a function which is applied to the nested list
     590                from user input when assigning the variable
     591            width -- the width of the input boxes
     592
     593        EXAMPLES:
     594            sage: sage.server.notebook.interact.InputGrid('M', 2,2, default_value = 0, label='M')
     595            A 2 x 2 InputGrid interactive control with M=[[0, 0], [0, 0]] and label 'M'
     596            sage: sage.server.notebook.interact.InputGrid('M', 2,2, default_value = [[1,2],[3,4]], label='M')
     597            A 2 x 2 InputGrid interactive control with M=[[1, 2], [3, 4]] and label 'M'
     598            sage: sage.server.notebook.interact.InputGrid('M', 2,2, default_value = [[1,2],[3,4]], label='M', to_value=MatrixSpace(ZZ,2,2))
     599            A 2 x 2 InputGrid interactive control with M=[1 2]
     600            [3 4] and label 'M'
     601            sage: sage.server.notebook.interact.InputGrid('M', 1, 3, default_value=[1,2,3], to_value=lambda x: vector(flatten(x)))
     602            A 1 x 3 InputGrid interactive control with M=(1, 2, 3) and label 'M'
     603        """
     604
     605        self.__rows = rows
     606        self.__columns = columns
     607        self.__to_value = to_value
     608        self.__width = width
     609
     610        if type(default_value) != list:
     611            default_value = [[default_value for _ in range(columns)] for _ in range(rows)]
     612        elif not all(type(elt)==list for elt in default_value):
     613            default_value = [[default_value[i*columns+j] for j in xrange(columns)] for i in xrange(rows)]
     614
     615        self.__default_value_grid = default_value
     616
     617        InteractControl.__init__(self, var, self.__to_value(default_value), label)
     618
     619    def __repr__(self):
     620        """
     621        String representation of an InputGrid interactive control.
     622
     623        EXAMPLES:
     624            sage: sage.server.notebook.interact.InputGrid('M', 2,2).__repr__()
     625            "A 2 x 2 InputGrid interactive control with M=[[None, None], [None, None]] and label 'M'"
     626        """
     627       
     628        return 'A %r x %r InputGrid interactive control with %s=%r and label %r'%( self.__rows,
     629                                self.__columns, self.var(),  self.default_value(), self.label())
     630
    571631   
     632    def _adaptor(self, value, globs):
     633        """
     634        Adapt a user input, which is the text they enter, to be an
     635        element selected by this control.
     636
     637        INPUT:
     638            value -- text entered by user
     639            globs -- the globals interpreter variables (not used here).
     640
     641        OUTPUT:
     642            object
     643
     644        EXAMPLES:
     645            sage: sage.server.notebook.interact.InputGrid('M', 1,3, default_value=[[1,2,3]], to_value=lambda x: vector(flatten(x)))._adaptor("[[4,5,6]]", globals())
     646            (4, 5, 6)
     647        """
     648       
     649        return self.__to_value(sage_eval(value, globs))
     650
     651    def value_js(self):
     652        """
     653        Return javascript string that will give the value of this
     654        control element.
     655
     656        OUTPUT:
     657             string -- javascript
     658
     659        EXAMPLES:
     660            sage: sage.server.notebook.interact.InputGrid('M', 2,2).value_js()
     661            ' "[["+jQuery(this).parents("table").eq(0).find("tr").map(function(){return jQuery(this).find("input").map(function() {return jQuery(this).val();}).get().join(",");}).get().join("],[")+"]]" '
     662        """
     663        # Basically, given an input element in a table, it constructs
     664        # a python string representation of a list of lists from the
     665        # rows in the table.
     666       
     667        return """ "[["+jQuery(this).parents("table").eq(0).find("tr").map(function(){return jQuery(this).find("input").map(function() {return jQuery(this).val();}).get().join(",");}).get().join("],[")+"]]" """
     668
     669    def render(self):
     670        """
     671        Render this control as a string.
     672
     673        OUTPUT:
     674             string -- html format
     675
     676        EXAMPLES:
     677            sage: sage.server.notebook.interact.InputGrid('M', 1,2).render()
     678            '<table><tr><td><input type=\'text\' value=\'None\' ...
     679
     680        """
     681        table = "<table>"
     682        for i in range(self.__rows):
     683            table += "<tr>"
     684            for j in range(self.__columns):
     685                table += "<td><input type='text' value='%s' size='%s' onchange='%s'></input></td>"%(self.__default_value_grid[i][j], self.__width, self.interact())
     686            table += "</tr>"
     687        table += "</table>"
     688
     689        return table
     690
    572691       
    573692
    574693class Selector(InteractControl):
     
    10931212        \item u = Color('blue') -- a 2d RGB color selector; returns Color object
    10941213        \item u = (default, v)  -- v as above, with given default value
    10951214        \item u = (label, v)    -- v as above, with given label (a string)
     1215        \item u = matrix        -- an input_grid with to_value set to matrix.parent() and the default values given by the matrix
    10961216    \end{itemize}
    10971217
    10981218    WARNING: Suppose you would like to make a interactive with a
     
    12391359        ...     f = (k^u*(1+cos(v))*cos(u), k^u*(1+cos(v))*sin(u), k^u*sin(v)-a*k_2^u)
    12401360        ...     show(parametric_plot3d(f, (u,0,6*pi), (v,0,2*pi), plot_points=[40,40], texture=(0,0.5,0)))
    12411361        <html>...
     1362
     1363    An input grid:
     1364        sage: @interact
     1365        ... def _(A=matrix(QQ,3,3,range(9)), v=matrix(QQ,3,1,range(3))):
     1366        ...     try:
     1367        ...         x = A\v
     1368        ...         html('$$%s %s = %s$$'%(latex(A), latex(x), latex(v)))
     1369        ...     except:
     1370        ...         html('There is no solution to $$%s x=%s$$'%(latex(A), latex(v)))
     1371        <html>...
     1372
    12421373    """
    12431374   
    12441375    (args, varargs, varkw, defaults) = inspect.getargspec(f)
     
    14131544            return ColorInput(var, default_value=self.__default, label=self.label(), type=self.__type)
    14141545        else:
    14151546            return InputBox(var, default_value=self.__default, label=self.label(), type=self.__type)
     1547
     1548
     1549class input_grid(control):
     1550    def __init__(self, rows, columns, default=None, label=None, to_value=lambda x: x, width=4):
     1551        r"""
     1552        An input grid interactive control.  Use this in conjunction
     1553        with the interact command.
     1554
     1555        INPUT:
     1556            default -- object; the default put in this input box
     1557            label -- the label rendered to the left of the box.
     1558            to_value -- the grid output (list of rows) is sent through
     1559            this function.  This may reformat the data or coerce the
     1560            type.
     1561            width -- size of each input box in characters
     1562           
     1563        NOTEBOOK EXAMPLE:
     1564            @interact
     1565            def _(m = input_grid(2,2, default = [[1,7],[3,4]],
     1566                                 label='M=', to_value=matrix),
     1567                  v = input_grid(2,1, default=[1,2],
     1568                                 label='v=', to_value=matrix)):
     1569                try:
     1570                    x = m\v
     1571                    html('$$%s %s = %s$$'%(latex(m), latex(x), latex(v)))
     1572                except:
     1573                    html('There is no solution to $$%s x=%s$$'%(latex(m), latex(v)))
     1574
     1575
     1576        EXAMPLES:
     1577            sage: input_grid(2,2, default = 0, label='M')
     1578            Interact 2 x 2 input grid control labeled M with default value 0
     1579            sage: input_grid(2,2, default = [[1,2],[3,4]], label='M')
     1580            Interact 2 x 2 input grid control labeled M with default value [[1, 2], [3, 4]]
     1581            sage: input_grid(2,2, default = [[1,2],[3,4]], label='M', to_value=MatrixSpace(ZZ,2,2))
     1582            Interact 2 x 2 input grid control labeled M with default value [[1, 2], [3, 4]]
     1583            sage: input_grid(1, 3, default=[[1,2,3]], to_value=lambda x: vector(flatten(x)))
     1584            Interact 1 x 3 input grid control labeled None with default value [[1, 2, 3]]
     1585
     1586        """
     1587        self.__default = default
     1588        self.__rows = rows
     1589        self.__columns = columns
     1590        self.__to_value = to_value
     1591        self.__width = width
     1592        control.__init__(self, label)
     1593
     1594    def __repr__(self):
     1595        """
     1596        Return print representation of this input box.
     1597
     1598        EXAMPLES:
     1599            sage: input_grid(2,2, label='M').__repr__()
     1600            'Interact 2 x 2 input grid control labeled M with default value None'
     1601
     1602        """
     1603       
     1604        return 'Interact %r x %r input grid control labeled %s with default value %s'%( self.__rows,
     1605                                self.__columns, self.label(),  self.default())
     1606           
     1607
     1608    def default(self):
     1609        """
     1610        Return the default value of this input grid.
     1611
     1612        EXAMPLES:
     1613            sage: input_grid(2,2, default=1).default()
     1614            1
     1615        """
     1616        return self.__default
     1617
     1618
     1619    def render(self, var):
     1620        r"""
     1621        Return rendering of this input grid as an InputGrid to be used
     1622        for an interact canvas.  Basically this specializes this
     1623        input to be used for a specific function and variable.
     1624       
     1625        INPUT:
     1626            var -- a string (variable; one of the variable names input to f)
     1627
     1628        OUTPUT:
     1629            InputGrid -- an InputGrid object.
     1630
     1631        EXAMPLES:
     1632            sage: input_grid(2,2).render('x')
     1633            A 2 x 2 InputGrid interactive control with x=[[None, None], [None, None]] and label 'x'
     1634           
     1635        """
     1636        return InputGrid(var, rows=self.__rows, columns=self.__columns, default_value=self.__default, label=self.label(), to_value=self.__to_value, width=self.__width)
     1637
     1638
    14161639
    14171640class checkbox(input_box):
    14181641    def __init__(self, default=True, label=None):
     
    17661989        Slider: None [1--|1|---100]
    17671990        sage: sage.server.notebook.interact.automatic_control((5, (1..100)))
    17681991        Slider: None [1--|5|---100]
     1992        sage: sage.server.notebook.interact.automatic_control(matrix(2,2))
     1993        Interact 2 x 2 input grid control labeled None with default value [0, 0, 0, 0]
    17691994    """
    17701995    label = None
    17711996    default_value = None
     
    17992024            C = slider(default[0], default[1], default[2], default=default_value, label=label)
    18002025        else:
    18012026            C = slider(list(default), default=default_value, label=label)
     2027    elif is_Matrix(default):
     2028        C = input_grid(default.nrows(), default.ncols(), default=default.list(), to_value=default.parent())
    18022029    else:
    18032030        C = input_box(default, label=label)
    18042031