Ticket #14175: trac_14175_plot_options.patch

File trac_14175_plot_options.patch, 11.7 KB (added by nthiery, 9 years ago)
  • sage/geometry/polyhedron/base.py

    # HG changeset patch
    # User Volker Braun <vbraun@stp.dias.ie>
    # Date 1362210542 36000
    # Node ID cc1407623ad3fd8765aaa666f84d0d3129ad99b9
    # Parent  d636994612526f2134cd5e4617439b41aa656e3e
    #14175: More plot options for polytopes
    
    diff --git a/sage/geometry/polyhedron/base.py b/sage/geometry/polyhedron/base.py
    a b class Polyhedron_base(Element): 
    420420                    for other_H, self_V in
    421421                    CartesianProduct(other.Hrepresentation(), self.Vrepresentation()) )
    422422
    423     def plot(self, **kwds):
     423    def plot(self,
     424             point=None, line=None, polygon=None, # None means unspecified by the user
     425             wireframe='blue', fill='green',
     426             **kwds):
    424427        """
    425428        Return a graphical representation.
    426429
    427430        INPUT:
    428431
    429         - ``**kwds`` -- optional keyword parameters.
    430 
    431         See :func:`render_2d`, :func:`render_3d`, :func:`render_4d`
    432         for a description of available options for different ambient
    433         space dimensions.
     432        - ``point``, ``line``, ``polygon`` -- Parameters to pass to
     433          point (0d), line (1d), and polygon (2d) plot commands.
     434          Allowed values are:
     435
     436          * A Python dictionary to be passed as keywords to the plot
     437            commands.
     438
     439          * A string or triple of numbers: The color. This is
     440            equivalent to passing the dictionary ``{'color':...}``.
     441
     442          * ``False``: Switches off the drawing of the corresponding
     443            graphics object
     444
     445        - ``wireframe``, ``fill`` -- Similar to ``point``, ``line``,
     446          and ``polygon``, but ``fill`` is used for the graphics
     447          objects in the dimension of the polytope (or of dimension 2
     448          for higher dimensional polytopes) and ``wireframe`` is used
     449          for all lower-dimensional graphics objects
     450          (default: 'green' for fill and 'blue' for wireframe)
     451
     452        - ``**kwds`` -- optional keyword parameters that are passed to
     453          all graphics objects.
    434454
    435455        OUTPUT:
    436456
    437         A graphics object.
     457        A (multipart) graphics object.
     458
     459        EXAMPLES::
     460
     461            sage: square = polytopes.n_cube(2)
     462            sage: point = Polyhedron([[1,1]])
     463            sage: line = Polyhedron([[1,1],[2,1]])
     464            sage: cube = polytopes.n_cube(3)
     465            sage: hypercube = polytopes.n_cube(4)
     466
     467        By default, the wireframe is rendered in blue and the fill in green::
     468
     469            sage: square.plot()
     470            sage: point.plot()
     471            sage: line.plot()
     472            sage: cube.plot()
     473            sage: hypercube.plot()
     474
     475        Draw the lines in red and nothing else::
     476
     477            sage: square.plot(point=False, line='red', polygon=False)
     478            sage: point.plot(point=False, line='red', polygon=False)
     479            sage: line.plot(point=False, line='red', polygon=False)
     480            sage: cube.plot(point=False, line='red', polygon=False)
     481            sage: hypercube.plot(point=False, line='red', polygon=False)
     482
     483        Draw points in red, no lines, and a blue polygon::
     484
     485            sage: square.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
     486            sage: point.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
     487            sage: line.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
     488            sage: cube.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
     489            sage: hypercube.plot(point={'color':'red'}, line=False, polygon=(0,0,1))
     490
     491        If we instead use the ``fill`` and ``wireframe`` options, the
     492        coloring depends on the dimension of the object::
     493
     494            sage: square.plot(fill='green', wireframe='red')
     495            sage: point.plot(fill='green', wireframe='red')
     496            sage: line.plot(fill='green', wireframe='red')
     497            sage: cube.plot(fill='green', wireframe='red')
     498            sage: hypercube.plot(fill='green', wireframe='red')
    438499
    439500        TESTS::
    440501
    441             sage: polytopes.n_cube(2).plot()
     502            sage: for p in square.plot():
     503            ...       print p.options()['rgbcolor'], p
     504            blue Point set defined by 4 point(s)
     505            blue Line defined by 2 points
     506            blue Line defined by 2 points
     507            blue Line defined by 2 points
     508            blue Line defined by 2 points
     509            green Polygon defined by 4 points
     510
     511            sage: for p in line.plot():
     512            ...       print p.options()['rgbcolor'], p
     513            blue Point set defined by 2 point(s)
     514            green Line defined by 2 points
     515
     516            sage: for p in point.plot():
     517            ...       print p.options()['rgbcolor'], p
     518            green Point set defined by 1 point(s)
     519
     520        Draw the lines in red and nothing else::
     521
     522            sage: for p in square.plot(point=False, line='red', polygon=False):
     523            ...       print p.options()['rgbcolor'], p
     524            red Line defined by 2 points
     525            red Line defined by 2 points
     526            red Line defined by 2 points
     527            red Line defined by 2 points
     528
     529        Draw vertices in red, no lines, and a blue polygon::
     530
     531            sage: for p in square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)):
     532            ...       print p.options()['rgbcolor'], p
     533            red Point set defined by 4 point(s)
     534            (0, 0, 1) Polygon defined by 4 points
     535
     536            sage: for p in line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)):
     537            ...       print p.options()['rgbcolor'], p
     538            red Point set defined by 2 point(s)
     539
     540            sage: for p in point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)):
     541            ...       print p.options()['rgbcolor'], p
     542            red Point set defined by 1 point(s)
     543
     544        Draw in red without wireframe::
     545
     546            sage: for p in square.plot(wireframe=False, fill="red"):
     547            ...       print p.options()['rgbcolor'], p
     548            red Polygon defined by 4 points
     549
     550            sage: for p in line.plot(wireframe=False, fill="red"):
     551            ...       print p.options()['rgbcolor'], p
     552            red Line defined by 2 points
     553
     554            sage: for p in point.plot(wireframe=False, fill="red"):
     555            ...       print p.options()['rgbcolor'], p
     556            red Point set defined by 1 point(s)
    442557        """
     558        def merge_options(*opts):
     559            merged = dict()
     560            for i in range(len(opts)):
     561                opt = opts[i]
     562                if opt is None:
     563                    continue
     564                elif opt is False:
     565                    return False
     566                elif isinstance(opt, (basestring, list, tuple)):
     567                    merged['color'] = opt
     568                else:
     569                    merged.update(opt)
     570            return merged
     571
     572        d = min(self.dim(), 2)
     573        opts = [wireframe] * d + [fill] + [False] * (2-d)
     574        # The point/line/polygon options take precedence over wireframe/fill
     575        opts = [merge_options(opt1, opt2, kwds)
     576                for opt1, opt2 in zip(opts, [point, line, polygon])]
     577
    443578        from plot import render_2d, render_3d, render_4d
    444579        render_method = [ None, None, render_2d, render_3d, render_4d ]
    445580        if self.ambient_dim() < len(render_method):
    446581            render = render_method[self.ambient_dim()]
    447582            if render != None:
    448                 return render(self,**kwds)
     583                return render(self, *opts)
    449584        raise NotImplementedError('Plotting of '+str(self.ambient_dim())+
    450585                                  '-dimensional polyhedra not implemented')
    451586
  • sage/geometry/polyhedron/plot.py

    diff --git a/sage/geometry/polyhedron/plot.py b/sage/geometry/polyhedron/plot.py
    a b from constructor import Polyhedron 
    2929
    3030
    3131#############################################################
    32 def render_2d(projection, **kwds):
     32def render_2d(projection, point_opts={}, line_opts={}, polygon_opts={}):
    3333    """
    3434    Return 2d rendering of the projection of a polyhedron into
    3535    2-dimensional ambient space.
    def render_2d(projection, **kwds): 
    5454    """
    5555    if is_Polyhedron(projection):
    5656        projection = Projection(projection)
    57     return \
    58         projection.render_points_2d(zorder=2, pointsize=10, **kwds) + \
    59         projection.render_outline_2d(zorder=1, **kwds) + \
    60         projection.render_fill_2d(zorder=0, rgbcolor=(0,1,0), **kwds)
     57    from sage.plot.graphics import Graphics
     58    plt = Graphics()
     59    if isinstance(point_opts, dict):
     60        point_opts.setdefault('zorder', 2)
     61        point_opts.setdefault('pointsize', 10)
     62        plt += projection.render_points_2d(**point_opts)
     63    if isinstance(line_opts, dict):
     64        line_opts.setdefault('zorder', 1)
     65        plt += projection.render_outline_2d(**line_opts)
     66    if isinstance(polygon_opts, dict):
     67        polygon_opts.setdefault('zorder', 0)
     68        plt += projection.render_fill_2d(**polygon_opts)
     69    return plt
    6170
    6271
    63 def render_3d(projection, **kwds):
     72def render_3d(projection, point_opts={}, line_opts={}, polygon_opts={}):
    6473    """
    6574    Return 3d rendering of a polyhedron projected into
    6675    3-dimensional ambient space.
    def render_3d(projection, **kwds): 
    9099    """
    91100    if is_Polyhedron(projection):
    92101        projection = Projection(projection)
    93     return \
    94         projection.render_vertices_3d(width=3, color='green', **kwds) +\
    95         projection.render_wireframe_3d(width=3, color='green', **kwds) + \
    96         projection.render_solid_3d(**kwds)
     102    from sage.plot.plot3d.base import Graphics3d
     103    plt = Graphics3d()
     104    if isinstance(point_opts, dict):
     105        point_opts.setdefault('width', 3)
     106        plt += projection.render_vertices_3d(**point_opts)
     107    if isinstance(line_opts, dict):
     108        line_opts.setdefault('width', 3)
     109        plt += projection.render_wireframe_3d(**line_opts)
     110    if isinstance(polygon_opts, dict):
     111        plt += projection.render_solid_3d(**polygon_opts)
     112    return plt
    97113
    98 
    99 def render_4d(polyhedron, **kwds):
     114def render_4d(polyhedron, point_opts={}, line_opts={}, polygon_opts={}, projection_direction=None):
    100115    """
    101116    Return a 3d rendering of the Schlegel projection of a 4d
    102117    polyhedron projected into 3-dimensional space.
    def render_4d(polyhedron, **kwds): 
    111126    - ``polyhedron`` -- A
    112127      :mod:`~sage.geometry.polyhedron.constructor.Polyhedron` object.
    113128
    114     - ``kwds`` -- plot keywords. Passing
    115       ``projection_direction=<list>`` sets the projetion direction of
    116       the Schlegel projection. If it is not given, the center of a
    117       facet is used.
     129    - ``point_opts``, ``line_opts``, ``polygon_opts`` -- dictionaries
     130      of plot keywords or ``False`` to disable.
     131
     132    - ``projection_direction`` -- list/tuple/iterable of coordinates
     133      or ``None`` (default). Sets the projetion direction of the
     134      Schlegel projection. If it is not given, the center of a facet
     135      is used.
    118136
    119137    EXAMPLES::
    120138
    def render_4d(polyhedron, **kwds): 
    135153        sage: tach_str.count('FCylinder')
    136154        32
    137155    """
    138     projection_direction = None
    139     try:
    140         projection_direction = kwds.pop('projection_direction')
    141     except KeyError:
     156    if projection_direction is None:
    142157        for ineq in polyhedron.inequality_generator():
    143158            center = [v() for v in ineq.incident() if v.is_vertex()]
    144159            center = sum(center) / len(center)
    def render_4d(polyhedron, **kwds): 
    146161                projection_direction = center
    147162                break
    148163    projection_3d = Projection(polyhedron).schlegel(projection_direction)
    149     return render_3d(projection_3d, **kwds)
     164    return render_3d(projection_3d, point_opts, line_opts, polygon_opts)
    150165
    151166
    152167