# Ticket #1431: trac_1431-ticks-and-formatting.patch

File trac_1431-ticks-and-formatting.patch, 15.6 KB (added by kcrisman, 11 years ago)

Based on 4.3.5, apply only this patch to Sage library

• ## sage/plot/misc.py

# HG changeset patch
# User Karl-Dieter Crisman <kcrisman@gmail.com>
# Date 1271787464 14400
# Node ID 5296ca88bd3a5e500b0f0300d86bfb67c4465864
# Parent  ea02bc44fa947f97673768aede1126e6bc7b2c79
Trac 1431 - includes formatting and location of ticks in 2d plots

diff -r ea02bc44fa94 -r 5296ca88bd3a sage/plot/misc.py
 a # we probably have a constant pass return tuple(sorted(vars, key=lambda x: str(x))), tuple(sorted(free_variables, key=lambda x: str(x))) def multiple_of_constant(n,pos,const): """ Function for internal use in formatting ticks on axes with nice-looking multiples of various symbolic constants, such as \pi or e.  Should only be used via keyword argument tick_formatter in :meth:plot.show.  See documentation for the matplotlib.ticker module for more details. EXAMPLES: Here is the intended use:: sage: plot(sin(x), (x,0,2*pi), tick_locator=pi/3, tick_formatter=pi) Here is an unintended use, which yields unexpected results:: sage: plot(x^2, (x, -2, 2), tick_formatter=pi) We can also use more unusual constant choices:: sage: plot(ln(x), (x,0,10), tick_locator=e, tick_formatter=e) sage: plot(x^2, (x,0,10), tick_locator=[sqrt(2),8], tick_formatter=sqrt(2)) """ from sage.misc.latex import latex from sage.rings.arith import convergents c=[i for i in convergents(n/const.n()) if i.denominator()<12] return '$%s$'%latex(c[-1]*const)
• ## sage/plot/plot.py

diff -r ea02bc44fa94 -r 5296ca88bd3a sage/plot/plot.py
 a sage: plot(x^2,(x,480,500))  # no scientific notation sage: plot(x^2,(x,300,500))  # scientific notation on y-axis But you can fix your own labels, if you know what to expect and have a preference:: sage: plot(x^2,(x,300,500),tick_locator=[None,50000]) Next we construct the reflection of the above polygon about the y-axis by iterating over the list of first-coordinates of the first graphic element of P (which is the actual sage: g2 = plot(2*exp(-30*x) - exp(-3*x), 0, 1) sage: show(graphics_array([g1, g2], 2, 1), xmin=0) Pi Axis: In the PyX manual, the point of this example is to show labeling the X-axis using rational multiples of Pi. Sage currently has no support for controlling how the ticks on the x and y axes are labeled, so this is really a bad example:: Pi Axis:: sage: g1 = plot(sin(x), 0, 2*pi) sage: g2 = plot(cos(x), 0, 2*pi, linestyle = "--") sage: g1 + g2    # show their sum sage: (g1+g2).show(tick_locator=pi/6, tick_formatter=pi)  # show their sum, nicely formatted An illustration of integration:: fontsize=None, aspect_ratio=None, gridlines=None, gridlinesstyle=None, vgridlinesstyle=None, hgridlinesstyle=None,transparent=False, axes_pad=.02) axes_pad=.02, tick_locator=None, tick_formatter=None) def show(self, **kwds): """ etc.  To get axes that are exactly the specified limits, set axes_pad to zero. - tick_locator - A matplotlib locator for the major ticks, or a number. There are several options.  For more information about locators, type from matplotlib import ticker and then ticker?. - If this is a locator object, then it is the locator for the horizontal axis.  A value of None means use the default locator. - If it is a list of two locators, then the first is for the horizontal axis and one for the vertical axis.  A value of None means use the default locator (so a value of [None, my_locator] uses my_locator for the vertical axis and the default for the horizontal axis). - If in either case above one of the entries is a number m (something which can be coerced to a float), it will be replaced by a MultipleLocator which places major ticks at integer multiples of m.  See examples. - If in either case above one of the entries is a list of numbers, it will be replaced by a FixedLocator which places ticks at the locations specified.  See examples. - tick_formatter - A matplotlib formatter for the major ticks. There are several options.  For more information about formatters, type from matplotlib import ticker and then ticker?. - If this is a formatter object, then it is the formatter for the horizontal axis.  A value of None means use the default locator. - If it is a list of two formatters, then the first is for the horizontal axis and one for the vertical axis.  A value of None means use the default formatter (so a value of [None, my_formatter] uses my_formatter for the vertical axis and the default for the horizontal axis). - If in either case above one of the entries is a symbolic constant such as \pi, e, or sqrt(2), ticks will be formatted nicely at rational multiples of this constant. This should only be used with a tick_locator option using nice rational multiples of that constant! - If in either case above one of the entries is the string "latex", then the formatting will be nice typesetting of the ticks.  This is intended to be used when the tick locator for a given axis is a list including some symbolic elements.  See examples. EXAMPLES:: sage: c = circle((1,1), 1, color='red') sage: plot(sin(x), (x, -pi, pi),thickness=2)+point((pi, -1), pointsize=15) sage: plot(sin(x), (x, -pi, pi),thickness=2,axes_pad=0)+point((pi, -1), pointsize=15) Via matplotlib, Sage allows setting of custom ticks.  See documentation for :meth:show for more details. :: sage: plot(sin(pi*x), (x, -8, 8)) # Labels not so helpful sage: plot(sin(pi*x), (x, -8, 8), tick_locator=2) # Multiples of 2 sage: plot(sin(pi*x), (x, -8, 8), tick_locator=[[-7,-3,0,3,7],[-1/2,0,1/2]]) # Your choices sage: plot(1.5/(1+e^(-x)), (x, -10, 10)) # doesn't quite show value of inflection point sage: plot(1.5/(1+e^(-x)), (x, -10, 10), tick_locator=[None, 1.5/4]) # It's right at f(x)=0.75! But be careful to leave enough room for at least two major ticks, so that the user can tell what the scale is. :: sage: plot(x^2,(x,1,8),tick_locator=6) Traceback (most recent call last): ... ValueError: Expand the range of the independent variable to allow two multiples of your tick_locator. We can also do custom formatting if you need it.  See documentation for :meth:show for more details. :: sage: plot(sin(x),(x,0,2*pi),tick_locator=pi/3,tick_formatter=pi) sage: plot(2*x+1,(x,0,5),tick_locator=[[0,1,e,pi,sqrt(20)],2],tick_formatter="latex") """ # This option should not be passed on to save(). axes=None, axes_labels=None, fontsize=None, frame=False, verify=True, aspect_ratio = None, gridlines=None, gridlinesstyle=None, vgridlinesstyle=None, hgridlinesstyle=None,axes_pad=0.02): vgridlinesstyle=None, hgridlinesstyle=None,axes_pad=0.02, tick_formatter=None, tick_locator=None): r""" Return a matplotlib figure object representing the graphic :meth:show method (this function accepts all except the transparent argument). """ if not isinstance(tick_locator, (list, tuple)): tick_locator = (tick_locator, None) if not isinstance(tick_formatter, (list, tuple)): tick_formatter = (tick_formatter, None) self.set_axes_range(xmin, xmax, ymin, ymax) d = self.get_axes_range() xmin = d['xmin'] # For now, set the formatter to the old one, since that is # sort of what we are used to.  We should eventually look at # the default one to see if we like it better. from matplotlib.ticker import OldScalarFormatter, MaxNLocator subplot.xaxis.set_major_locator(MaxNLocator(nbins=9)) subplot.yaxis.set_major_locator(MaxNLocator(nbins=9)) subplot.xaxis.set_major_formatter(OldScalarFormatter()) subplot.yaxis.set_major_formatter(OldScalarFormatter()) from matplotlib.ticker import OldScalarFormatter, MaxNLocator, MultipleLocator, FixedLocator, Locator x_locator, y_locator = tick_locator if x_locator is None: x_locator = MaxNLocator(nbins=9) elif isinstance(x_locator,Locator): pass elif isinstance(x_locator,list): x_locator = FixedLocator(x_locator) else: # x_locator is a number which can be made a float from sage.functions.other import ceil, floor if floor(xmax/x_locator)-ceil(xmin/x_locator)>1: x_locator=MultipleLocator(float(x_locator)) else: # not enough room for two major ticks raise ValueError('Expand the range of the independent variable to allow two multiples of your tick_locator.') if y_locator is None: y_locator = MaxNLocator(nbins=9) elif isinstance(y_locator,Locator): pass elif isinstance(y_locator,Locator): y_locator = FixedLocator(y_locator) else: # y_locator is a number which can be made a float from sage.functions.other import ceil, floor if floor(ymax/y_locator)-ceil(ymin/y_locator)>1: y_locator=MultipleLocator(float(y_locator)) else: # not enough room for two major ticks raise ValueError('Expand the range of the dependent variable to allow two multiples of your tick_locator.') x_formatter, y_formatter = tick_formatter from matplotlib.ticker import FuncFormatter from sage.misc.latex import latex from sage.symbolic.ring import SR if x_formatter is None: x_formatter = OldScalarFormatter() elif x_formatter in SR: from misc import multiple_of_constant x_const = x_formatter x_formatter = FuncFormatter(lambda n,pos: multiple_of_constant(n,pos,x_const)) elif x_formatter == "latex": x_formatter = FuncFormatter(lambda n,pos: '$%s$'%latex(n)) if y_formatter is None: y_formatter = OldScalarFormatter() elif y_formatter in SR: from misc import multiple_of_constant y_const = y_formatter y_formatter = FuncFormatter(lambda n,pos: multiple_of_constant(n,pos,y_const)) elif y_formatter == "latex": y_formatter = FuncFormatter(lambda n,pos: '$%s$'%latex(n)) subplot.xaxis.set_major_locator(x_locator) subplot.yaxis.set_major_locator(y_locator) subplot.xaxis.set_major_formatter(x_formatter) subplot.yaxis.set_major_formatter(y_formatter) subplot.set_frame_on(True) if axes: # For now, set the formatter to the old one, since that is # sort of what we are used to.  We should eventually look at # the default one to see if we like it better. from matplotlib.ticker import OldScalarFormatter, MaxNLocator subplot.xaxis.set_major_locator(MaxNLocator(nbins=10,steps=[1,2,5,10])) subplot.yaxis.set_major_locator(MaxNLocator(nbins=10,steps=[1,2,5,10])) subplot.xaxis.set_major_formatter(OldScalarFormatter()) subplot.yaxis.set_major_formatter(OldScalarFormatter()) from matplotlib.ticker import OldScalarFormatter, MaxNLocator, MultipleLocator, FixedLocator, Locator x_locator, y_locator = tick_locator if x_locator is None: x_locator = MaxNLocator(nbins=9, steps=[1,2,5,10]) elif isinstance(x_locator,Locator): pass elif isinstance(x_locator,list): x_locator = FixedLocator(x_locator) else: # x_locator is a number which can be made a float from sage.functions.other import ceil, floor if floor(xmax/x_locator)-ceil(xmin/x_locator)>1: x_locator=MultipleLocator(float(x_locator)) else: # not enough room for two major ticks raise ValueError('Expand the range of the independent variable to allow two multiples of your tick_locator.') if y_locator is None: y_locator = MaxNLocator(nbins=9, steps=[1,2,5,10]) elif isinstance(y_locator,Locator): pass elif isinstance(y_locator,list): y_locator = FixedLocator(y_locator) else: # y_locator is a number which can be made a float from sage.functions.other import ceil, floor if floor(ymax/y_locator)-ceil(ymin/y_locator)>1: y_locator=MultipleLocator(float(y_locator)) else: # not enough room for two major ticks raise ValueError('Expand the range of the dependent variable to allow two multiples of your tick_locator.') x_formatter, y_formatter = tick_formatter from matplotlib.ticker import FuncFormatter from sage.misc.latex import latex from sage.symbolic.ring import SR if x_formatter is None: x_formatter = OldScalarFormatter() elif x_formatter in SR: from misc import multiple_of_constant x_const = x_formatter x_formatter = FuncFormatter(lambda n,pos: multiple_of_constant(n,pos,x_const)) elif x_formatter == "latex": x_formatter = FuncFormatter(lambda n,pos: '$%s$'%latex(n)) if y_formatter is None: y_formatter = OldScalarFormatter() elif y_formatter in SR: from misc import multiple_of_constant y_const = y_formatter y_formatter = FuncFormatter(lambda n,pos: multiple_of_constant(n,pos,y_const)) elif y_formatter == "latex": y_formatter = FuncFormatter(lambda n,pos: '$%s$'%latex(n)) subplot.xaxis.set_major_locator(x_locator) subplot.yaxis.set_major_locator(y_locator) subplot.xaxis.set_major_formatter(x_formatter) subplot.yaxis.set_major_formatter(y_formatter) # Make ticklines go on both sides of the axes #             if xmiddle: