Ticket #4529: trac_4529-add_logscale_to_Graphics.patch

File trac_4529-add_logscale_to_Graphics.patch, 29.3 KB (added by ppurka, 9 years ago)

Apply to devel/sage

  • sage/plot/graphics.py

    # HG changeset patch
    # User Punarbasu Purkayastha <ppurka@gmail.com>
    # Date 1337533475 -28800
    # Node ID fa6385e572d44e1ba135efd4920ffff8afe33e4e
    # Parent  d980750cc2b4ed5f3605383ffc8b7effd7d4d70f
    add log scale to Graphics class
    
    diff --git a/sage/plot/graphics.py b/sage/plot/graphics.py
    a b  
    99AUTHORS:
    1010
    1111- Jeroen Demeyer (2012-04-19): split off this file from plot.py (:trac:`12857`)
     12- Punarbasu Purkayastha (2012-05-20): Add logarithmic scale (:trac:`4529`)
    1213
    1314"""
    1415
     
    117118        ...        G+=line(l,color=hue(c + p*(x/h)))
    118119        sage: G.show(figsize=[5,5])
    119120
     121    We can change the scale of the axes in the graphics before displaying::
     122
     123        sage: G = plot(exp, 1, 10)
     124        sage: G.set_scale('semilogy')
     125        sage: G.show()
     126
    120127    TESTS:
    121128
    122129    From :trac:`4604`, ensure Graphics can handle 3d objects::
     
    150157        self._axes_color = (0, 0, 0)
    151158        self._axes_label_color = (0, 0, 0)
    152159        self._axes_width = 0.8
     160        self._basex = 10
     161        self._basey = 10
    153162        self._bbox_extra_artists = []
    154163        self._extra_kwds = {}
    155164        self._fontsize = 10
     
    158167        self._show_axes = True
    159168        self._show_legend = False
    160169        self._tick_label_color = (0, 0, 0)
     170        self._xscale = 'linear'
     171        self._yscale = 'linear'
    161172
    162173    def set_aspect_ratio(self, ratio):
    163174        """
     
    389400        else:
    390401            self._legend_opts.update(kwds)
    391402
     403    def get_scale(self):
     404        """
     405        Get the current axes scale.
     406
     407        OUTPUT:
     408        The output is a tuple ``(scale, basex, basey)``. ``scale`` takes
     409        values
     410        - ``linear`` -- both the axes are linear.
     411        - ``loglog`` -- both the axes are logarithmic.
     412        - ``semilogx`` -- the horizontal axis is logarithmic and the
     413          vertical axis is linear.
     414        - ``semilogy`` -- the horizontal axis is linear and the vertical
     415          axis is logarithmic.
     416
     417        ``basex``, ``basey`` are scalars greater than 1. When the
     418        horizontal or vertical axis has linear scale, then the
     419        corresponding base has no significance and defaults to 10.
     420
     421        EXAMPLES::
     422
     423            sage: p = Graphics(); p.get_scale()
     424            ('linear', 10, 10)
     425            sage: p.set_scale('loglog'); p.get_scale()
     426            ('loglog', 10, 10)
     427            sage: p.set_scale(('semilogx', 2)); p.get_scale()
     428            ('semilogx', 2, 10)
     429        """
     430        if self._xscale == 'linear' and self._yscale == 'linear':
     431            return ('linear', self._basex, self._basey)
     432        if self._xscale == 'log' and self._yscale == 'log':
     433            return ('loglog', self._basex, self._basey)
     434        if self._xscale == 'log' and self._yscale == 'linear':
     435            return ('semilogx', self._basex, self._basey)
     436        if self._xscale == 'linear' and self._yscale == 'log':
     437            return ('semilogy', self._basex, self._basey)
     438
     439    def get_xscale(self):
     440        """
     441        Get the current horizontal axis scale.
     442
     443        OUTPUT:
     444        The output is a tuple ``(scale, base)``. ``scale`` takes
     445        values
     446        - ``linear`` -- the axis is linear.
     447        - ``log`` -- the axis is logarithmic.
     448
     449        ``base`` is a scalar greater than 1. When the horizontal axis has
     450        linear scale, then the corresponding base has no significance and
     451        defaults to 10.
     452
     453        EXAMPLES::
     454
     455            sage: p = Graphics(); p.get_xscale()
     456            ('linear', 10)
     457            sage: p.set_scale('loglog'); p.get_xscale()
     458            ('log', 10)
     459            sage: p.set_scale(('semilogx', 2)); p.get_xscale()
     460            ('log', 2)
     461        """
     462        return (self._xscale, self._basex)
     463
     464    def get_yscale(self):
     465        """
     466        Get the current vertical axis scale.
     467
     468        OUTPUT:
     469        The output is a tuple ``(scale, base)``. ``scale`` takes
     470        values
     471        - ``linear`` -- the axis is linear.
     472        - ``log`` -- the axis is logarithmic.
     473
     474        ``base`` is a scalar greater than 1. When the vertical axis has
     475        linear scale, then the corresponding base has no significance and
     476        defaults to 10.
     477
     478        EXAMPLES::
     479
     480            sage: p = Graphics(); p.get_yscale()
     481            ('linear', 10)
     482            sage: p.set_scale('loglog'); p.get_yscale()
     483            ('log', 10)
     484            sage: p.set_scale(('semilogy', 2)); p.get_yscale()
     485            ('log', 2)
     486        """
     487        return (self._yscale, self._basey)
     488
     489    def set_scale(self, scale, base=10):
     490        """
     491        Set the scale of both the axes of this graphics object.
     492
     493        INPUT:
     494
     495        - ``scale`` -- string. The scale of the axes. Possible values are
     496          `linear`, `loglog`, `semilogx`, `semilogy`.
     497
     498        - ``base`` -- (Default: 10) the base of the logarithm if
     499          a logarithmic scale is set. This must be greater than 1. The base
     500          can be also given as a list or tuple ``(basex, basey)``.
     501          ``basex`` sets the base of the logarithm along the horizontal
     502          axis and ``basey`` sets the base along the vertical axis.
     503
     504        The INPUT can be also be given as single argument that is a list or
     505        tuple ``(scale, base)`` or ``(scale, basex, basey)``.
     506
     507        The `loglog` scale sets both the horizontal and vertical axes to
     508        logarithmic scale. The `semilogx` scale sets the horizontal axis to
     509        logarithmic scale. The `semilogy` scale sets the vertical axis to
     510        logarithmic scale. The `linear` scale is the default value when
     511        :class:`Graphics` is initialized.
     512
     513        IMPORTANT: This parameter sets the scale of all the graphics
     514        primitives in this graphics object. If you try to add two graphics
     515        objects with different scales, you will get an error.
     516
     517        EXAMPLES::
     518
     519            sage: p = Graphics()
     520            sage: p.set_scale('loglog'); p.get_scale()
     521            ('loglog', 10, 10)
     522            sage: p.set_scale(('semilogx', 2)); p.get_scale()
     523            ('semilogx', 2, 10)
     524            sage: p.set_scale(('semilogy', 2, 3)); p.get_scale()
     525            ('semilogy', 10, 3)
     526
     527        TESTS::
     528
     529            sage: p = Graphics()
     530            sage: p.set_scale('log')
     531            Traceback (most recent call last):
     532            ...
     533            ValueError: The scale must be one of 'linear', 'loglog', 'semilogx' or 'semilogy' -- got log
     534            sage: p.set_scale(('loglog', 1))
     535            Traceback (most recent call last):
     536            ...
     537            ValueError: The base of the logarithm must be greater than 1
     538        """
     539        if isinstance(scale, (list, tuple)):
     540            if len(scale) != 2 and len(scale) != 3:
     541                raise ValueError("If the input is a tuple, it must be of "
     542                    "the form (scale, base) or (scale, basex, basey)")
     543            if len(scale) == 2:
     544                base = scale[1]
     545            else:
     546                base = scale[1:]
     547            scale = scale[0]
     548
     549        if scale not in ('linear', 'loglog', 'semilogx', 'semilogy'):
     550            raise ValueError("The scale must be one of 'linear', 'loglog',"
     551                    " 'semilogx' or 'semilogy' -- got {0}".format(scale))
     552        if isinstance(base, (list, tuple)):
     553            basex, basey = base
     554        else:
     555            basex = basey = base
     556
     557        if basex <= 1 or basey <= 1:
     558            raise ValueError("The base of the logarithm must be greater "
     559                             "than 1")
     560
     561        if scale == 'linear':
     562            self.set_xscale('linear')
     563            self.set_yscale('linear')
     564        elif scale == 'loglog':
     565            self.set_xscale('log', base=basex)
     566            self.set_yscale('log', base=basey)
     567        elif scale == 'semilogx':
     568            self.set_xscale('log', base=basex)
     569            self.set_yscale('linear')
     570        elif scale == 'semilogy':
     571            self.set_xscale('linear')
     572            self.set_yscale('log', base=basey)
     573
     574    def set_xscale(self, scale, base=10):
     575        """
     576        Set the scale along the horizontal axis.
     577
     578        INPUT:
     579
     580        - ``scale`` -- string. The scale of the horizontal axes. Possible
     581          values are `linear`, `log`.
     582
     583        - ``base`` -- (Default: 10) the base of the logarithm if
     584          a logarithmic scale is set. This must be greater than 1.
     585
     586        The INPUT can be also be given as single argument that is a list or
     587        tuple ``(scale, base)``. If the scale is given as `linear`, then
     588        the ``base`` is set to `10` irrespective of the input given.
     589
     590        IMPORTANT: This parameter sets the scale of all the graphics
     591        primitives in this graphics object. If you try to add two graphics
     592        objects with different scales, you will get an error.
     593
     594        EXAMPLES::
     595
     596            sage: p = Graphics()
     597            sage: p.set_xscale('log'); p.get_xscale()
     598            ('log', 10)
     599            sage: p.set_xscale(('log', 2)); p.get_xscale()
     600            ('log', 2)
     601            sage: p.set_xscale(['linear', 1]); p.get_xscale()
     602            ('linear', 10)
     603
     604        TESTS::
     605
     606            sage: p = Graphics()
     607            sage: p.set_xscale('loglog')
     608            Traceback (most recent call last):
     609            ...
     610            ValueError: The scale must be one of 'linear', 'log'
     611            sage: p.set_xscale(('log', 2, 3))
     612            Traceback (most recent call last):
     613            ...
     614            ValueError: If the input is a tuple, it must be of the form (scale, base)
     615        """
     616        if isinstance(scale, (list, tuple)):
     617            if len(scale) != 2:
     618                raise ValueError("If the input is a tuple, it must be of "
     619                                 "the form (scale, base)")
     620            base  = scale[1]
     621            scale = scale[0]
     622
     623        if scale not in ('linear', 'log'):
     624            raise ValueError("The scale must be one of 'linear', 'log'")
     625        if scale == 'log':
     626            if base <= 1:
     627                raise ValueError("The base of the logarithm must be greater "
     628                                 "than 1")
     629            self._basex = base
     630        else:
     631            self._basex = 10
     632        self._xscale = scale
     633
     634    def set_yscale(self, scale, base=10):
     635        """
     636        Set the scale along the vertical axis.
     637
     638        INPUT:
     639
     640        - ``scale`` -- string. The scale of the vertical axes. Possible
     641          values are `linear`, `log`.
     642
     643        - ``base`` -- (Default: 10) the base of the logarithm if
     644          a logarithmic scale is set. This must be greater than 1.
     645
     646        The INPUT can be also be given as single argument that is a list or
     647        tuple ``(scale, base)``. If the scale is given as `linear`, then
     648        the ``base`` is set to `10` irrespective of the input given.
     649
     650        IMPORTANT: This parameter sets the scale of all the graphics
     651        primitives in this graphics object. If you try to add two graphics
     652        objects with different scales, you will get an error.
     653
     654        EXAMPLES::
     655
     656            sage: p = Graphics()
     657            sage: p.set_yscale('log'); p.get_yscale()
     658            ('log', 10)
     659            sage: p.set_yscale(['log', 2]); p.get_yscale()
     660            ('log', 2)
     661            sage: p.set_yscale('linear', 1); p.get_yscale()
     662            ('linear', 10)
     663
     664        TESTS::
     665
     666            sage: p = Graphics()
     667            sage: p.set_yscale('loglog')
     668            Traceback (most recent call last):
     669            ...
     670            ValueError: The scale must be one of 'linear', 'log'
     671            sage: p.set_yscale(('log', 2, 3))
     672            Traceback (most recent call last):
     673            ...
     674            ValueError: If the input is a tuple, it must be of the form (scale, base)
     675        """
     676        if isinstance(scale, (list, tuple)):
     677            if len(scale) != 2:
     678                raise ValueError("If the input is a tuple, it must be of "
     679                                 "the form (scale, base)")
     680            base  = scale[1]
     681            scale = scale[0]
     682
     683        if scale not in ('linear', 'log'):
     684            raise ValueError("The scale must be one of 'linear', 'log'")
     685        if scale == 'log':
     686            if base <= 1:
     687                raise ValueError("The base of the logarithm must be greater "
     688                                 "than 1")
     689            self._basey = base
     690        else:
     691            self._basey = 10
     692        self._yscale = scale
    392693
    393694    def get_axes_range(self):
    394695        """
     
    8391140            [Graphics object consisting of 1 graphics primitive,
    8401141             Graphics object consisting of 1 graphics primitive]
    8411142
     1143        If the graphics are in logarithmic scale, then the scale is also
     1144        mentioned::
     1145
     1146            sage: p = plot(x); p.set_xscale('log')
     1147            sage: q = plot(x**2); q.set_xscale('log')
     1148            sage: (p+q).__str__()
     1149            'Graphics object consisting of 2 graphics primitives in semilogx scale'
     1150
    8421151        ::
    8431152
    8441153            sage: show_default(True)
    8451154        """
    846         pr, i = '', 0
    847         for x in self:
    848             pr += '\n\t%s -- %s'%(i, x)
    849             i += 1
    8501155        s = "Graphics object consisting of %s graphics primitives"%(len(self))
    8511156        if len(self) == 1:
    8521157            s = s[:-1]
    853         return s
     1158        t = ""
     1159        if self._xscale == 'log' and self._yscale == 'log':
     1160            t = " in loglog scale"
     1161        elif self._xscale == 'log':
     1162            t = " in semilogx scale"
     1163        elif self._yscale == 'log':
     1164            t = " in semilogy scale"
     1165        return s+t
    8541166
    8551167    def __getitem__(self, i):
    8561168        """
     
    9831295            sage: g2.set_aspect_ratio(3)
    9841296            sage: (g1+g2).aspect_ratio()
    9851297            3.0
     1298
     1299        Graphics of different scales can not be added::
     1300
     1301            sage: p = plot(exp, 1, 10); p.set_scale('loglog')
     1302            sage: q = plot(x, 1, 10)
     1303            sage: p + q
     1304            Traceback (most recent call last):
     1305            ...
     1306            TypeError: Both the Graphics objects must have the same scale and the same base for the logarithms
    9861307        """
    9871308        if isinstance(other, int) and other == 0:
    9881309            return self
     1310
    9891311        if not isinstance(other, Graphics):
    9901312            from sage.plot.plot3d.base import Graphics3d
    9911313            if isinstance(other, Graphics3d):
    9921314                return self.plot3d() + other
    993             raise TypeError, "other (=%s) must be a Graphics objects"%other
     1315            raise TypeError("other (={0}) must be a Graphics object".format(other))
     1316       
     1317        # If we have come here, then other is a Graphics object, which
     1318        # means it has got the _[xy]scale and _base[xy] attributes.
     1319        if self._xscale != other._xscale or self._yscale != other._yscale \
     1320            or self._basex != other._basex or self._basey != other._basey:
     1321            raise TypeError("Both the Graphics objects must have the same "
     1322                            "scale and the same base for the logarithms")
    9941323        g = Graphics()
    9951324        g._objects = self._objects + other._objects
    9961325        g._show_legend = self._show_legend or other._show_legend
     
    10011330        elif other.aspect_ratio()=='automatic':
    10021331            g.set_aspect_ratio(self.aspect_ratio())
    10031332        else:
    1004             g.set_aspect_ratio( max(self.aspect_ratio(), other.aspect_ratio()))
     1333            g.set_aspect_ratio(max(self.aspect_ratio(), other.aspect_ratio()))
     1334        g.set_xscale(self.get_xscale())
     1335        g.set_yscale(self.get_yscale())
    10051336        return g
    10061337
    10071338    def add_primitive(self, primitive):
     
    11071438    # this dictionary to contain the default value for that parameter.
    11081439
    11091440    SHOW_OPTIONS = dict(aspect_ratio=None, axes=None, axes_labels=None,
    1110                         axes_pad=.02, dpi=DEFAULT_DPI,
     1441                        axes_pad=.02, base=None, dpi=DEFAULT_DPI,
    11111442                        fig_tight=True, figsize=None, filename=None,
    11121443                        fontsize=None, frame=False,
    11131444                        gridlines=None, gridlinesstyle=None,
    1114                         hgridlinesstyle=None, legend_options={},
     1445                        hgridlinesstyle=None, legend_options={}, scale=None,
    11151446                        show_legend=None, tick_formatter=None, ticks=None,
    11161447                        ticks_integer=False, transparent=False,
    11171448                        xmin=None, xmax=None, ymin=None, ymax=None,
     
    12691600
    12701601        - ``legend_*`` - all the options valid for :meth:`set_legend_options` prefixed with ``legend_``
    12711602
     1603        - ``base`` - (default: 10) the base of the logarithm if
     1604          a logarithmic scale is set. This must be greater than 1. The base
     1605          can be also given as a list or tuple ``(basex, basey)``.
     1606          ``basex`` sets the base of the logarithm along the horizontal
     1607          axis and ``basey`` sets the base along the vertical axis.
     1608
     1609        - ``scale`` -- (default: `linear`) string. The scale of the axes.
     1610          Possible values are `linear`, `loglog`, `semilogx`, `semilogy`.
     1611
     1612          The scale can be also be given as single argument that is a list
     1613          or tuple ``(scale, base)`` or ``(scale, basex, basey)``.
     1614
     1615          The `loglog` scale sets both the horizontal and vertical axes to
     1616          logarithmic scale. The `semilogx` scale sets the horizontal axis
     1617          to logarithmic scale. The `semilogy` scale sets the vertical axis
     1618          to logarithmic scale. The `linear` scale is the default value
     1619          when :class:`Graphics` is initialized.
     1620
    12721621        EXAMPLES::
    12731622
    12741623            sage: c = circle((1,1), 1, color='red')
     
    12951644
    12961645            sage: plot(sin(x), (x, -4, 4), transparent=True)
    12971646
     1647        We can change the scale of the axes in the graphics before
     1648        displaying::
     1649
     1650            sage: G = plot(exp, 1, 10)
     1651            sage: G.show(scale=('semilogy', 2))
     1652
    12981653        Add grid lines at the major ticks of the axes.
    12991654
    13001655        ::
     
    16061961        return {'xmin':xmin, 'xmax':xmax, 'ymin':ymin, 'ymax':ymax}
    16071962
    16081963    def _matplotlib_tick_formatter(self, subplot, locator_options={},
    1609             tick_formatter=None, ticks=None, xmax=None, xmin=None,
    1610             ymax=None, ymin=None):
     1964            tick_formatter=(None, None), ticks=(None, None),
     1965            xmax=None, xmin=None, ymax=None, ymin=None):
    16111966        r"""
    16121967        Take a matplotlib subplot instance representing the graphic and set
    16131968        the ticks formatting. This function is only for internal use.
    16141969
    16151970        INPUT:
    16161971        - ``subplot`` -- the subplot instance.
     1972
     1973        EXAMPLES::
     1974
     1975            sage: from matplotlib.figure import Figure
     1976            sage: p = plot(x); d = p.get_minmax_data()
     1977            sage: subplot = Figure().add_subplot(111)
     1978            sage: p._objects[0]._render_on_subplot(subplot)
     1979            sage: p._matplotlib_tick_formatter(subplot, **d)
     1980            (<matplotlib.axes.AxesSubplot object at ...>,
     1981            <matplotlib.ticker.MaxNLocator instance at ...>,
     1982            <matplotlib.ticker.MaxNLocator instance at ...>,
     1983            <matplotlib.ticker.OldScalarFormatter instance at ...>,
     1984            <matplotlib.ticker.OldScalarFormatter instance at ...>)
    16171985        """
    16181986        # This function is created to refactor some code that is repeated
    16191987        # in the matplotlib function
    1620         from matplotlib.ticker import FixedLocator, Locator, MaxNLocator, \
    1621                 MultipleLocator, NullLocator, OldScalarFormatter
     1988        from matplotlib.ticker import FixedLocator, Locator, LogFormatter, \
     1989            LogLocator, MaxNLocator, MultipleLocator, NullLocator, \
     1990            OldScalarFormatter
    16221991
    16231992        x_locator, y_locator = ticks
    16241993        #---------------------- Location of x-ticks ---------------------#
    16251994        if x_locator is None:
    1626             x_locator = MaxNLocator(**locator_options)
     1995            if self._xscale == 'log':
     1996                x_locator = LogLocator(base=self._basex)
     1997            else:
     1998                x_locator = MaxNLocator(**locator_options)
    16271999        elif isinstance(x_locator,Locator):
    16282000            pass
    16292001        elif x_locator == []:
     
    16412013
    16422014        #---------------------- Location of y-ticks ---------------------#
    16432015        if y_locator is None:
    1644             y_locator = MaxNLocator(**locator_options)
     2016            if self._yscale == 'log':
     2017                y_locator = LogLocator(base=self._basey)
     2018            else:
     2019                y_locator = MaxNLocator(**locator_options)
    16452020        elif isinstance(y_locator,Locator):
    16462021            pass
    16472022        elif y_locator == []:
     
    16632038        from sage.symbolic.ring import SR
    16642039        #---------------------- Formatting x-ticks ----------------------#
    16652040        if x_formatter is None:
    1666             x_formatter = OldScalarFormatter()
     2041            if self._xscale == 'log':
     2042                x_formatter = LogFormatter(base=self._basex)
     2043            else:
     2044                x_formatter = OldScalarFormatter()
    16672045        elif x_formatter in SR:
    16682046            from misc import _multiple_of_constant
    16692047            x_const = x_formatter
     
    16732051            x_formatter = FuncFormatter(lambda n,pos: '$%s$'%latex(n))
    16742052        #---------------------- Formatting y-ticks ----------------------#
    16752053        if y_formatter is None:
    1676             y_formatter = OldScalarFormatter()
     2054            if self._yscale == 'log':
     2055                y_formatter = LogFormatter(base=self._basey)
     2056            else:
     2057                y_formatter = OldScalarFormatter()
    16772058        elif y_formatter in SR:
    16782059            from misc import _multiple_of_constant
    16792060            y_const = y_formatter
     
    16892070
    16902071        return (subplot, x_locator, y_locator, x_formatter, y_formatter)
    16912072
    1692     def matplotlib(self, filename=None,
    1693                    aspect_ratio=None, axes=None, axes_labels=None, axes_pad=0.02,
     2073    def matplotlib(self, filename=None, aspect_ratio=None, axes=None,
     2074                   axes_labels=None, axes_pad=0.02, base=None,
    16942075                   figsize=None, figure=None, fontsize=None, frame=False,
    1695                    gridlines=None, gridlinesstyle=None, hgridlinesstyle=None,
    1696                    legend_options={}, show_legend=None, sub=None,
    1697                    tick_formatter=None, ticks=None, ticks_integer=None,
    1698                    xmin=None, xmax=None, ymin=None, ymax=None,
    1699                    vgridlinesstyle=None, verify=True):
     2076                   gridlines=None, gridlinesstyle=None,
     2077                   hgridlinesstyle=None, legend_options={}, scale=None,
     2078                   show_legend=None, sub=None, tick_formatter=None,
     2079                   ticks=None, ticks_integer=None, xmin=None, xmax=None,
     2080                   ymin=None, ymax=None, vgridlinesstyle=None, verify=True):
    17002081        r"""
    17012082        Return a matplotlib figure object representing the graphic
    17022083
     
    17902171            if hasattr(g, '_bbox_extra_artists'):
    17912172                self._bbox_extra_artists.extend(g._bbox_extra_artists)
    17922173
    1793         #add the legend if requested
     2174        #--------------------------- Set the scale -----------------------#
     2175        if scale is not None:
     2176            if base is not None:
     2177                self.set_scale(scale, base)
     2178            else:
     2179                self.set_scale(scale)
     2180        xscale = self._xscale
     2181        yscale = self._yscale
     2182        if xscale == 'log':
     2183            figure.get_axes()[0].set_xscale('log', basex=self._basex)
     2184        if yscale == 'log':
     2185            figure.get_axes()[0].set_yscale('log', basey=self._basey)
     2186
     2187        #-------------------------- Set the legend -----------------------#
    17942188        if show_legend is None:
    17952189            show_legend = self._show_legend
    17962190
     
    18122206
    18132207
    18142208        subplot.set_xlim([xmin, xmax])
    1815         subplot.set_ylim([ymin,ymax])
     2209        subplot.set_ylim([ymin, ymax])
    18162210
    18172211        locator_options=dict(nbins=9,steps=[1,2,5,10],integer=ticks_integer)
    18182212
     
    18372231                            xmax=xmax, xmin=xmin, ymax=ymax, ymin=ymin)
    18382232
    18392233            subplot.set_frame_on(True)
    1840             if axes:
     2234            if axes and xscale == 'linear' and yscale == 'linear':
    18412235                if ymin<=0 and ymax>=0:
    18422236                    subplot.axhline(color=self._axes_color,
    18432237                                    linewidth=self._axes_width)
     
    18502244            xmiddle=False
    18512245            if xmin>0:
    18522246                subplot.spines['right'].set_visible(False)
    1853                 subplot.spines['left'].set_position(('outward',10))
     2247                if xscale == 'linear' and yscale == 'linear':
     2248                    subplot.spines['left'].set_position(('outward',10))
    18542249                subplot.yaxis.set_ticks_position('left')
    18552250                subplot.yaxis.set_label_position('left')
    18562251                yaxis='left'
    18572252            elif xmax<0:
    18582253                subplot.spines['left'].set_visible(False)
    1859                 subplot.spines['right'].set_position(('outward',10))
     2254                if xscale == 'linear' and yscale == 'linear':
     2255                    subplot.spines['right'].set_position(('outward',10))
    18602256                subplot.yaxis.set_ticks_position('right')
    18612257                subplot.yaxis.set_label_position('right')
    18622258                yaxis='right'
    18632259            else:
    1864                 subplot.spines['left'].set_position('zero')
     2260                if xscale == 'linear' and yscale == 'linear':
     2261                    subplot.spines['left'].set_position('zero')
    18652262                subplot.yaxis.set_ticks_position('left')
    18662263                subplot.yaxis.set_label_position('left')
    18672264                subplot.spines['right'].set_visible(False)
     
    18702267
    18712268            if ymin>0:
    18722269                subplot.spines['top'].set_visible(False)
    1873                 subplot.spines['bottom'].set_position(('outward',10))
     2270                if xscale == 'linear' and yscale == 'linear':
     2271                    subplot.spines['bottom'].set_position(('outward',10))
    18742272                subplot.xaxis.set_ticks_position('bottom')
    18752273                subplot.xaxis.set_label_position('bottom')
    18762274                xaxis='bottom'
    18772275            elif ymax<0:
    18782276                subplot.spines['bottom'].set_visible(False)
    1879                 subplot.spines['top'].set_position(('outward',10))
     2277                if xscale == 'linear' and yscale == 'linear':
     2278                    subplot.spines['top'].set_position(('outward',10))
    18802279                subplot.xaxis.set_ticks_position('top')
    18812280                subplot.xaxis.set_label_position('top')
    18822281                xaxis='top'
    18832282            else:
    1884                 subplot.spines['bottom'].set_position('zero')
     2283                if xscale == 'linear' and yscale == 'linear':
     2284                    subplot.spines['bottom'].set_position('zero')
    18852285                subplot.xaxis.set_ticks_position('bottom')
    18862286                subplot.xaxis.set_label_position('bottom')
    18872287                subplot.spines['top'].set_visible(False)
     
    19162316            #                     t.set_markersize(4)
    19172317
    19182318            # Make the zero tick labels disappear if the axes cross
    1919             # inside the picture
    1920             if xmiddle and ymiddle:
     2319            # inside the picture, but only if log scale is not used
     2320            if xmiddle and ymiddle and xscale == 'linear' and \
     2321                yscale == 'linear':
    19212322                from sage.plot.plot import SelectiveFormatter
    19222323                subplot.yaxis.set_major_formatter(SelectiveFormatter(
    19232324                    subplot.yaxis.get_major_formatter(), skip_values=[0]))
     
    19352336
    19362337        if frame or axes:
    19372338            # Make minor tickmarks, unless we specify fixed ticks or no ticks
     2339            # We do this change only on linear scale, otherwise matplotlib
     2340            # errors out with a memory error.
    19382341            from matplotlib.ticker import AutoMinorLocator, FixedLocator, NullLocator
    1939             if isinstance(x_locator, (NullLocator, FixedLocator)):
    1940                 subplot.xaxis.set_minor_locator(NullLocator())
    1941             else:
    1942                 subplot.xaxis.set_minor_locator(AutoMinorLocator())
    1943             if isinstance(y_locator, (NullLocator, FixedLocator)):
    1944                 subplot.yaxis.set_minor_locator(NullLocator())
    1945             else:
    1946                 subplot.yaxis.set_minor_locator(AutoMinorLocator())
    1947 
    1948             ticklabels=subplot.xaxis.get_majorticklabels() + \
    1949                 subplot.xaxis.get_minorticklabels() + \
    1950                 subplot.yaxis.get_majorticklabels() + \
    1951                 subplot.yaxis.get_minorticklabels()
    1952             for ticklabel in ticklabels:
    1953                 ticklabel.set_fontsize(self._fontsize)
    1954                 ticklabel.set_color(self._tick_label_color)
    1955 
    1956             ticklines=subplot.xaxis.get_majorticklines() + \
    1957                 subplot.xaxis.get_minorticklines() + \
    1958                 subplot.yaxis.get_majorticklines() + \
    1959                 subplot.yaxis.get_minorticklines()
    1960             for tickline in ticklines:
    1961                 tickline.set_color(self._axes_color)
     2342            if xscale == 'linear':
     2343                if isinstance(x_locator, (NullLocator, FixedLocator)):
     2344                    subplot.xaxis.set_minor_locator(NullLocator())
     2345                else:
     2346                    subplot.xaxis.set_minor_locator(AutoMinorLocator())
     2347            if yscale == 'linear':
     2348                if isinstance(y_locator, (NullLocator, FixedLocator)):
     2349                    subplot.yaxis.set_minor_locator(NullLocator())
     2350                else:
     2351                    subplot.yaxis.set_minor_locator(AutoMinorLocator())
     2352
     2353            # Set the color and fontsize of ticks
     2354            figure.get_axes()[0].tick_params(color=self._axes_color,
     2355                    labelcolor=self._tick_label_color,
     2356                    labelsize=self._fontsize, which='both')
    19622357
    19632358
    19642359        if gridlines is not None: