Tutorial for Advanced 2d Plotting¶
This Sage document is one of the tutorials developed for the MAA PREP Workshop “Sage: Using Open-Source Mathematics Software with Undergraduates” (funding provided by NSF DUE 0817071). It is licensed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA).
Thanks to Sage’s integration of projects like matplotlib, Sage has comprehensive two-dimensional plotting capabilities. This worksheet consists of the following sections:
This tutorial assumes that one is familiar with the basics of Sage, such as evaluating a cell by clicking the “evaluate” link, or by pressing Shift + Enter (hold down Shift while pressing the Enter key).
Graphing Functions and Plotting Curves¶
Cartesian Plots¶
A simple quadratic is easy.
sage: plot(x^2, (x,-2,2))
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> plot(x**Integer(2), (x,-Integer(2),Integer(2)))
Graphics object consisting of 1 graphics primitive
plot(x^2, (x,-2,2))
You can combine “plot objects” by adding them.
sage: regular = plot(x^2, (x,-2,2), color= 'purple')
sage: skinny = plot(4*x^2, (x,-2,2), color = 'green')
sage: regular + skinny
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> regular = plot(x**Integer(2), (x,-Integer(2),Integer(2)), color= 'purple')
>>> skinny = plot(Integer(4)*x**Integer(2), (x,-Integer(2),Integer(2)), color = 'green')
>>> regular + skinny
Graphics object consisting of 2 graphics primitives
regular = plot(x^2, (x,-2,2), color= 'purple') skinny = plot(4*x^2, (x,-2,2), color = 'green') regular + skinny
Problem : Plot a green \(y=\sin(x)\) together with a red
\(y=2\,\cos(x)\). (Hint: you can use pi
as part of your range.)
Boundaries of a plot can be specified, in addition to the overall size.
sage: plot(1+e^(-x^2), xmin=-2, xmax=2, ymin=0, ymax=2.5, figsize=10)
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> plot(Integer(1)+e**(-x**Integer(2)), xmin=-Integer(2), xmax=Integer(2), ymin=Integer(0), ymax=RealNumber('2.5'), figsize=Integer(10))
Graphics object consisting of 1 graphics primitive
plot(1+e^(-x^2), xmin=-2, xmax=2, ymin=0, ymax=2.5, figsize=10)
Problem : Plot \(y=5+3\,\sin(4x)\) with suitable boundaries.
You can add lots of extra information.
sage: exponential = plot(1+e^(-x^2), xmin=-2, xmax=2, ymin=0, ymax=2.5)
sage: max_line = plot(2, xmin=-2, xmax=2, linestyle='-.', color = 'red')
sage: min_line = plot(1, xmin=-2, xmax=2, linestyle=':', color = 'red')
sage: exponential + max_line + min_line
Graphics object consisting of 3 graphics primitives
>>> from sage.all import *
>>> exponential = plot(Integer(1)+e**(-x**Integer(2)), xmin=-Integer(2), xmax=Integer(2), ymin=Integer(0), ymax=RealNumber('2.5'))
>>> max_line = plot(Integer(2), xmin=-Integer(2), xmax=Integer(2), linestyle='-.', color = 'red')
>>> min_line = plot(Integer(1), xmin=-Integer(2), xmax=Integer(2), linestyle=':', color = 'red')
>>> exponential + max_line + min_line
Graphics object consisting of 3 graphics primitives
exponential = plot(1+e^(-x^2), xmin=-2, xmax=2, ymin=0, ymax=2.5) max_line = plot(2, xmin=-2, xmax=2, linestyle='-.', color = 'red') min_line = plot(1, xmin=-2, xmax=2, linestyle=':', color = 'red') exponential + max_line + min_line
You can fill regions with transparent color, and thicken the curve. This example uses several options to fine-tune our graphic.
sage: exponential = plot(1+e^(-x^2), xmin=-2, xmax=2, ymin=0, ymax=2.5, fill=0.5, fillcolor='grey', fillalpha=0.3)
sage: min_line = plot(1, xmin=-2, xmax=2, linestyle='-', thickness= 6, color = 'red')
sage: exponential + min_line
Graphics object consisting of 3 graphics primitives
>>> from sage.all import *
>>> exponential = plot(Integer(1)+e**(-x**Integer(2)), xmin=-Integer(2), xmax=Integer(2), ymin=Integer(0), ymax=RealNumber('2.5'), fill=RealNumber('0.5'), fillcolor='grey', fillalpha=RealNumber('0.3'))
>>> min_line = plot(Integer(1), xmin=-Integer(2), xmax=Integer(2), linestyle='-', thickness= Integer(6), color = 'red')
>>> exponential + min_line
Graphics object consisting of 3 graphics primitives
exponential = plot(1+e^(-x^2), xmin=-2, xmax=2, ymin=0, ymax=2.5, fill=0.5, fillcolor='grey', fillalpha=0.3) min_line = plot(1, xmin=-2, xmax=2, linestyle='-', thickness= 6, color = 'red') exponential + min_line
sage: sum([plot(x^n,(x,0,1),color=rainbow(5)[n]) for n in [0..4]])
Graphics object consisting of 5 graphics primitives
>>> from sage.all import *
>>> sum([plot(x**n,(x,Integer(0),Integer(1)),color=rainbow(Integer(5))[n]) for n in (ellipsis_range(Integer(0),Ellipsis,Integer(4)))])
Graphics object consisting of 5 graphics primitives
sum([plot(x^n,(x,0,1),color=rainbow(5)[n]) for n in [0..4]])
>>> from sage.all import *
>>> sum([plot(x**n,(x,Integer(0),Integer(1)),color=rainbow(Integer(5))[n]) for n in (ellipsis_range(Integer(0),Ellipsis,Integer(4)))])
Graphics object consisting of 5 graphics primitives
sum([plot(x^n,(x,0,1),color=rainbow(5)[n]) for n in [0..4]])
Problem : Create a plot showing the cross-section area for the following solid of revolution problem: Consider the area bounded by \(y=x^2-3x+6\) and the line \(y=4\). Find the volume created by rotating this area around the line \(y=1\).
Parametric Plots¶
A parametric plot needs a list of two functions of the parameter; in
Sage, we use square brackets to delimit the list. Notice also that we
must declare t
as a variable first. Because the graphic is slightly
wider than it is tall, we use the aspect_ratio
option (such options
are called keywords ) to ensure the axes are correct for how we want
to view this object.
sage: t = var('t')
sage: parametric_plot([cos(t) + 3 * cos(t/9), sin(t) - 3 * sin(t/9)], (t, 0, 18*pi), fill = True, aspect_ratio=1)
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> t = var('t')
>>> parametric_plot([cos(t) + Integer(3) * cos(t/Integer(9)), sin(t) - Integer(3) * sin(t/Integer(9))], (t, Integer(0), Integer(18)*pi), fill = True, aspect_ratio=Integer(1))
Graphics object consisting of 2 graphics primitives
t = var('t') parametric_plot([cos(t) + 3 * cos(t/9), sin(t) - 3 * sin(t/9)], (t, 0, 18*pi), fill = True, aspect_ratio=1)
Problem : These parametric equations will create a hypocycloid.
Create this as a parametric plot.
Sage automatically plots a 2d or 3d plot, and a curve or a surface, depending on how many variables and coordinates you specify.
sage: t = var('t')
sage: parametric_plot((t^2,sin(t)), (t,0,pi))
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> t = var('t')
>>> parametric_plot((t**Integer(2),sin(t)), (t,Integer(0),pi))
Graphics object consisting of 1 graphics primitive
t = var('t') parametric_plot((t^2,sin(t)), (t,0,pi))
sage: parametric_plot((t^2,sin(t),cos(t)), (t,0,pi))
Graphics3d Object
>>> from sage.all import *
>>> parametric_plot((t**Integer(2),sin(t),cos(t)), (t,Integer(0),pi))
Graphics3d Object
parametric_plot((t^2,sin(t),cos(t)), (t,0,pi))
>>> from sage.all import *
>>> parametric_plot((t**Integer(2),sin(t),cos(t)), (t,Integer(0),pi))
Graphics3d Object
parametric_plot((t^2,sin(t),cos(t)), (t,0,pi))
sage: r = var('r')
sage: parametric_plot((t^2,sin(r*t),cos(r*t)), (t,0,pi),(r,-1,1))
Graphics3d Object
>>> from sage.all import *
>>> r = var('r')
>>> parametric_plot((t**Integer(2),sin(r*t),cos(r*t)), (t,Integer(0),pi),(r,-Integer(1),Integer(1)))
Graphics3d Object
r = var('r') parametric_plot((t^2,sin(r*t),cos(r*t)), (t,0,pi),(r,-1,1))
>>> from sage.all import *
>>> r = var('r')
>>> parametric_plot((t**Integer(2),sin(r*t),cos(r*t)), (t,Integer(0),pi),(r,-Integer(1),Integer(1)))
Graphics3d Object
r = var('r') parametric_plot((t^2,sin(r*t),cos(r*t)), (t,0,pi),(r,-1,1))
Polar Plots¶
Sage can also do polar plots.
sage: polar_plot(2 + 2*cos(x), (x, 0, 2*pi), color=hue(0.5), thickness=4)
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> polar_plot(Integer(2) + Integer(2)*cos(x), (x, Integer(0), Integer(2)*pi), color=hue(RealNumber('0.5')), thickness=Integer(4))
Graphics object consisting of 1 graphics primitive
polar_plot(2 + 2*cos(x), (x, 0, 2*pi), color=hue(0.5), thickness=4)
Although they aren’t essential, many of these examples try to demonstrate things like coloring, fills, and shading to give you a sense of the possibilities.
More than one polar curve can be specified in a list (square brackets). Notice the automatic graded shading of the fill color.
sage: t = var('t')
sage: polar_plot([cos(4*t) + 1.5, 0.5 * cos(4*t) + 2.5], (t, 0, 2*pi),
....: color='black', thickness=2, fill=True, fillcolor='orange')
Graphics object consisting of 4 graphics primitives
>>> from sage.all import *
>>> t = var('t')
>>> polar_plot([cos(Integer(4)*t) + RealNumber('1.5'), RealNumber('0.5') * cos(Integer(4)*t) + RealNumber('2.5')], (t, Integer(0), Integer(2)*pi),
... color='black', thickness=Integer(2), fill=True, fillcolor='orange')
Graphics object consisting of 4 graphics primitives
t = var('t') polar_plot([cos(4*t) + 1.5, 0.5 * cos(4*t) + 2.5], (t, 0, 2*pi), color='black', thickness=2, fill=True, fillcolor='orange')
Problem: Create a plot for the following problem. Find the area that is inside the circle \(r=2\), but outside the cardioid \(2+2\cos(\theta)\).
Interactive Demonstration¶
It may be of interest to see all these things put together in a very nice pedagogical graphic. Even though this is fairly advanced, and so you may want to skip the code, it is not as difficult as you might think to put together.
sage: html('<h2>Sine and unit circle (by Jurgis Pralgauskis)</h2> inspired by <a href="http://www.youtube.com/watch?v=Ohp6Okk_tww&feature=related">this video</a>' )
sage: # http://doc.sagemath.org/html/en/reference/sage/plot/plot.html
sage: radius = 100 # scale for radius of "unit" circle
sage: graph_params = dict(xmin = -2*radius, xmax = 360,
....: ymin = -(radius+30), ymax = radius+30,
....: aspect_ratio=1,
....: axes = False
....: )
sage: def sine_and_unit_circle( angle=30, instant_show = True, show_pi=True ):
....: ccenter_x, ccenter_y = -radius, 0 # center of circle on real coords
....: sine_x = angle # the big magic to sync both graphs :)
....: current_y = circle_y = sine_y = radius * sin(angle*pi/180)
....: circle_x = ccenter_x + radius * cos(angle*pi/180)
....: graph = Graphics()
....: # we'll put unit circle and sine function on the same graph
....: # so there will be some coordinate mangling ;)
....: # CIRCLE
....: unit_circle = circle((ccenter_x, ccenter_y), radius, color="#ccc")
....: # SINE
....: x = var('x')
....: sine = plot( radius * sin(x*pi/180) , (x, 0, 360), color="#ccc" )
....: graph += unit_circle + sine
....: # CIRCLE axis
....: # x axis
....: graph += arrow( [-2*radius, 0], [0, 0], color = "#666" )
....: graph += text("$(1, 0)$", [-16, 16], color = "#666")
....: # circle y axis
....: graph += arrow( [ccenter_x,-radius], [ccenter_x, radius], color = "#666" )
....: graph += text("$(0, 1)$", [ccenter_x, radius+15], color = "#666")
....: # circle center
....: graph += text("$(0, 0)$", [ccenter_x, 0], color = "#666")
....: # SINE x axis
....: graph += arrow( [0,0], [360, 0], color = "#000" )
....: # let's set tics
....: # or http://aghitza.org/posts/tweak_labels_and_ticks_in_2d_plots_using_matplotlib/
....: # or wayt for https://github.com/sagemath/sage/issues/1431
....: # ['$-\pi/3$', '$2\pi/3$', '$5\pi/3$']
....: for x in range(0, 361, 30):
....: graph += point( [x, 0] )
....: angle_label = ". $%3d^{\circ}$ " % x
....: if show_pi: angle_label += " $(%s\pi) $"% x/180
....: graph += text(angle_label, [x, 0], rotation=-90,
....: vertical_alignment='top', fontsize=8, color="#000" )
....: # CURRENT VALUES
....: # SINE -- y
....: graph += arrow( [sine_x,0], [sine_x, sine_y], width=1, arrowsize=3)
....: graph += arrow( [circle_x,0], [circle_x, circle_y], width=1, arrowsize=3)
....: graph += line(([circle_x, current_y], [sine_x, current_y]), rgbcolor="#0F0", linestyle = "--", alpha=0.5)
....: # LABEL on sine
....: graph += text("$(%d^{\circ}, %3.2f)$"%(sine_x, float(current_y)/radius), [sine_x+30, current_y], color = "#0A0")
....: # ANGLE -- x
....: # on sine
....: graph += arrow( [0,0], [sine_x, 0], width=1, arrowsize=1, color='red')
....: # on circle
....: graph += disk( (ccenter_x, ccenter_y), float(radius)/4, (0, angle*pi/180), color='red', fill=False, thickness=1)
....: graph += arrow( [ccenter_x, ccenter_y], [circle_x, circle_y],
....: rgbcolor="#cccccc", width=1, arrowsize=1)
....: if instant_show:
....: show (graph, **graph_params)
....: return graph
sage: #####################
sage: # make Interaction
sage: ######################
sage: @interact
sage: def _( angle = slider([0..360], default=30, step_size=5,
....: label="Pasirinkite kampą: ", display_value=True) ):
....: sine_and_unit_circle(angle, show_pi = False)
>>> from sage.all import *
>>> html('<h2>Sine and unit circle (by Jurgis Pralgauskis)</h2> inspired by <a href="http://www.youtube.com/watch?v=Ohp6Okk_tww&feature=related">this video</a>' )
>>> # http://doc.sagemath.org/html/en/reference/sage/plot/plot.html
>>> radius = Integer(100) # scale for radius of "unit" circle
>>> graph_params = dict(xmin = -Integer(2)*radius, xmax = Integer(360),
... ymin = -(radius+Integer(30)), ymax = radius+Integer(30),
... aspect_ratio=Integer(1),
... axes = False
... )
>>> def sine_and_unit_circle( angle=Integer(30), instant_show = True, show_pi=True ):
... ccenter_x, ccenter_y = -radius, Integer(0) # center of circle on real coords
... sine_x = angle # the big magic to sync both graphs :)
... current_y = circle_y = sine_y = radius * sin(angle*pi/Integer(180))
... circle_x = ccenter_x + radius * cos(angle*pi/Integer(180))
... graph = Graphics()
... # we'll put unit circle and sine function on the same graph
... # so there will be some coordinate mangling ;)
... # CIRCLE
... unit_circle = circle((ccenter_x, ccenter_y), radius, color="#ccc")
... # SINE
... x = var('x')
... sine = plot( radius * sin(x*pi/Integer(180)) , (x, Integer(0), Integer(360)), color="#ccc" )
... graph += unit_circle + sine
... # CIRCLE axis
... # x axis
... graph += arrow( [-Integer(2)*radius, Integer(0)], [Integer(0), Integer(0)], color = "#666" )
... graph += text("$(1, 0)$", [-Integer(16), Integer(16)], color = "#666")
... # circle y axis
... graph += arrow( [ccenter_x,-radius], [ccenter_x, radius], color = "#666" )
... graph += text("$(0, 1)$", [ccenter_x, radius+Integer(15)], color = "#666")
... # circle center
... graph += text("$(0, 0)$", [ccenter_x, Integer(0)], color = "#666")
... # SINE x axis
... graph += arrow( [Integer(0),Integer(0)], [Integer(360), Integer(0)], color = "#000" )
... # let's set tics
... # or http://aghitza.org/posts/tweak_labels_and_ticks_in_2d_plots_using_matplotlib/
... # or wayt for https://github.com/sagemath/sage/issues/1431
... # ['$-\pi/3$', '$2\pi/3$', '$5\pi/3$']
... for x in range(Integer(0), Integer(361), Integer(30)):
... graph += point( [x, Integer(0)] )
... angle_label = ". $%3d^{\circ}$ " % x
... if show_pi: angle_label += " $(%s\pi) $"% x/Integer(180)
... graph += text(angle_label, [x, Integer(0)], rotation=-Integer(90),
... vertical_alignment='top', fontsize=Integer(8), color="#000" )
... # CURRENT VALUES
... # SINE -- y
... graph += arrow( [sine_x,Integer(0)], [sine_x, sine_y], width=Integer(1), arrowsize=Integer(3))
... graph += arrow( [circle_x,Integer(0)], [circle_x, circle_y], width=Integer(1), arrowsize=Integer(3))
... graph += line(([circle_x, current_y], [sine_x, current_y]), rgbcolor="#0F0", linestyle = "--", alpha=RealNumber('0.5'))
... # LABEL on sine
... graph += text("$(%d^{\circ}, %3.2f)$"%(sine_x, float(current_y)/radius), [sine_x+Integer(30), current_y], color = "#0A0")
... # ANGLE -- x
... # on sine
... graph += arrow( [Integer(0),Integer(0)], [sine_x, Integer(0)], width=Integer(1), arrowsize=Integer(1), color='red')
... # on circle
... graph += disk( (ccenter_x, ccenter_y), float(radius)/Integer(4), (Integer(0), angle*pi/Integer(180)), color='red', fill=False, thickness=Integer(1))
... graph += arrow( [ccenter_x, ccenter_y], [circle_x, circle_y],
... rgbcolor="#cccccc", width=Integer(1), arrowsize=Integer(1))
... if instant_show:
... show (graph, **graph_params)
... return graph
>>> #####################
>>> # make Interaction
>>> ######################
>>> @interact
>>> def _( angle = slider((ellipsis_range(Integer(0),Ellipsis,Integer(360))), default=Integer(30), step_size=Integer(5),
... label="Pasirinkite kampą: ", display_value=True) ):
... sine_and_unit_circle(angle, show_pi = False)
html('<h2>Sine and unit circle (by Jurgis Pralgauskis)</h2> inspired by <a href="http://www.youtube.com/watch?v=Ohp6Okk_tww&feature=related">this video</a>' ) # http://doc.sagemath.org/html/en/reference/sage/plot/plot.html radius = 100 # scale for radius of "unit" circle graph_params = dict(xmin = -2*radius, xmax = 360, ymin = -(radius+30), ymax = radius+30, aspect_ratio=1, axes = False ) def sine_and_unit_circle( angle=30, instant_show = True, show_pi=True ): ccenter_x, ccenter_y = -radius, 0 # center of circle on real coords sine_x = angle # the big magic to sync both graphs :) current_y = circle_y = sine_y = radius * sin(angle*pi/180) circle_x = ccenter_x + radius * cos(angle*pi/180) graph = Graphics() # we'll put unit circle and sine function on the same graph # so there will be some coordinate mangling ;) # CIRCLE unit_circle = circle((ccenter_x, ccenter_y), radius, color="#ccc") # SINE x = var('x') sine = plot( radius * sin(x*pi/180) , (x, 0, 360), color="#ccc" ) graph += unit_circle + sine # CIRCLE axis # x axis graph += arrow( [-2*radius, 0], [0, 0], color = "#666" ) graph += text("$(1, 0)$", [-16, 16], color = "#666") # circle y axis graph += arrow( [ccenter_x,-radius], [ccenter_x, radius], color = "#666" ) graph += text("$(0, 1)$", [ccenter_x, radius+15], color = "#666") # circle center graph += text("$(0, 0)$", [ccenter_x, 0], color = "#666") # SINE x axis graph += arrow( [0,0], [360, 0], color = "#000" ) # let's set tics # or http://aghitza.org/posts/tweak_labels_and_ticks_in_2d_plots_using_matplotlib/ # or wayt for https://github.com/sagemath/sage/issues/1431 # ['$-\pi/3$', '$2\pi/3$', '$5\pi/3$'] for x in range(0, 361, 30): graph += point( [x, 0] ) angle_label = ". $%3d^{\circ}$ " % x if show_pi: angle_label += " $(%s\pi) $"% x/180 graph += text(angle_label, [x, 0], rotation=-90, vertical_alignment='top', fontsize=8, color="#000" ) # CURRENT VALUES # SINE -- y graph += arrow( [sine_x,0], [sine_x, sine_y], width=1, arrowsize=3) graph += arrow( [circle_x,0], [circle_x, circle_y], width=1, arrowsize=3) graph += line(([circle_x, current_y], [sine_x, current_y]), rgbcolor="#0F0", linestyle = "--", alpha=0.5) # LABEL on sine graph += text("$(%d^{\circ}, %3.2f)$"%(sine_x, float(current_y)/radius), [sine_x+30, current_y], color = "#0A0") # ANGLE -- x # on sine graph += arrow( [0,0], [sine_x, 0], width=1, arrowsize=1, color='red') # on circle graph += disk( (ccenter_x, ccenter_y), float(radius)/4, (0, angle*pi/180), color='red', fill=False, thickness=1) graph += arrow( [ccenter_x, ccenter_y], [circle_x, circle_y], rgbcolor="#cccccc", width=1, arrowsize=1) if instant_show: show (graph, **graph_params) return graph ##################### # make Interaction ###################### @interact def _( angle = slider([0..360], default=30, step_size=5, label="Pasirinkite kampą: ", display_value=True) ): sine_and_unit_circle(angle, show_pi = False)
Plotting Data¶
Plotting Data Points¶
Sometimes one wishes to simply plot data. Here, we demonstrate several ways of plotting points and data via the simple approximation to the Fibonacci numbers given by
which is quite good after about \(n=5\).
First, we notice that the Fibonacci numbers are built in.
sage: fibonacci_sequence(6)
<generator object fibonacci_sequence at ...>
>>> from sage.all import *
>>> fibonacci_sequence(Integer(6))
<generator object fibonacci_sequence at ...>
fibonacci_sequence(6)
sage: list(fibonacci_sequence(6))
[0, 1, 1, 2, 3, 5]
>>> from sage.all import *
>>> list(fibonacci_sequence(Integer(6)))
[0, 1, 1, 2, 3, 5]
list(fibonacci_sequence(6))
>>> from sage.all import *
>>> list(fibonacci_sequence(Integer(6)))
[0, 1, 1, 2, 3, 5]
list(fibonacci_sequence(6))
The enumerate
command is useful for taking a list and coordinating
it with the counting numbers.
sage: list(enumerate(fibonacci_sequence(6)))
[(0, 0), (1, 1), (2, 1), (3, 2), (4, 3), (5, 5)]
>>> from sage.all import *
>>> list(enumerate(fibonacci_sequence(Integer(6))))
[(0, 0), (1, 1), (2, 1), (3, 2), (4, 3), (5, 5)]
list(enumerate(fibonacci_sequence(6)))
So we just define the numbers and coordinate pairs we are about to plot.
sage: fibonacci = list(enumerate(fibonacci_sequence(6)))
sage: f(n)=(1/sqrt(5))*((1+sqrt(5))/2)^n
sage: asymptotic = [(i, f(i)) for i in range(6)]
sage: fibonacci
[(0, 0), (1, 1), (2, 1), (3, 2), (4, 3), (5, 5)]
sage: asymptotic
[(0, 1/5*sqrt(5)), (1, 1/10*sqrt(5)*(sqrt(5) + 1)), (2, 1/20*sqrt(5)*(sqrt(5) + 1)^2), (3, 1/40*sqrt(5)*(sqrt(5) + 1)^3), (4, 1/80*sqrt(5)*(sqrt(5) + 1)^4), (5, 1/160*sqrt(5)*(sqrt(5) + 1)^5)]
>>> from sage.all import *
>>> fibonacci = list(enumerate(fibonacci_sequence(Integer(6))))
>>> __tmp__=var("n"); f = symbolic_expression((Integer(1)/sqrt(Integer(5)))*((Integer(1)+sqrt(Integer(5)))/Integer(2))**n).function(n)
>>> asymptotic = [(i, f(i)) for i in range(Integer(6))]
>>> fibonacci
[(0, 0), (1, 1), (2, 1), (3, 2), (4, 3), (5, 5)]
>>> asymptotic
[(0, 1/5*sqrt(5)), (1, 1/10*sqrt(5)*(sqrt(5) + 1)), (2, 1/20*sqrt(5)*(sqrt(5) + 1)^2), (3, 1/40*sqrt(5)*(sqrt(5) + 1)^3), (4, 1/80*sqrt(5)*(sqrt(5) + 1)^4), (5, 1/160*sqrt(5)*(sqrt(5) + 1)^5)]
fibonacci = list(enumerate(fibonacci_sequence(6))) f(n)=(1/sqrt(5))*((1+sqrt(5))/2)^n asymptotic = [(i, f(i)) for i in range(6)] fibonacci asymptotic
Now we can plot not just the two sets of points, but also use several of
the documented options for plotting points. Those coming from other
systems may prefer list_plot
.
sage: fib_plot=list_plot(fibonacci, color='red', pointsize=30)
sage: asy_plot = list_plot(asymptotic, marker='D',color='black',thickness=2,plotjoined=True)
sage: show(fib_plot+asy_plot, aspect_ratio=1)
>>> from sage.all import *
>>> fib_plot=list_plot(fibonacci, color='red', pointsize=Integer(30))
>>> asy_plot = list_plot(asymptotic, marker='D',color='black',thickness=Integer(2),plotjoined=True)
>>> show(fib_plot+asy_plot, aspect_ratio=Integer(1))
fib_plot=list_plot(fibonacci, color='red', pointsize=30) asy_plot = list_plot(asymptotic, marker='D',color='black',thickness=2,plotjoined=True) show(fib_plot+asy_plot, aspect_ratio=1)
Other options include line
, points
, and scatter_plot
.
Having the choice of markers for different data is particularly helpful
for generating publishable graphics.
sage: fib_plot=scatter_plot(fibonacci, facecolor='red', marker='o',markersize=40)
sage: asy_plot = line(asymptotic, marker='D',color='black',thickness=2)
sage: show(fib_plot+asy_plot, aspect_ratio=1)
>>> from sage.all import *
>>> fib_plot=scatter_plot(fibonacci, facecolor='red', marker='o',markersize=Integer(40))
>>> asy_plot = line(asymptotic, marker='D',color='black',thickness=Integer(2))
>>> show(fib_plot+asy_plot, aspect_ratio=Integer(1))
fib_plot=scatter_plot(fibonacci, facecolor='red', marker='o',markersize=40) asy_plot = line(asymptotic, marker='D',color='black',thickness=2) show(fib_plot+asy_plot, aspect_ratio=1)
Contour-type Plots¶
Contour Plots¶
Contour plotting can be very useful when trying to get a handle on multivariable functions, as well as modeling. The basic syntax is essentially the same as for 3D plotting - simply an extension of the 2D plotting syntax.
sage: f(x,y)=y^2+1-x^3-x
sage: contour_plot(f, (x,-pi,pi), (y,-pi,pi))
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> __tmp__=var("x,y"); f = symbolic_expression(y**Integer(2)+Integer(1)-x**Integer(3)-x).function(x,y)
>>> contour_plot(f, (x,-pi,pi), (y,-pi,pi))
Graphics object consisting of 1 graphics primitive
f(x,y)=y^2+1-x^3-x contour_plot(f, (x,-pi,pi), (y,-pi,pi))
We can change colors, specify contours, label curves, and many other
things. When there are many levels, the colorbar
keyword becomes
quite useful for keeping track of them. Notice that, as opposed to many
other options, it can only be True
or False
(corresponding to
whether it appears or does not appear).
sage: contour_plot(f, (x,-pi,pi), (y,-pi,pi),colorbar=True,labels=True)
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> contour_plot(f, (x,-pi,pi), (y,-pi,pi),colorbar=True,labels=True)
Graphics object consisting of 1 graphics primitive
contour_plot(f, (x,-pi,pi), (y,-pi,pi),colorbar=True,labels=True)
This example is fairly self-explanatory, but demonstrates the power of
formatting, labeling, and the wide variety of built-in color gradations
(colormaps or cmap
). The strange-looking construction
corresponding to label_fmt
is a Sage/Python data type called a
dictionary , and turns out to be useful for more advanced Sage use; it
consists of pairs connected by a colon, all inside curly braces.
sage: contour_plot(f, (x,-pi,pi), (y,-pi,pi), contours=[-4,0,4], fill=False,
....: cmap='cool', labels=True, label_inline=True,
....: label_fmt={-4:"low", 0:"medium", 4: "hi"}, label_colors='black')
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> contour_plot(f, (x,-pi,pi), (y,-pi,pi), contours=[-Integer(4),Integer(0),Integer(4)], fill=False,
... cmap='cool', labels=True, label_inline=True,
... label_fmt={-Integer(4):"low", Integer(0):"medium", Integer(4): "hi"}, label_colors='black')
Graphics object consisting of 1 graphics primitive
contour_plot(f, (x,-pi,pi), (y,-pi,pi), contours=[-4,0,4], fill=False, cmap='cool', labels=True, label_inline=True, label_fmt={-4:"low", 0:"medium", 4: "hi"}, label_colors='black')
Implicit plots are a special type of contour plot (they just plot the zero contour).
sage: f(x,y)
-x^3 + y^2 - x + 1
>>> from sage.all import *
>>> f(x,y)
-x^3 + y^2 - x + 1
f(x,y)
sage: implicit_plot(f(x,y)==0,(x,-pi,pi),(y,-pi,pi))
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> implicit_plot(f(x,y)==Integer(0),(x,-pi,pi),(y,-pi,pi))
Graphics object consisting of 1 graphics primitive
implicit_plot(f(x,y)==0,(x,-pi,pi),(y,-pi,pi))
>>> from sage.all import *
>>> implicit_plot(f(x,y)==Integer(0),(x,-pi,pi),(y,-pi,pi))
Graphics object consisting of 1 graphics primitive
implicit_plot(f(x,y)==0,(x,-pi,pi),(y,-pi,pi))
A density plot is like a contour plot, but without discrete levels.
sage: density_plot(f, (x, -2, 2), (y, -2, 2))
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> density_plot(f, (x, -Integer(2), Integer(2)), (y, -Integer(2), Integer(2)))
Graphics object consisting of 1 graphics primitive
density_plot(f, (x, -2, 2), (y, -2, 2))
Sometimes contour plots can be a little misleading (which makes for a great classroom discussion about the problems of ignorantly relying on technology). Here we combine a density plot and contour plot to show even better what is happening with the function.
sage: density_plot(f,(x,-2,2),(y,-2,2))+contour_plot(f,(x,-2,2),(y,-2,2),fill=False,labels=True,label_inline=True,cmap='jet')
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> density_plot(f,(x,-Integer(2),Integer(2)),(y,-Integer(2),Integer(2)))+contour_plot(f,(x,-Integer(2),Integer(2)),(y,-Integer(2),Integer(2)),fill=False,labels=True,label_inline=True,cmap='jet')
Graphics object consisting of 2 graphics primitives
density_plot(f,(x,-2,2),(y,-2,2))+contour_plot(f,(x,-2,2),(y,-2,2),fill=False,labels=True,label_inline=True,cmap='jet')
It can be worth getting familiar with the various options for different plots, especially if you will be doing a lot of them in a given worksheet or pedagogical situation.
Here are the options for contour plots.
They are given as an “attribute” - no parentheses - of the
contour_plot
object.They are given as a dictionary (see the programming tutorial).
sage: contour_plot.options
{'aspect_ratio': 1,
'axes': False,
'colorbar': False,
'contours': None,
'fill': True,
'frame': True,
'labels': False,
'legend_label': None,
'linestyles': None,
'linewidths': None,
'plot_points': 100,
'region': None}
>>> from sage.all import *
>>> contour_plot.options
{'aspect_ratio': 1,
'axes': False,
'colorbar': False,
'contours': None,
'fill': True,
'frame': True,
'labels': False,
'legend_label': None,
'linestyles': None,
'linewidths': None,
'plot_points': 100,
'region': None}
contour_plot.options
Let’s change it so that all future contour plots don’t have the fill. That’s how some of us might use them in a class. We’ll also check that the change happened.
sage: contour_plot.options["fill"]=False
sage: contour_plot.options
{'aspect_ratio': 1,
'axes': False,
'colorbar': False,
'contours': None,
'fill': False,
'frame': True,
'labels': False,
'legend_label': None,
'linestyles': None,
'linewidths': None,
'plot_points': 100,
'region': None}
>>> from sage.all import *
>>> contour_plot.options["fill"]=False
>>> contour_plot.options
{'aspect_ratio': 1,
'axes': False,
'colorbar': False,
'contours': None,
'fill': False,
'frame': True,
'labels': False,
'legend_label': None,
'linestyles': None,
'linewidths': None,
'plot_points': 100,
'region': None}
contour_plot.options["fill"]=False contour_plot.options
And it works!
sage: contour_plot(f,(x,-2,2),(y,-2,2))
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> contour_plot(f,(x,-Integer(2),Integer(2)),(y,-Integer(2),Integer(2)))
Graphics object consisting of 1 graphics primitive
contour_plot(f,(x,-2,2),(y,-2,2))
We can always access the default options, of course, to remind us.
sage: contour_plot.defaults()
{'aspect_ratio': 1,
'axes': False,
'colorbar': False,
'contours': None,
'fill': True,
'frame': True,
'labels': False,
'legend_label': None,
'linestyles': None,
'linewidths': None,
'plot_points': 100,
'region': None}
>>> from sage.all import *
>>> contour_plot.defaults()
{'aspect_ratio': 1,
'axes': False,
'colorbar': False,
'contours': None,
'fill': True,
'frame': True,
'labels': False,
'legend_label': None,
'linestyles': None,
'linewidths': None,
'plot_points': 100,
'region': None}
contour_plot.defaults()
Vector fields¶
The syntax for vector fields is very similar to other multivariate constructions. Notice that the arrows are scaled appropriately, and colored by length in the 3D case.
sage: var('x,y')
(x, y)
sage: plot_vector_field((-y+x,y*x),(x,-3,3),(y,-3,3))
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> var('x,y')
(x, y)
>>> plot_vector_field((-y+x,y*x),(x,-Integer(3),Integer(3)),(y,-Integer(3),Integer(3)))
Graphics object consisting of 1 graphics primitive
var('x,y') plot_vector_field((-y+x,y*x),(x,-3,3),(y,-3,3))
sage: var('x,y,z')
(x, y, z)
sage: plot_vector_field3d((-y,-z,x), (x,-3,3),(y,-3,3),(z,-3,3))
Graphics3d Object
>>> from sage.all import *
>>> var('x,y,z')
(x, y, z)
>>> plot_vector_field3d((-y,-z,x), (x,-Integer(3),Integer(3)),(y,-Integer(3),Integer(3)),(z,-Integer(3),Integer(3)))
Graphics3d Object
var('x,y,z') plot_vector_field3d((-y,-z,x), (x,-3,3),(y,-3,3),(z,-3,3))
>>> from sage.all import *
>>> var('x,y,z')
(x, y, z)
>>> plot_vector_field3d((-y,-z,x), (x,-Integer(3),Integer(3)),(y,-Integer(3),Integer(3)),(z,-Integer(3),Integer(3)))
Graphics3d Object
var('x,y,z') plot_vector_field3d((-y,-z,x), (x,-3,3),(y,-3,3),(z,-3,3))
3d vector field plots are ideally viewed with 3d glasses (right-click on the plot and select “Style” and “Stereographic”)
Complex Plots¶
We can plot functions of complex variables, where the magnitude is indicated by the brightness (black is zero magnitude) and the argument is indicated by the hue (red is a positive real number).
sage: f(z) = exp(z) #z^5 + z - 1 + 1/z
sage: complex_plot(f, (-5,5),(-5,5))
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> __tmp__=var("z"); f = symbolic_expression(exp(z) ).function(z)#z^5 + z - 1 + 1/z
>>> complex_plot(f, (-Integer(5),Integer(5)),(-Integer(5),Integer(5)))
Graphics object consisting of 1 graphics primitive
f(z) = exp(z) #z^5 + z - 1 + 1/z complex_plot(f, (-5,5),(-5,5))
Region plots¶
These plot where an expression is true, and are useful for plotting inequalities.
sage: region_plot(cos(x^2+y^2) <= 0, (x, -3, 3), (y, -3, 3),aspect_ratio=1)
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> region_plot(cos(x**Integer(2)+y**Integer(2)) <= Integer(0), (x, -Integer(3), Integer(3)), (y, -Integer(3), Integer(3)),aspect_ratio=Integer(1))
Graphics object consisting of 1 graphics primitive
region_plot(cos(x^2+y^2) <= 0, (x, -3, 3), (y, -3, 3),aspect_ratio=1)
We can get fancier options as well.
sage: region_plot(sin(x)*sin(y) >= 1/4, (x,-10,10), (y,-10,10), incol='yellow', bordercol='black', borderstyle='dashed', plot_points=250,aspect_ratio=1)
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> region_plot(sin(x)*sin(y) >= Integer(1)/Integer(4), (x,-Integer(10),Integer(10)), (y,-Integer(10),Integer(10)), incol='yellow', bordercol='black', borderstyle='dashed', plot_points=Integer(250),aspect_ratio=Integer(1))
Graphics object consisting of 2 graphics primitives
region_plot(sin(x)*sin(y) >= 1/4, (x,-10,10), (y,-10,10), incol='yellow', bordercol='black', borderstyle='dashed', plot_points=250,aspect_ratio=1)
Remember, what command would give full information about the syntax, options, and examples?
Miscellaneous Plot Information¶
Builtin Graphics Objects¶
Sage includes a variety of built-in graphics objects. These are
particularly useful for adding to one’s plot certain objects which are
difficult to describe with equations, but which are basic geometric
objects nonetheless. In this section we will try to demonstrate the
syntax of some of the most useful of them; for most of them the
contextual (remember, append ?
) help will give more details.
Points¶
To make one point, a coordinate pair suffices.
sage: point((3,5))
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> point((Integer(3),Integer(5)))
Graphics object consisting of 1 graphics primitive
point((3,5))
It doesn’t matter how multiple point are generated; they must go in as input via a list (square brackets). Here, we demonstrate the hard (but naive) and easy (but a little more sophisticated) way to do this.
sage: f(x)=x^2
sage: points([(0,f(0)), (1,f(1)), (2,f(2)), (3,f(3)), (4,f(4))])
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> __tmp__=var("x"); f = symbolic_expression(x**Integer(2)).function(x)
>>> points([(Integer(0),f(Integer(0))), (Integer(1),f(Integer(1))), (Integer(2),f(Integer(2))), (Integer(3),f(Integer(3))), (Integer(4),f(Integer(4)))])
Graphics object consisting of 1 graphics primitive
f(x)=x^2 points([(0,f(0)), (1,f(1)), (2,f(2)), (3,f(3)), (4,f(4))])
sage: points([(x,f(x)) for x in range(5)])
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> points([(x,f(x)) for x in range(Integer(5))])
Graphics object consisting of 1 graphics primitive
points([(x,f(x)) for x in range(5)])
>>> from sage.all import *
>>> points([(x,f(x)) for x in range(Integer(5))])
Graphics object consisting of 1 graphics primitive
points([(x,f(x)) for x in range(5)])
Sage tries to tell how many dimensions you are working in automatically.
sage: f(x,y)=x^2-y^2
sage: points([(x,y,f(x,y)) for x in range(5) for y in range(5)])
Graphics3d Object
>>> from sage.all import *
>>> __tmp__=var("x,y"); f = symbolic_expression(x**Integer(2)-y**Integer(2)).function(x,y)
>>> points([(x,y,f(x,y)) for x in range(Integer(5)) for y in range(Integer(5))])
Graphics3d Object
f(x,y)=x^2-y^2 points([(x,y,f(x,y)) for x in range(5) for y in range(5)])
Lines¶
The syntax for lines is the same as that for points, but you get… well, you get connecting lines too!
sage: f(x)=x^2
sage: line([(x,f(x)) for x in range(5)])
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> __tmp__=var("x"); f = symbolic_expression(x**Integer(2)).function(x)
>>> line([(x,f(x)) for x in range(Integer(5))])
Graphics object consisting of 1 graphics primitive
f(x)=x^2 line([(x,f(x)) for x in range(5)])
Balls¶
Sage has disks and spheres of various types available. Generally the center and radius are all that is needed, but other options are possible.
sage: circle((0,1),1,aspect_ratio=1)
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> circle((Integer(0),Integer(1)),Integer(1),aspect_ratio=Integer(1))
Graphics object consisting of 1 graphics primitive
circle((0,1),1,aspect_ratio=1)
sage: disk((0,0), 1, (pi, 3*pi/2), color='yellow',aspect_ratio=1)
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> disk((Integer(0),Integer(0)), Integer(1), (pi, Integer(3)*pi/Integer(2)), color='yellow',aspect_ratio=Integer(1))
Graphics object consisting of 1 graphics primitive
disk((0,0), 1, (pi, 3*pi/2), color='yellow',aspect_ratio=1)
>>> from sage.all import *
>>> disk((Integer(0),Integer(0)), Integer(1), (pi, Integer(3)*pi/Integer(2)), color='yellow',aspect_ratio=Integer(1))
Graphics object consisting of 1 graphics primitive
disk((0,0), 1, (pi, 3*pi/2), color='yellow',aspect_ratio=1)
There are also ellipses and various arcs; see the full plot documentation.
Arrows¶
sage: arrow((0,0), (1,1))
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> arrow((Integer(0),Integer(0)), (Integer(1),Integer(1)))
Graphics object consisting of 1 graphics primitive
arrow((0,0), (1,1))
Polygons¶
Polygons will try to complete themselves and fill in the interior; otherwise the syntax is fairly self-evident.
sage: polygon([[0,0],[1,1],[1,2]])
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> polygon([[Integer(0),Integer(0)],[Integer(1),Integer(1)],[Integer(1),Integer(2)]])
Graphics object consisting of 1 graphics primitive
polygon([[0,0],[1,1],[1,2]])
Text¶
In 2d, one can typeset mathematics using the text
command. This can
be used to fine-tune certain types of labels. Unfortunately, in 3D the
text is just text.
sage: text(r'$\int_0^2 x^2\, dx$', (0.5,2))+plot(x^2,(x,0,2),fill=True)
Graphics object consisting of 3 graphics primitives
>>> from sage.all import *
>>> text(r'$\int_0^2 x^2\, dx$', (RealNumber('0.5'),Integer(2)))+plot(x**Integer(2),(x,Integer(0),Integer(2)),fill=True)
Graphics object consisting of 3 graphics primitives
text(r'$\int_0^2 x^2\, dx$', (0.5,2))+plot(x^2,(x,0,2),fill=True)
Saving Plots¶
We can save 2d plots to many different formats. Sage can determine the format based on the filename for the image.
sage: p=plot(x^2,(x,-1,1))
sage: p
Graphics object consisting of 1 graphics primitive
>>> from sage.all import *
>>> p=plot(x**Integer(2),(x,-Integer(1),Integer(1)))
>>> p
Graphics object consisting of 1 graphics primitive
p=plot(x^2,(x,-1,1)) p
For testing purposes, we use the Sage standard temporary filename;
however, you could use any string for a name that you wanted, like
"my_plot.png"
.
sage: name = tmp_filename() # this is a string
sage: png_savename = name+'.png'
sage: p.save(png_savename)
>>> from sage.all import *
>>> name = tmp_filename() # this is a string
>>> png_savename = name+'.png'
>>> p.save(png_savename)
name = tmp_filename() # this is a string png_savename = name+'.png' p.save(png_savename)
In the notebook, these are usually ready for downloading in little links by the cells.
sage: pdf_savename = name+'.pdf'
sage: p.save(pdf_savename)
>>> from sage.all import *
>>> pdf_savename = name+'.pdf'
>>> p.save(pdf_savename)
pdf_savename = name+'.pdf' p.save(pdf_savename)
Notably, we can export in formats ready for inclusion in web pages.
sage: svg_savename = name+'.svg'
sage: p.save(svg_savename)
>>> from sage.all import *
>>> svg_savename = name+'.svg'
>>> p.save(svg_savename)
svg_savename = name+'.svg' p.save(svg_savename)