Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Merge branch 'u/alauve/implement_multi_function_plotting_options_in_p…
Browse files Browse the repository at this point in the history
…lot__' of trac.sagemath.org:sage into public/graphics/multi_function_plot_options-12962

Conflicts:
	src/sage/plot/plot.py
  • Loading branch information
Travis Scrimshaw committed Jul 12, 2016
2 parents db5b361 + f7394a8 commit 276f8eb
Showing 1 changed file with 197 additions and 75 deletions.
272 changes: 197 additions & 75 deletions src/sage/plot/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,9 @@ def f(x): return (x-3)*(x-5)*(x-7)+40
- Jeroen Demeyer (2012-04-19): move parts of this file to graphics.py (:trac:`12857`)
- Aaron Lauve (2015-07-13): reworked handling of 'color' and 'linestyle'
when passed a list of functions; now more in-line with other CAS's. (:trac:`12962`)
"""
#*****************************************************************************
# Copyright (C) 2006 Alex Clemesha <clemesha@gmail.com>
Expand Down Expand Up @@ -778,7 +781,7 @@ def xydata_from_point_list(points):
return xdata, ydata

@rename_keyword(color='rgbcolor')
@options(alpha=1, thickness=1, fill=False, fillcolor='automatic', fillalpha=0.5, rgbcolor=(0,0,1), plot_points=200,
@options(alpha=1, thickness=1, fill=False, fillcolor='automatic', fillalpha=0.5, rgbcolor='automatic', plot_points=200,
adaptive_tolerance=0.01, adaptive_recursion=5, detect_poles = False, exclude = None, legend_label=None,
__original_opts=True, aspect_ratio='automatic')
def plot(funcs, *args, **kwds):
Expand Down Expand Up @@ -846,9 +849,22 @@ def plot(funcs, *args, **kwds):
- ``ymax`` - ending y value in the rendered figure. This parameter is passed
directly to the ``show`` procedure and it could be overwritten.
- ``color`` - an RGB tuple (r,g,b) with each of r,g,b between 0 and 1,
or a color name as a string (e.g., 'purple'), or an HTML color
such as '#aaff0b'.
COLOR OPTIONS:
- ``color`` - (Default: 'blue') One of:
- an RGB tuple (r,g,b) with each of r,g,b between 0 and 1.
- a color name as a string (e.g., 'purple').
- an HTML color such as '#aaff0b'.
- a list or dictionary of colors (valid only if `X` is a list):
if a dictionary, keys are taken from ``range(len(X))``;
the entries/values of the list/dictonary may be any of the options above.
- 'automatic' -- maps to blue if `X` is a single Sage object; and
maps to ``rainbow(len(X))`` if `X` is a list.
- ``detect_poles`` - (Default: False) If set to True poles are detected.
If set to "show" vertical asymptotes are drawn.
Expand Down Expand Up @@ -888,42 +904,51 @@ def plot(funcs, *args, **kwds):
- ``hue`` - The color given as a hue
LINE OPTIONS:
Any MATPLOTLIB line option may also be passed in. E.g.,
- ``linestyle`` - (default: "-") The style of the line, which is one of
- ``"-"`` or ``"solid"``
- ``"--"`` or ``"dashed"``
- ``"-."`` or ``"dash dot"``
- ``":"`` or ``"dotted"``
- ``"None"`` or ``" "`` or ``""`` (nothing)
The linestyle can also be prefixed with a drawing style (e.g., ``"steps--"``)
- ``"default"`` (connect the points with straight lines)
- ``"steps"`` or ``"steps-pre"`` (step function; horizontal
line is to the left of point)
- ``"steps-mid"`` (step function; points are in the middle of
horizontal lines)
- ``"steps-post"`` (step function; horizontal line is to the
right of point)
- ``"-"`` or ``"solid"``
- ``"--"`` or ``"dashed"``
- ``"-."`` or ``"dash dot"``
- ``":"`` or ``"dotted"``
- ``"None"`` or ``" "`` or ``""`` (nothing)
- a list or dictionary (see below)
The linestyle can also be prefixed with a drawing style (e.g., ``"steps--"``)
- ``"default"`` (connect the points with straight lines)
- ``"steps"`` or ``"steps-pre"`` (step function; horizontal
line is to the left of point)
- ``"steps-mid"`` (step function; points are in the middle of
horizontal lines)
- ``"steps-post"`` (step function; horizontal line is to the
right of point)
If `X` is a list, then ``linestyle`` may also be a list, with entries
taken from the strings above, or a dictionary, with keys in ``range(len(X))``
and values taken from the strings above.
- ``marker`` - The style of the markers, which is one of
- ``"None"`` or ``" "`` or ``""`` (nothing) -- default
- ``","`` (pixel), ``"."`` (point)
- ``"_"`` (horizontal line), ``"|"`` (vertical line)
- ``"o"`` (circle), ``"p"`` (pentagon), ``"s"`` (square), ``"x"`` (x), ``"+"`` (plus), ``"*"`` (star)
- ``"D"`` (diamond), ``"d"`` (thin diamond)
- ``"H"`` (hexagon), ``"h"`` (alternative hexagon)
- ``"<"`` (triangle left), ``">"`` (triangle right), ``"^"`` (triangle up), ``"v"`` (triangle down)
- ``"1"`` (tri down), ``"2"`` (tri up), ``"3"`` (tri left), ``"4"`` (tri right)
- ``0`` (tick left), ``1`` (tick right), ``2`` (tick up), ``3`` (tick down)
- ``4`` (caret left), ``5`` (caret right), ``6`` (caret up), ``7`` (caret down), ``8`` (octagon)
- ``"$...$"`` (math TeX string)
- ``(numsides, style, angle)`` to create a custom, regular symbol
- ``numsides`` -- the number of sides
- ``style`` -- ``0`` (regular polygon), ``1`` (star shape), ``2`` (asterisk), ``3`` (circle)
- ``angle`` -- the angular rotation in degrees
- ``"None"`` or ``" "`` or ``""`` (nothing) -- default
- ``","`` (pixel), ``"."`` (point)
- ``"_"`` (horizontal line), ``"|"`` (vertical line)
- ``"o"`` (circle), ``"p"`` (pentagon), ``"s"`` (square), ``"x"`` (x), ``"+"`` (plus), ``"*"`` (star)
- ``"D"`` (diamond), ``"d"`` (thin diamond)
- ``"H"`` (hexagon), ``"h"`` (alternative hexagon)
- ``"<"`` (triangle left), ``">"`` (triangle right), ``"^"`` (triangle up), ``"v"`` (triangle down)
- ``"1"`` (tri down), ``"2"`` (tri up), ``"3"`` (tri left), ``"4"`` (tri right)
- ``0`` (tick left), ``1`` (tick right), ``2`` (tick up), ``3`` (tick down)
- ``4`` (caret left), ``5`` (caret right), ``6`` (caret up), ``7`` (caret down), ``8`` (octagon)
- ``"$...$"`` (math TeX string)
- ``(numsides, style, angle)`` to create a custom, regular symbol
- ``numsides`` -- the number of sides
- ``style`` -- ``0`` (regular polygon), ``1`` (star shape), ``2`` (asterisk), ``3`` (circle)
- ``angle`` -- the angular rotation in degrees
- ``markersize`` - the size of the marker in points
Expand Down Expand Up @@ -957,8 +982,12 @@ def plot(funcs, *args, **kwds):
the j-th function in the list. (But if ``d[i] == j``: Fill the area
between the i-th function in the list and the horizontal line y = j.)
- ``fillcolor`` - (default: 'automatic') The color of the fill.
Either 'automatic' or a color.
- ``fillcolor`` - The color of the fill. One of:
- 'automatic' -- default
- a color, in RGB, color name, or HTML format
- a list or dictionary (valid in the event that `X` is a list),
with values taken from the options above.
- ``fillalpha`` - (default: 0.5) How transparent the fill is.
A number between 0 and 1.
Expand Down Expand Up @@ -1049,6 +1078,15 @@ def plot(funcs, *args, **kwds):
g=plot([sin(n*x) for n in range(1,5)], (0, pi))
sphinx_plot(g)
By default, color and linestyle will change from one primitive to the next.
This may be controlled by modifying ``color`` and ``linestyle`` options::
sage: plot([sin(n*x)+n for n in [1..4]], (0, pi), color='blue', linestyle='-')
Graphics object consisting of 4 graphics primitives
sage: plot([sin(n*x)+n for n in [1..4]], (0, pi), color=['red','orange','green','purple'], linestyle=['-','-','--','-.'])
Graphics object consisting of 4 graphics primitives
We can also build a plot step by step from an empty plot::
sage: a = plot([]); a # passing an empty list returns an empty plot (Graphics() object)
Expand Down Expand Up @@ -1460,16 +1498,26 @@ def h2(x): return -abs(sqrt(x**3 - 1))
sage: p1 = plot(sin(x), -pi, pi, fill = 'axis')
sage: p2 = plot(sin(x), -pi, pi, fill = 'min')
sage: p3 = plot(sin(x), -pi, pi, fill = 'max')
sage: p4 = plot(sin(x), -pi, pi, fill = 0.5)
sage: p4 = plot(sin(x), -pi, pi, fill = 0.5 + cos(x))
sage: graphics_array([[p1, p2], [p3, p4]]).show(frame=True, axes=False) # long time
sage: plot([sin(x), cos(2*x)*sin(4*x)], -pi, pi, fill = {0: 1}, fillcolor = 'red', fillalpha = 1)
Graphics object consisting of 3 graphics primitives
The basic options for filling a list of plots::
sage: p1 = plot([sin(x), cos(2*x)*sin(x)], -pi, pi, fill = {1: [0]}, fillcolor = 'blue', fillalpha = .25, color = 'blue')
sage: p2 = plot([sin(x), cos(2*x)*sin(x)], -pi, pi, fill = {0: 1, 1:[0]}, color = ['blue'])
sage: p3 = plot([sin(x), cos(2*x)*sin(x)], -pi, pi, fill = [0, [0]], fillcolor = ['#f60'], fillalpha = 1, color = {1: 'blue'})
sage: p4 = plot([sin(x), cos(2*x)*sin(x)], (x,-pi, pi), fill = [0, x/pi], fillcolor = 'grey', color=['red', 'blue'])
sage: graphics_array([[p1, p2], [p3, p4]]).show(frame=True, axes=False) # long time
.. PLOT::
g = plot([sin(x), cos(2*x)*sin(4*x)], -pi, pi, fill = {0: 1}, fillcolor = 'red', fillalpha = 1)
sphinx_plot(g)
p1 = plot([sin(x), cos(2*x)*sin(x)], -pi, pi, fill = {1: [0]}, fillcolor = 'blue', fillalpha = .25, color = 'blue')
p2 = plot([sin(x), cos(2*x)*sin(x)], -pi, pi, fill = {0: 1, 1:[0]}, color = ['blue'])
p3 = plot([sin(x), cos(2*x)*sin(x)], -pi, pi, fill = [0, [0]], fillcolor = ['#f60'], fillalpha = 1, color = {1: 'blue'})
p4 = plot([sin(x), cos(2*x)*sin(x)], (x,-pi, pi), fill = [0, x/pi], fillcolor = 'grey', color=['red', 'blue'])
g = graphics_array([[p1, p2], [p3, p4]])
sphinx_plot(g.show(frame=True, axes=False))
A example about the growth of prime numbers::
Expand Down Expand Up @@ -1510,25 +1558,18 @@ def b(n): return lambda x: bessel_J(n, x)
like ``i:j`` will fill between the ith function and the line y=j::
sage: def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1)
sage: plot([b(c) for c in [1..5]], 0, 40, fill = dict([(i, [i+1]) for i in [0..3]]))
sage: plot([b(c) for c in [1..5]], 0, 40, fill = dict([(i, [i+1]) for i in [0..3]]), color = 'blue')
Graphics object consisting of 9 graphics primitives
.. PLOT::
def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1)
g = plot([b(c) for c in range(1,6)], (0, 40), fill = dict([(i, [i+1]) for i in range(0,4)]))
sphinx_plot(g)
::
sage: plot([b(c) for c in [1..5]], 0, 40, fill = dict([(i, i+1) for i in [0..3]])) # long time
sage: plot([b(c) for c in [1..5]], 0, 40, fill = dict([(i, i+1) for i in [0..3]]), color = 'blue', linestyle = '-') # long time
Graphics object consisting of 9 graphics primitives
.. PLOT::
.. PLOT::
def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1)
g = plot([b(c) for c in range(1,6)], 0, 40, fill = dict([(i, i+1) for i in range(0,4)])) # long time
sphinx_plot(g)
def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1)
p1 = plot([b(c) for c in [1..5]], 0, 40, fill = dict([(i, [i+1]) for i in [0..3]]), color = 'blue')
p2 = plot([b(c) for c in [1..5]], 0, 40, fill = dict([(i, i+1) for i in [0..3]]), color = 'blue', linestyle = '-') # long time
g = graphics_array([p1,p2])
sphinx_plot(g.show(frame=True, axes=False))
Extra options will get passed on to :meth:`~sage.plot.graphics.Graphics.show`,
as long as they are valid::
Expand Down Expand Up @@ -1961,38 +2002,119 @@ def _plot(funcs, xrange, parametric=False,
else:
f = funcs

# Keep ``rgbcolor`` option 'automatic' only for lists of functions.
# Otherwise, let the plot color be 'blue'.
if parametric or not isinstance(funcs, (list, tuple)):
if 'rgbcolor' in options.keys() and options['rgbcolor']=='automatic':
options['rgbcolor'] = (0,0,1) # default color for a single curve.

#check to see if funcs is a list of functions that will
#be all plotted together.
if isinstance(funcs, (list, tuple)) and not parametric:
from sage.plot.colors import rainbow
rainbow_colors = rainbow(len(funcs))
from sage.plot.colors import rainbow, Color
rainbow_colors = rainbow(len(funcs)+1)
# :TODO:
# decide if and/or how to replace `rainbow_colors` in the code below.
# for demonstration purposes, `golden_rainbow` is used for `color`
def golden_rainbow(i):
# note: 'blue' has hue-saturation-lightness values (2/3, 1, 1/2).
h = golden_ratio_conjugate = 0.618033988749895
return Color((0.666666666666+i*h) % 1, 1, 0.4, space='hsl')

default_line_styles = ("-","--","-.",":")*len(funcs)

G = Graphics()
for i, h in enumerate(funcs):
if isinstance(fill, dict):
if i in fill:
fill_entry = fill[i]
if isinstance(fill_entry, list):
if fill_entry[0] < len(funcs):
fill_temp = funcs[fill_entry[0]]
options_temp = options.copy()
fill_temp = options_temp.pop('fill', fill)
fillcolor_temp = options_temp.pop('fillcolor', 'automatic')
color_temp = options_temp.pop('rgbcolor', 'automatic')
color_temp = options_temp.pop('color',color_temp)
linestyle_temp = options_temp.pop('linestyle',None)

# passed more than one fill directive?
if isinstance(fill_temp, dict):
if i in fill_temp:
fill_entry_listQ = fill_temp[i]
if isinstance(fill_entry_listQ, list):
if fill_entry_listQ[0] < len(funcs):
fill_entry = funcs[fill_entry_listQ[0]]
else:
fill_entry = False
else:
fill_entry = fill_entry_listQ
else:
fill_entry = False
elif isinstance(fill_temp, (list, tuple)):
if i < len(fill_temp):
fill_entry_listQ = fill_temp[i]
if isinstance(fill_entry_listQ, list):
if fill_entry_listQ[0] < len(funcs):
fill_entry = funcs[fill_entry_listQ[0]]
else:
fill_temp = None
fill_entry = False
else:
fill_temp = fill_entry
fill_entry = fill_entry_listQ
else:
fill_temp = None
fill_entry = False
else:
fill_temp = fill
fill_entry = fill_temp

# passed more than one fillcolor directive?
if isinstance(fillcolor_temp, dict):
if i in fillcolor_temp:
fillcolor_entry = fillcolor_temp[i]
else:
fillcolor_entry = rainbow_colors[i]
elif isinstance(fillcolor_temp, (list, tuple)):
if i < len(fillcolor_temp):
fillcolor_entry = fillcolor_temp[i]
else:
fillcolor_entry = rainbow_colors[i]
elif fillcolor_temp == 'automatic':
fillcolor_entry = rainbow_colors[i]
else:
fillcolor_entry = fillcolor_temp

# passed more than one color directive?
if isinstance(color_temp, dict):
if i in color_temp:
color_entry = color_temp[i]
else:
color_entry = golden_rainbow(i)
elif isinstance(color_temp, (list,tuple)) and isinstance(color_temp[0], (str,list,tuple)):
if i < len(color_temp):
color_entry = color_temp[i]
else:
color_entry = golden_rainbow(i)
elif color_temp == 'automatic':
color_entry = golden_rainbow(i)
else:
color_entry = color_temp

# passed more than one linestyle directive?
if isinstance(linestyle_temp, dict):
if i in linestyle_temp:
linestyle_entry = linestyle_temp[i]
else:
linestyle_entry = default_line_styles[i]
elif isinstance(linestyle_temp, (list,tuple)):
if i < len(linestyle_temp):
linestyle_entry = linestyle_temp[i]
else:
linestyle_entry = default_line_styles[i]
elif linestyle_temp == None:
linestyle_entry = default_line_styles[i]
else:
linestyle_entry = linestyle_temp

options_temp = options.copy()
fillcolor_temp = options_temp.pop('fillcolor', 'automatic')
if i >= 1:
legend_label=options_temp.pop('legend_label', None) # legend_label popped so the label isn't repeated for nothing
if fillcolor_temp == 'automatic':
fillcolor_temp = rainbow_colors[i]

G += plot(h, xrange, polar = polar, fill = fill_temp, \
fillcolor = fillcolor_temp, **options_temp)
#print color_entry
G += plot(h, xrange, polar = polar, fill = fill_entry, fillcolor = fillcolor_entry, \
color = color_entry, linestyle = linestyle_entry, \
**options_temp)
return G

adaptive_tolerance = options.pop('adaptive_tolerance')
Expand Down

0 comments on commit 276f8eb

Please sign in to comment.