SageMath dispone de una amplia panoplia de funciones para crear gráficos en dos dimensiones. La relación completa se halla detallada en la documentación sobre gráficos 2D de SageMath, donde se proporcionan la sintaxis de cada función y multitud de ejemplos de uso. En esta guía nos centraremos en sólo una parte de los recursos que ofrece SageMath.
En un gráfico pueden aparecer figuras como puntos, líneas, polígonos, etc., así como distintos tipos de curvas o regiones planas. Para combinar dos de estos objetos, basta con «sumarlos»: si p
y q
representan dos objetos gráficos, entonces p + q
es el gráfico que une ambos. Por ejemplo, en la siguiente celda se definen tres círculos que luego son mostrados conjuntamente:
centros = [(cos(t), sin(t)) for t in [0,2*pi/3,4*pi/3]]
c1 = circle(centros[0], 1.5, color="red", alpha=0.9, fill=True, axes=False)
c2 = circle(centros[1], 1.5, color="green", alpha=0.7, fill=True)
c3 = circle(centros[2], 1.5, color="blue", alpha=0.5, fill=True)
c1 + c2 + c3 # «sumamos» c1, c2 y c3 para combinarlos
Si los objetos dependen de un índice o parámetro, se puede sumarlos con la función sum
:
flechas = sum(arrow((0,0),(cos(a),sin(a)), color="darkgreen") for a in srange(0,2*pi,pi/6))
flechas.show(aspect_ratio=1, axes=False, frame=True, gridlines=True)
El ejemplo anterior usa el método show
para terminar de perfilar el aspecto del gráfico, con las opciones aspect_ratio
(número positivo que regula la proporción entre la altura y la anchura del gráfico), axes
(controla si se dibujan o no los ejes de coordenadas), frame
(dibujo o no de un marco) y gridlines
(dibujo de una cuadrícula). La lista completa de opciones admisibles se puede obtener evaluando la expresión Graphics.SHOW_OPTIONS
. El método show
también puede actuar como función: hubiera sido correcto escribir show(flechas, aspect_ratio=1, axes=False, frame=True)
.
Otro modo de modificar un objeto gráfico, o de explorar sus características, consiste en utilizar métodos. Si se teclea Graphics.
y se pulsa Tab, se abre una ventana con una relación de los métodos aplicables. Alternativamente, la orden dir(Graphics)
proporciona una lista todavía más exhaustiva. La información particular sobre cada método se obtiene con Graphics.<método>?
, sustituyendo <método>
por el método concreto que sea de interés.
Repetimos el último gráfico empleando diversos métodos para cambiar su aspecto:
flechas = sum(arrow((0,0),(cos(a),sin(a)), color="darkgreen") for a in srange(0,2*pi,pi/6))
flechas.set_aspect_ratio(1)
flechas.axes_color("darkred") # color del marco
flechas.tick_label_color("darkblue") # color de los números
flechas.axes_labels(["Eje Ox", "Eje Oy"]) # etiquetas en los ejes
flechas.axes_label_color("brown") # color de las etiquetas
flechas.show(axes=False, frame=True, gridlines=True)
Para guardar una imagen en un fichero se emplea el método save
, que tiene un argumento, el nombre del fichero, y las mismas opciones que show
. Por ejemplo, con la orden
flechas.save("flechas.pdf", axes=False, frame=True, gridlines=True)
se almacenaría el último gráfico en el fichero flechas.pdf.
La mayoría de las primitivas gráficas admiten una o más opciones para fijar el color del objeto correspondiente. El color se puede indicar, en primer lugar, mediante sus coordenadas en el sistema RGB, esto es, mediante una terna $(r,g,b)$ de números reales pertenecientes al intervalo $[0,1]$. Los números $r$, $g$ y $b$ determinan, respectivamente, la proporción de rojo, verde y azul del color considerado. Tal proporción también se puede indicar en la forma hexadecimal #rrggbb, donde cada par de cifras rr, gg y bb oscila entre 00 y ff (i.e., entre 0 y 255 en base decimal). La celda siguiente, un vez evaluada, permite escoger colores de diversas formas y ver la terna RGB equivalente. Se activa el selector de color pulsando sobre el cuadrado pequeño:
@interact
def _(color=color_selector(widget="colorpicker", label="Color")):
poligono = polygon([(0,0),(1,0),(1,1),[0,1]], color=color, edgecolor="black")
rgb = [n(i, digits=5) for i in sage.plot.colors.rgbcolor(color)]
show(poligono, axes=False, frame=False, figsize=3, title="RGB: "+str(rgb))
Otro método de expresar el color consiste en dar el nombre de uno de los colores incluidos en la lista oficial de colores SVG. Mediante la celda siguiente se puede explorar estos colores y ver su equivalencia en el sistema RGB:
@interact
def _(color=selector(sorted(colors), label="Color")):
poligono = polygon([(0,0),(1,0),(1,1),[0,1]], color=color, edgecolor="black")
rgb = [n(i, digits=5) for i in sage.plot.colors.rgbcolor(color)]
show(poligono, axes=False, frame=False, figsize=3, title="RGB: "+str(rgb))
Existen asimismo gamas de colores, útiles, sobre todo, en la representación de curvas de nivel o en gráficos tridimensionales. Nuevamente, la celda siguiente permite explorar las gamas predefinidas:
var("x,y")
gamas=sorted(colormaps)
@interact
def _(cmap=selector(gamas, default="jet", label="Gama", buttons=False)):
show(contour_plot(x^2-y^2, (x,-2,2), (y,-2,2), contours=15,
cmap=cmap, colorbar=True), figsize=5)
La orden sorted(colormaps)
genera una lista ordenada de todas las gamas predefinidas.
Para mayor información sobre el color en SageMath, cabe consultar la documentación correspondiente.
Sagemath proporciona funciones para trazar las siguientes figuras: puntos (point
), segmentos y líneas poligonales (line
), flechas (arrow
), polígonos (polygon
), circunferencias y círculos (circle
), elipses (ellipse
), arcos elípticos (arc
) y sectores circulares (disk
). Además se puede añadir texto con la función text
. Describamos la sintaxis de las funciones más relevantes:
point(punto, opciones) o bien point(lista_puntos, opciones)
line(lista_vértices, opciones)
arrow(pto_inicial, pto_final, opciones)
polygon(lista_vértices, opciones)
circle(centro, radio, opciones)
ellipse(centro, r_1, r_2, ángulo, opciones)
text(texto, posición, opciones)
En los argumentos punto, pto_inicial, pto_final, centro o posición se especifican las coordenadas $(x,y)$ del punto correspondiente, expresadas mediante una lista [x,y]
, una tupla (x,y)
o un vector vector([x,y])
. Los argumentos lista_puntos y lista_vértices son listas de coordenadas. Los argumentos r_1 y r_2 de ellipse
son las longitudes de los semiejes, y ángulo es el ángulo de giro de sus ejes con respecto a la horizontal (por omisión, su valor es $0$; se expresa en radianes); para circle
, radio es, obviamente, el radio del círculo.
Todas las funciones cuentan con las opciones color
(color de la figura), legend_label
(texto de la leyenda) y legend_color
(color de la leyenda). En el caso de circle
, en vez de color
, se pueden usar las opciones edgecolor
(color del borde) y facecolor
(color del interior); en cambio, para la función polygon
, la opción color
fija el color de todo el polígono, salvo que se especifique el del borde con edgecolor
. Con fill=True
se rellena el interior de círculos y polígonos; con fill=False
, sólo se traza su borde.
La opción alpha
es un número entre $0$ y $1$ que fija el grado de opacidad de la figura ($0=$ transparente, $1=$ opaca). No es opción válida de arrow
.
Para line
, arrow
, circle
y polygon
, el grosor de las líneas se indica con thickness
; el estilo, con linestyle
, que puede tomar los valores solid
, dashed
, dashdot
, dotted
o ""
. En el caso de line
, se pueden marcar los vértices de la línea poligonal trazada haciendo uso de las opciones marker
, markersize
, markeredgecolor
, markerfacecolor
y markeredgewith
. La primera opción, marker
, controla la forma del punto. Admite muchos valores, como None
, ,
(píxel), .
(punto), _
(línea horizontal), |
(línea vertical), o
(círculo), p
(pentágono), s
(cuadrado), x
, +
, *
, D
y d
(diamantes), H
y h
(hexágonos), etc. La función point
también admite la opción marker
, pero, en este caso, el tamaño del punto se regula con size
.
La función arrow
tiene algunas opciones propias: arrowsize
(tamaño de la punta de la flecha), width
(ancho del astil), head
(en qué extremo situar una punta: 0
, 1
o 2
, para ponerla al principio, al final o en ambos extemos) y arrowshorten
(para acortar la longitud de la flecha).
La función text
cuenta también con las opciones fontstyle
(valores normal
, italic
, oblique
), fontweight
(valores ultralight
, light
, normal
, regular
, book
, medium
, roman
, semibold
, demibold
, demi
, bold
, heavy
, extra bold
, black
), background_color
(color del fondo sobre el que se escribe el texto), rotation
(ángulo de giro del texto en grados sexagesimales), vertical_alignment
(alineamiento vertical del texto, que puede ser top
, center
, bottom
) y horizontal_alignment
(alineamiento horizontal; posibles valores: left
, center
, right
).
En fin, el valor de la opción zorder
es un entero cualquiera (incluso negativo). Cuando dos o más elementos gráficos se solapan, resulta visible aquél que tenga el valor más alto de zorder
.
En las celdas siguientes se ejemplifican muchas de las opciones mencionadas:
# Representación de un triángulo, su círculo circunscrito y su circuncentro.
# Para facilitar el dibujo, los vértices A, B y C del triángulo pertenecen
# a la circunferencia x^2 + y^2 = 16. El circuncentro es (0,0).
# Coordenadas de los vértices:
A, B, C = vector((-3,-sqrt(7))), vector((-1,sqrt(15))), vector((4,0))
# Triángulo, circunferencia circunscrita y circuncentro
triangulo = polygon([A,B,C], color="lightgreen", edgecolor="green", zorder=0)
circunferencia = circle((0,0), 4, thickness=2, fill=True,
edgecolor="darkblue", facecolor="lightcyan", zorder=-1)
circuncentro = point((0,0), color="red", marker="o", size=30, zorder=10)
# Mediatrices de los lados
pmAB = (A+B)/2 # punto medio del lado AB
mAB = line([-2.2*pmAB,2.2*pmAB], linestyle="dashed", color="dimgray")
pmAC = (A+C)/2 # punto medio del lado AC
mAC = line([-3.2*pmAC,3.2*pmAC], linestyle="dashed", color="dimgray")
pmBC = (B+C)/2 # punto medio del lado BC
mBC = line([-1.9*pmBC,1.9*pmBC], linestyle="dashed", color="dimgray")
# Combinamos todo
todo = triangulo + circunferencia + circuncentro + mAB + mAC + mBC
# Añadimos texto
todo += text("A", A, horizontal_alignment="right",vertical_alignment="top", color="black")
todo += text("B", B, vertical_alignment="bottom", color="black")
todo += text("C", C, horizontal_alignment="left", color="black")
todo += text("circuncentro", (-0.5,-3.05), horizontal_alignment="center", color="black")
todo += arrow((-0.5,-3),(0,0), arrowshorten=8, arrowsize=3)
# Dibujamos
todo.show(axes=False)
# Representación de las funciones coseno y seno
# mediante dos líneas poligonales
p1 = [(t, cos(t)) for t in srange(-pi,4*pi,pi/8)]
lin1 = line(p1, color="darkgreen", thickness=2, marker="s",
markeredgecolor="gray", markerfacecolor="lightgreen",
legend_label="cos", zorder=10)
p2 = [(t, sin(t)) for t in srange(-pi,4*pi,pi/8)]
lin2 = line(p2, color="darkblue", thickness=2, marker="o",
markeredgecolor="gray",markerfacecolor="lightskyblue",
legend_label="sen", zorder=10)
lin = lin1 + lin2
lin.set_axes_range(-9*pi/8, 4*pi, -1.1, 1.1)
op_leyenda = dict(numpoints=2, loc=0, handlelength=2, labelspacing=0.4,
back_color=(0.95,0.95,0.95), fancybox=True)
lin.show(frame=True, legend_options=op_leyenda)
# Dibujo de una cara
# Cabeza, boca y nariz
cara = circle((0,-1), 10, fill=True, facecolor="lightcyan",
edgecolor="gray", thickness=2, zorder = -1)
cara += arc((0,-2.5), 6, sector=(3*pi/2-3*pi/10,3*pi/2+3*pi/10),
thickness=10, color="firebrick")
cara += disk((0,-2.5), 4, (3*pi/2-pi/6,3*pi/2+pi/6), color="orange", thickness=4)
# Ojos y pestañas
for i in [-4.5,4.5]:
cara += circle((i,0), 4, fill=True, facecolor="lightgray",
edgecolor="gray", thickness=2) # párpados
cara += ellipse((i,0), 4, 3, fill=True, facecolor="ghostwhite",
edgecolor="gray") # globo ocular
cara += circle((i,0), 3, fill=True, color="green") # iris
cara += circle((i,0), 1, fill=True, color="black") # pupila
cara += arc((i,1), 4, sector=(pi/2-pi/4,pi/2+pi/4),
thickness=4, color="black") # pestaña
# Dibujo de la cara
cara.show(axes=False, figsize=5)
Dada una función $f:D\subset\mathbb{R}\to\mathbb{R}$, la representación de la curva $y=f(x)$ en un intervalo $[a,b]$ se realiza mediante la función plot
, que se emplea de la forma siguiente:
plot(fun, rango_x, opciones)
donde:
plot(x*cos(x), (x, -pi, 5*pi)) f1(x) = x*cos(x) def f2(x): return x*cos(x)
plot(f1, (-pi, 5*pi)) plot(f2, (x, -pi, 5*pi))
Al objeto de representar varias curvas simultáneamente, el argumento fun puede ser asimismo una lista de funciones. No obstante, es posible trazar cada curva con una función plot
y sumar luego los gráficos resultantes. Ambas alternativas se ejemplifican en la celda siguiente:
op_leyenda = dict(loc=0, handlelength=2.5, labelspacing=0.3, fancybox=True)
# Primera alternativa: trazado de dos curvas con una sola orden plot
plot([4*sin(x),x*cos(x)], (x,-2*pi,2*pi), color=["red","blue"],
linestyle=["solid","dashed"], thickness=2, title="Primera alternativa",
legend_label=[r"$4\,\mathrm{sen}\,x$",r"$x\,\cos\,x$"]).show(legend_options=op_leyenda)
# Segunda alternativa: cada curva se traza con su propia orden plot
p1 = plot(4*sin(x), (x,-2*pi,2*pi), color="red", thickness=2,
legend_label=r"$4\,\mathrm{sen}\,x$")
p2 = plot(x*cos(x), (x,-2*pi,2*pi), color="blue", linestyle="dashed", thickness=2,
legend_label=r"$x\,\cos\,x$")
show(p1+p2, title="Segunda alternativa", legend_options=op_leyenda) # se «suman» p1 y p2 para combinarlos
La orden plot?
o la documentación detallan las múltiples opciones de la función plot
. Algunas, como thickness
, linestyle
, color
o legend_label
, usadas en la última celda, son idénticas a las de la función line
. Mencionemos algunas otras.
La opción plot_points
señala el número mínimo de puntos que se han de utilizar para trazar el gráfico; SageMath añade más puntos donde sea necesario para refinar el dibujo:
p1 = plot(cos(x), (x,-pi,4*pi), plot_points=10, color="darkgreen", thickness=2,
marker="s", markersize=5, markeredgecolor="gray",
markerfacecolor="lightgreen", legend_label="cos")
p2 = plot(sin(x), (x,-pi,4*pi), plot_points=10, color="darkblue", thickness=2,
marker="o", markersize=5, markeredgecolor="gray",
markerfacecolor="lightskyblue", legend_label="sen")
p = p1 + p2
p.set_axes_range(-9*pi/8, 4*pi, -1.1, 1.1)
op_leyenda = dict(numpoints=2, loc=0, handlelength=2, labelspacing=0.4,
back_color=(0.95,0.95,0.95), fancybox=True)
show(p, frame=True, legend_options=op_leyenda)
Las opciones exclude
y detect_poles
ayudan a tratar los puntos de discontinuidad de la función. Con la primera, se indican, mediante una lista o una ecuación de una sola variable, los puntos en los que no se ha de evaluar la función. La opción detect_poles
, por su parte, permite localizar y, en su caso, trazar asíntotas verticales. Sus posibles valores son True
, False
y "show"
. Las opciones ymin
e ymax
acotan inferior y superiormente qué parte del gráfico se muestra. Las siguientes celdas ilustran estas opciones, así como la función graphics_array
, que sirve para presentar simultáneamente una matriz de gráficos:
p1 = plot(sin(floor(x)), (x,-6,6), title="Sin exclusiones")
p2 = plot(sin(floor(x)), (x,-6,6), exclude=[-6,-5..6], title="Exclusión de los puntos de discontinuidad")
graphics_array([p1,p2]).show(figsize=[6,3], frame=True, axes=False, gridlines=True,
ticks=[[-6,-4..6],[-1,-1/2..1]])
p1 = plot(tan(pi*x), (x,-2,2), detect_poles=False, ymin=-5, ymax=5, title="detect_poles=False")
p2 = plot(tan(pi*x), (x,-2,2), detect_poles=True, ymin=-5, ymax=5, title="detect_poles=True")
p3 = plot(tan(pi*x), (x,-2,2), detect_poles="show", ymin=-5, ymax=5, title='detect_poles="show"')
graphics_array([p1,p2,p3]).show(aspect_ratio=1/3, figsize=8)
La opción scale
controla la escala (lineal o logarítmica) que se ha de usar en cada eje. La celda siguiente compara una representación de la función $f(x)=10^{x-2}$ usando primero una escala lineal en ambos ejes (es la opción por omisión) y luego una escala logarítmica en el eje de ordenadas:
p1 = plot(10^(x-2), (x,0,4)) # escala lineal en Ox y Oy
p2 = plot(10^(x-2), (x,0,4), scale="semilogy") # escala lineal en Ox y logarítmica en Oy
graphics_array([p1,p2]).show(figsize=[6,3], frame=True, gridlines=True)
Las opciones fill
, fillcolor
y fillalpha
controlan si se rellena, y de qué modo, una región limitada, en parte, por la curva considerada. La variedad de posibilidades es muy amplia. Ilustramos sólo algunas:
p1 = plot(x*cos(x), (x,-2*pi,3*pi), color="red", fill=True, fillcolor="lightgreen", fillalpha=0.25)
p2 = plot(x*cos(x), (x,-2*pi,3*pi), color="red", fill="min", fillcolor="lightgreen", fillalpha=0.5)
p3 = plot(x*cos(x), (x,-2*pi,3*pi), color="red", fill="max", fillcolor="lightgreen", fillalpha=1)
p4 = plot([x*cos(x),sin(x)], (x,-2*pi,3*pi), color=["red","darkgreen"],
fill={0:[1]}, fillcolor="lightgreen")
p = graphics_array([[p1,p2],[p3,p4]])
p.show(figsize=8,frame=True, axes=False, gridlines="minors",
ticks=[[-2*pi,-pi..3*pi],None], tick_formatter=[pi,None])
Las figuras generadas con plot
se pueden combinar con otros elementos gráficos, como líneas, flechas, puntos, círculos, polígonos o texto. La celda siguiente representa la función
$$
f(x)=\frac{x(x^2-9x+8)}{x^2-1}.
$$
Se añaden las dos asíntotas que tiene esta función y texto que las identifica:
f(x) = x*(x^2-9*x+8)/(x^2-1)
x1, x2 = -10, 10
y1, y2 = -50, 30
# Grafo de f
p = plot(f(x), (x,x1,x2), color="brown", exclude=[-1,1], ymin=y1, ymax=y2, thickness=2,
legend_label="$y=f(x)$", legend_color="darkblue")
p.set_legend_options(font_size="large", handlelength=2)
# Añadimos las asíntotas
p += line([(x1,x1-9),(x2,x2-9)], linestyle="dashed", color="darkgreen")
p += line([(-1,y1),(-1,y2)], linestyle="dashed", color="darkgreen")
# Y texto con las ecuaciones de las asíntotas
p += text("$y=x-9$", (8,-5), color="darkblue", fontsize="large")
p += text("$x=1$", (-2,25), color="darkblue", fontsize="large")
# Finalmente se traza la gráfica
p.show(frame=True, gridlines=["minor","major"], aspect_ratio=1/5)
Consideremos una curva dada en forma paramétrica mediante la ecuación $(x,y)=\boldsymbol{\varphi}(t)$, con $\boldsymbol{\varphi}=(\varphi_1,\varphi_2):I\subset\mathbb{R}\to\mathbb{R}^2$. La función parametric_plot
traza un arco de esta curva cuando el parámetro $t$ recorre un intervalo $[a,b]$ del dominio de $\boldsymbol{\varphi}$. La sintaxis de esta orden es:
parametric_plot(fun, rango_t, opciones),
donde:
Las opciones son similares a las de plot
. Damos a continuación algunos ejemplos. Trazamos primero la curva
$$
\left\{
\begin{aligned}
&x=t\cos t, \\
&y=t\,\mathrm{sen}\,t,
\end{aligned}
\right.
\quad t\in[0,8\pi],
$$
llamada espiral de Arquímedes:
var("t")
parametric_plot([t*cos(t), t*sin(t)], (0,8*pi))
Una epicicloide es una curva generada por un punto de una circunferencia de radio $b$ que rueda por el exterior de otra circunferencia de radio $a$. Su parametrización es $$ \renewcommand{\sin}{\operatorname{sen}} \left\{ \begin{aligned} &x = (a + b)\cos t - b\cos((a/b + 1)t), \\ &y = (a + b)\sin t - b\sin((a/b + 1)t). \end{aligned} \right. $$ Representamos el caso $a=10$ y $b=3$:
a, b = 10, 3
phi_1(t) = (a + b)*cos(t) - b*cos((a/b + 1)*t)
phi_2(t) = (a + b)*sin(t) - b*sin((a/b + 1)*t)
parametric_plot((phi_1(t),phi_2(t)), (t,0,6*pi))
Trazamos ahora una rosa de cuatro pétalos, curva cuya expresión explícita en coordenadas polares es $r=\cos2\theta$. Usamos la opción fill
para dar color a la región limitada por esta curva:
# Rosa de cuatro pétalos
var("theta")
def phi(theta):
r = cos(2*theta)
return (r*cos(theta), r*sin(theta))
parametric_plot(phi(theta), (theta,0,2*pi), color="darkgreen", fill=True,
fillcolor="lightgreen", linestyle="dotted", frame=True, axes=False)
Como último ejemplo, representamos una curva de Lissajous:
a, b = 3/4, pi/5
parametric_plot([sin(t), sin(a*t + b)], (t,0,8*pi), color="green",
fill=True, fillcolor="orange", frame=True, axes=False)
Dadas dos funciones $F, G:D\subset\mathbb{R}^2\to\mathbb{R}$, la función implicit_plot
representa la porción de la curva $F(x,y)=G(x,y)$ que se encuentre en un determinado rectángulo $[a_1,b_1]\times[a_2,b_2]$. Esta función admite la siguiente sintaxis:
implicit_plot($F(x,y)$==$G(x,y)$, rango_x, rango_y, opciones)
donde:
Si $G\equiv0$, en el primer argumento se puede escribir simplemente $F(x,y)$, o incluso $F$, en lugar de $F(x,y)$==$0$.
Las opciones de implicit_plot
son análogas a las de la función plot
. En particular, si fill=True
, se rellena la porción del plano que satisface $F(x,y)-G(x,y)<0$ con el color que indique fillcolor
. Pongamos algunos ejemplos. Representamos primero la curva $(x^2+y^2)^2=x^2-y^2$:
var("x,y")
implicit_plot((x^2+y^2)^2==x^2-y^2, (x,-1.2,1.2), (y,-0.5,0.5), plot_points=250,
color="darkgreen", gridlines=True)
Dada la función $F(x,y)= x^3-2x+y^2-1$, trazamos ahora la curva $F(x,y)=0$ con una línea discontinua y marcamos la región del plano en la que tal función es negativa:
F(x,y) = x^3-2*x+y^2-1
implicit_plot(F(x,y), (-4,2), (-4,4), color='darkgreen', linestyle="dashed",
fill=True, fillcolor="lightgreen", frame=True)
Dibujamos finalmente varios elementos de las familias ortogonales de curvas $(x-c)^2+y^2=c^2$ y $x^2+(y-c)^2=c^2$:
var("x,y")
p = sum(implicit_plot((x-c)^2+y^2-c^2, (x,-5,5), (y,-5,5), color="darkgreen") for c in [-2.5,-1.5..2.5])
q = sum(implicit_plot(x^2+(y-c)^2-c^2, (x,-5,5), (y,-5,5), color="darkred") for c in [-2.5,-1.5..2.5])
show(p+q)
Las curvas de nivel de una función $F:D\subset\mathbb{R}^2\to\mathbb{R}$ son las curvas de ecuación $F(x,y)=c$ para cada $c$ perteneciente al recorrido de $F$. En SageMath se trazan con la función contour_plot
, que se usa del siguiente modo:
contour_plot(fun, rango_x, rango_y, opciones),
donde:
Se selecciona automáticamente la relación de valores de $c$ para los que se dibujan las correspondientes curvas $F(x,y)=c$; con la opción contours
se puede cambiar tanto el número de curvas, proporcionando el entero adecuado, como las lista de valores.
Por omisión, se colorean las curvas de nivel y el espacio entre ellas con una gama de grises. Se cambia la gama con la opción cmap
, que puede ser una de las gamas predefinidas (jet
, coolwarm
, terrain
...) o una lista de colores. Con colorbar=True
, se añade una barra con el rango de valores y colores asociados. El espacio entre curvas queda en blanco si fill=False
.
Análogamente, si labels=True
, se anota en cada curva el valor de $c$ asociado. El formato de este número se controla con label_fontsize
, label_colors
, label_inline
, label_inline_spacing
y label_fmt
.
La opción plot_points
indica el número de puntos en los que se evalúa la función para trazar las curvas. Las opciones linewidths
y linestyles
regulan el aspecto de las curvas; se les puede asignar un único valor, que se emplea para todas las curvas, o una lista de valores, que se aplica entonces cíclicamente.
En la celda siguiente se muestran las curvas de nivel de la función $F(x,y)=x^2-y^2$ de diversos modos. Se puede apreciar así el efecto de muchas de las opciones mencionadas:
var("x,y")
p1 = contour_plot(x^2-y^2, (x,-2,2), (y,-2,2))
p2 = contour_plot(x^2-y^2, (x,-2,2), (y,-2,2), contours=15, cmap=["dimgray"], fill=False,
labels=True, label_inline=True, label_fontsize=7)
p3 = contour_plot(x^2-y^2, (x,-2,2), (y,-2,2), contours=15, cmap="coolwarm", colorbar=True)
p4 = contour_plot(x^2-y^2, (x,-2,2), (y,-2,2), contours=15, cmap="coolwarm", colorbar=True,
fill=False, linewidths=3, linestyles=["solid","dashed"],
labels=True, label_fmt="%1.1f", label_inline=True, label_inline_space=4,
label_fontsize=7, label_colors="black")
p5 = contour_plot(x^2-y^2, (x,-2,2), (y,-2,2), contours=[-2,0,2],
cmap=["darkblue","blue","gray","red","darkred"],
labels=True, label_fmt={-2:"frío", 0:"templado", 2:"caliente"},
label_fontsize=10, label_colors="white")
p6 = contour_plot(x^2-y^2, (x,-2,2), (y,-2,2), contours=[-3..3], cmap="coolwarm", fill=False,
labels=True, label_fmt=lambda x:"$z={:1.0f}$".format(x),
label_inline=True, label_inline_space=2,
label_fontsize=10, label_colors="black")
graphics_array([[p1,p2],[p3,p4],[p5,p6]]).show(figsize=[10,12])
No es posible usar en una misma función contour_plot
dos gamas de colores, una para las curvas y otra para el relleno. No obstante, sí es posible superponer dos gráficos, lo cual puede ser conveniente para remarcar las curvas de nivel. Compárense los gráficos a izquierda y derecha:
var("x,y")
f(x,y) = (2*x+3*y^2) / (x^2+y^2+1)^2
p = contour_plot(f(x,y), (x,-2,2), (y,-2,2), contours=15, plot_points=200,
cmap=["black"], fill=False, linewidths=0.9)
q = contour_plot(f(x,y), (x,-2,2), (y,-2,2), contours=15, plot_points=200,
cmap="jet", colorbar=True)
graphics_array([q,q+p]).show(figsize=[12,5])
Mencionemos, para terminar, la opción region
, que permite restringir el dibujo de las curvas a una zona determinada del plano. El valor que se asigne a esta opción ha de ser una función numérica o booleana. Sólo se trazarán curvas allí donde tal función sea positiva, si es numérica, o tome el valor True
, si es booleana. Por ejemplo, en la siguiente celda, se limita el dibujo de las curvas de nivel de la función $f(x,y)=\sin(x+y)\cos(x-y)$ a la banda comprendida entre las rectas $y=x-4.5$ e $y=x+4.5$:
def f(x,y):
return sin(x+y)*cos(x-y)
contour_plot(f(x,y), (x,-3,3), (y,-3,3), contours=15, cmap="jet", colorbar=True,
region=lambda x,y: x-4.5<y<x+4.5)
Ya hemos visto que la opción fill
de las funciones plot
, parametric_plot
e implicit_plot
permite dar color a diversas regiones planas. Lo mismo sucede con la función contour_plot
. SageMath cuenta, además, con la función region_plot
, cuya sintaxis es
region_plot(desig, rango_x, rango_y, opciones),
donde:
Los colores del interior y del exterior de la región se regulan con las opciones incol
y outcol
; la apariencia del borde se fija con bordercol
, borderstyle
y borderwidth
. Son admisibles más opciones como plot_points
o alpha
.
La celda siguiente muestra cómo representar la región $x^4+y^4-5x^3+3y<1$, con $(x,y)\in[-1,5.2]\times[-3.2,3]$:
var("x,y")
region_plot([x^4+y^4-5*x^3+3*y<1], (x,-1,5.2), (y,-3.2,3),
incol="lightgreen", outcol="lightgray", bordercol="darkgreen", frame=True)
Se representa ahora el conjunto limitado por las circunferencias $x^2+y^2=2x$ y $x^2+y^2=4x$ y las rectas $y=x$ e $y=0$. Cada punto $(x,y)$ de este conjunto satisface las condiciones
$$
2x\leq x^2+y^2 \leq 4x,\quad 0\leq y\leq x.
$$
Las cuatro desigualdades se pasan, en forma de lista, como primer argumento de region_plot
:
var("x,y")
r = region_plot([x^2+y^2>=2*x, x^2+y^2<=4*x, 0<=y, y<=x], (x,0,4), (y,-0.5,2),
plot_points=200, incol="lightgreen", bordercol="darkgreen", borderwidth=3)
p = plot(x, (-0.5,4), linestyle="dashed", color="gray", zorder=0)
q1 = implicit_plot(x^2+y^2==2*x, (x,0,4), (y,0,2), color="gray", linestyle="dashed")
q2 = implicit_plot(x^2+y^2==4*x, (x,0,4), (y,0,2), color="gray", linestyle="dashed")
show(p+q1+q2+r, frame=False, ymin=-0.5, ymax=2.5, aspect_ratio=1)
Se procede análogamente para representar el conjunto $\{ (x,y)\in\mathbb{R}^2 \mid 1\lt x^2-y^2\lt 6,\ x^2+y^2\lt 9\}$:
var("x,y")
region_plot([1<x^2-y^2, x^2-y^2<6, x^2+y^2<9], (x,-3,3), (y,-3,3), plot_points=200,
incol="lightgreen", bordercol="darkgreen", borderstyle="dashed", frame=True)
El primer argumento de region_plot
puede ser también el nombre de una función booleana más o menos compleja. Por ejemplo, la celda siguiente colorea, dentro del rectángulo $[-3,3]\times[-3,3]$, los puntos $(x,y)$ tales que, o bien
$\lvert\sin(x^2-y^2)\rvert\leq 1/2$, o bien $\lvert\cos(x^2+y^2)\rvert\leq 1/2$:
def f(x,y):
return abs(sin(x^2-y^2))<0.5 or abs(cos(x^2+y^2))<0.5
region_plot(f, (x,-3,3), (y,-3,3), plot_points=400,
incol="lightgreen", bordercol="darkgreen", frame=True)
%%html
<style>
h1{text-align: center; color: rgb(185,74,72);}
h2{text-align: center; color: rgb(0,102,0); padding: 0.25em 0;
border: 2px solid rgb(0,191,0); border-width: 2px 0;}
h3{border-bottom: 2px solid rgb(153,153,153);}
h4{color: rgb(58,135,173); font-size: 115%!important;
font-weight: bold!important;}
.text_cell_render{font-family: "Trebuchet MS",Geneva,sans-serif;
font-size: 110%; line-height: 1.5;}
.MathJax_Display{margin: 0.5em 0;}
</style>