Nota
Haga clic aquí para descargar el código de ejemplo completo
Tutorial del artista #
Uso de objetos de artista para renderizar en el lienzo.
Hay tres capas en la API de Matplotlib.
el
matplotlib.backend_bases.FigureCanvas
es el área sobre la que se dibuja la figurael
matplotlib.backend_bases.Renderer
es el objeto que sabe dibujar en elFigureCanvas
y el
matplotlib.artist.Artist
es el objeto que sabe cómo usar un renderizador para pintar sobre el lienzo.
FigureCanvas
y
maneja todos los Renderer
detalles de hablar con juegos de herramientas de interfaz de usuario como wxPython o lenguajes de dibujo como PostScript®, y Artist
maneja todas las construcciones de alto nivel como representar y diseñar la figura, el texto y las líneas. El usuario típico pasará el 95% de su tiempo trabajando con Artists
.
Hay dos tipos de Artists
: primitivas y contenedores. Las primitivas representan los objetos gráficos estándar que queremos pintar en nuestro lienzo:
Line2D
, Rectangle
,
Text
, AxesImage
, etc., y los contenedores son lugares para colocarlos ( Axis
,
Axes
y Figure
). El uso estándar es crear una Figure
instancia, usar el Figure
para crear una o más Axes
instancias
Subplot
y usar los Axes
métodos auxiliares de la instancia para crear las primitivas. En el siguiente ejemplo, creamos una
Figure
instancia usando matplotlib.pyplot.figure()
, que es un método conveniente para instanciar Figure
instancias y conectarlas con su interfaz de usuario o kit de herramientas de dibujo.FigureCanvas
. Como discutiremos a continuación, esto no es necesario: puede trabajar directamente con instancias de PostScript, PDF Gtk+ o wxPython FigureCanvas
, crear una instancia Figures
directamente y conectarlas usted mismo, pero dado que nos estamos enfocando aquí en la
Artist
API, dejaremos pyplot
manejar algunos de esos detalles para nosotros:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(2, 1, 1) # two rows, one column, first plot
Probablemente sea la Axes
clase más importante en la API de Matplotlib y con la que trabajará la mayor parte del tiempo. Esto se debe a que Axes
es el área de trazado en la que van la mayoría de los objetos, y Axes
tiene muchos métodos auxiliares especiales ( plot()
,
text()
,
hist()
,
imshow()
) para crear las primitivas gráficas más comunes ( Line2D
,
Text
,
Rectangle
,
AxesImage
, respectivamente). Estos métodos auxiliares tomarán sus datos (p. ej., numpy
matrices y cadenas) y crearán Artist
instancias primitivas según sea necesario (p. ej. Line2D
), las agregarán a los contenedores relevantes y las dibujarán cuando se solicite. La mayoría de ustedes probablemente esté familiarizado con el Subplot
, que es solo un caso especial de un Axes
que vive en una cuadrícula regular de filas por columnas deSubplot
instancias. Si desea crear un Axes
en una ubicación arbitraria, simplemente use el
add_axes()
método que toma una lista de valores en coordenadas de figuras relativas 0-1:[left, bottom, width, height]
fig2 = plt.figure()
ax2 = fig2.add_axes([0.15, 0.1, 0.7, 0.3])
Siguiendo con nuestro ejemplo:
En este ejemplo, ax
es la Axes
instancia creada por la
fig.add_subplot
llamada anterior (recuerde Subplot
que es solo una subclase de
Axes
) y cuando llama ax.plot
, crea una Line2D
instancia y la agrega a Axes
. En la siguiente sesión interactiva de IPython
, puede ver que la Axes.lines
lista tiene una longitud de uno y contiene la misma línea que devolvió la llamada:line, = ax.plot...
In [101]: ax.lines[0]
Out[101]: <matplotlib.lines.Line2D at 0x19a95710>
In [102]: line
Out[102]: <matplotlib.lines.Line2D at 0x19a95710>
Si realiza llamadas posteriores a ax.plot
(y el estado de espera está "activado", que es el valor predeterminado), se agregarán líneas adicionales a la lista. Puede eliminar una línea más tarde llamando a su remove
método:
The Axes también tiene métodos de ayuda para configurar y decorar el eje x y el eje y, las etiquetas de marca y las etiquetas de los ejes:
xtext = ax.set_xlabel('my xdata') # returns a Text instance
ytext = ax.set_ylabel('my ydata')
Cuando llama ax.set_xlabel
, pasa la información sobre la Text
instancia del XAxis
. Cada Axes
instancia contiene una XAxis
y una
YAxis
instancia, que manejan el diseño y el dibujo de las marcas, las etiquetas de marcas y las etiquetas de los ejes.
Intente crear la figura de abajo.
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
fig.subplots_adjust(top=0.8)
ax1 = fig.add_subplot(211)
ax1.set_ylabel('volts')
ax1.set_title('a sine wave')
t = np.arange(0.0, 1.0, 0.01)
s = np.sin(2*np.pi*t)
line, = ax1.plot(t, s, color='blue', lw=2)
# Fixing random state for reproducibility
np.random.seed(19680801)
ax2 = fig.add_axes([0.15, 0.1, 0.7, 0.3])
n, bins, patches = ax2.hist(np.random.randn(1000), 50,
facecolor='yellow', edgecolor='yellow')
ax2.set_xlabel('time (s)')
plt.show()
Personalizando tus objetos #
Cada elemento de la figura está representado por un Matplotlib
Artist
y cada uno tiene una extensa lista de propiedades para configurar su apariencia. La figura en sí contiene
Rectangle
exactamente el tamaño de la figura, que puede usar para establecer el color de fondo y la transparencia de las figuras. Del mismo modo, cada Axes
cuadro delimitador (el cuadro blanco estándar con bordes negros en el diagrama típico de Matplotlib) tiene una Rectangle
instancia que determina el color, la transparencia y otras propiedades de los ejes. Estas instancias se almacenan como variables miembro Figure.patch
y Axes.patch
("Patch" es un nombre heredado de MATLAB, y es un "parche" 2D de color en la figura, por ejemplo, rectángulos, círculos y polígonos). Cada Matplotlib Artist
tiene las siguientes propiedades
Propiedad |
Descripción |
---|---|
alfa |
La transparencia - un escalar de 0-1 |
animado |
Un booleano que se utiliza para facilitar el dibujo animado. |
hachas |
Los ejes en los que vive el artista, posiblemente ninguno |
clip_box |
El cuadro delimitador que recorta al Artista |
clip_en |
Si el recorte está habilitado |
clip_path |
El camino al que se recorta el artista |
contiene |
Una función de selección para probar si el artista contiene el punto de selección |
figura |
La instancia de la figura en la que vive el artista, posiblemente Ninguna. |
etiqueta |
Una etiqueta de texto (p. ej., para etiquetado automático) |
recogedor |
Un objeto de Python que controla la selección de objetos. |
transformar |
La transformación |
visible |
Un booleano si el artista debe ser dibujado |
orden Z |
Un número que determina el orden de dibujo |
rasterizado |
booleano; Convierte vectores en gráficos de trama (para compresión y transparencia EPS) |
Se accede a cada una de las propiedades con un setter o getter anticuado (sí, sabemos que esto irrita a los pitonistas y planeamos admitir el acceso directo a través de propiedades o rasgos, pero aún no se ha hecho). Por ejemplo, para multiplicar el alfa actual por la mitad:
a = o.get_alpha()
o.set_alpha(0.5*a)
Si desea establecer varias propiedades a la vez, también puede usar el set
método con argumentos de palabras clave. Por ejemplo:
o.set(alpha=0.5, zorder=2)
Si está trabajando de forma interactiva en el shell de python, una forma práctica de inspeccionar las Artist
propiedades es usar la
matplotlib.artist.getp()
función (simplemente
getp()
en pyplot), que enumera las propiedades y sus valores. Esto también funciona para las clases derivadas de Artist
, por ejemplo, Figure
y Rectangle
. Aquí están las Figure
propiedades del rectángulo mencionadas anteriormente:
In [149]: matplotlib.artist.getp(fig.patch)
agg_filter = None
alpha = None
animated = False
antialiased or aa = False
bbox = Bbox(x0=0.0, y0=0.0, x1=1.0, y1=1.0)
capstyle = butt
children = []
clip_box = None
clip_on = True
clip_path = None
contains = None
data_transform = BboxTransformTo( TransformedBbox( Bbox...
edgecolor or ec = (1.0, 1.0, 1.0, 1.0)
extents = Bbox(x0=0.0, y0=0.0, x1=640.0, y1=480.0)
facecolor or fc = (1.0, 1.0, 1.0, 1.0)
figure = Figure(640x480)
fill = True
gid = None
hatch = None
height = 1
in_layout = False
joinstyle = miter
label =
linestyle or ls = solid
linewidth or lw = 0.0
patch_transform = CompositeGenericTransform( BboxTransformTo( ...
path = Path(array([[0., 0.], [1., 0.], [1.,...
path_effects = []
picker = None
rasterized = None
sketch_params = None
snap = None
transform = CompositeGenericTransform( CompositeGenericTra...
transformed_clip_path_and_affine = (None, None)
url = None
verts = [[ 0. 0.] [640. 0.] [640. 480.] [ 0. 480....
visible = True
width = 1
window_extent = Bbox(x0=0.0, y0=0.0, x1=640.0, y1=480.0)
x = 0
xy = (0, 0)
y = 0
zorder = 1
Las cadenas de documentación para todas las clases también contienen las Artist
propiedades, por lo que puede consultar la "ayuda" interactiva o
matplotlib.artist para obtener una lista de propiedades para un objeto determinado.
Contenedores de objetos #
Ahora que sabemos cómo inspeccionar y establecer las propiedades de un objeto dado que queremos configurar, necesitamos saber cómo llegar a ese objeto. Como se mencionó en la introducción, hay dos tipos de objetos: primitivos y contenedores. Las primitivas suelen ser las cosas que desea configurar (la fuente de una Text
instancia, el ancho de un Line2D
), aunque los contenedores también tienen algunas propiedades; por ejemplo,
es un contenedor que contiene muchas de las primitivas en su trama, pero también tiene propiedades como para controlar si el eje x es 'lineal' o 'log'. En esta sección, revisaremos dónde almacenan los diversos objetos contenedores lo que desea obtener.Axes
Artist
xscale
Artists
Figura contenedor #
El contenedor de nivel superior Artist
es el
matplotlib.figure.Figure
y contiene todo lo que se muestra en la figura. El fondo de la figura es un
Rectangle
que se almacena en
Figure.patch
. A medida que agrega subgráficos ( add_subplot()
) y ejes ( add_axes()
) a la figura, estos se agregarán al Figure.axes
. Estos también son devueltos por los métodos que los crean:
In [156]: fig = plt.figure()
In [157]: ax1 = fig.add_subplot(211)
In [158]: ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3])
In [159]: ax1
Out[159]: <AxesSubplot:>
In [160]: print(fig.axes)
[<AxesSubplot:>, <matplotlib.axes._axes.Axes object at 0x7f0768702be0>]
Debido a que la figura mantiene el concepto de los "ejes actuales" (consulte
Figure.gca
y
Figure.sca
) para admitir la máquina de estado pylab/pyplot, no debe insertar ni eliminar ejes directamente de la lista de ejes, sino usar los
métodos add_subplot()
y
add_axes()
para insertar, y el
Axes.remove
método borrar. Sin embargo, puede iterar sobre la lista de ejes o indexarla para obtener acceso a las Axes
instancias que desea personalizar. Aquí hay un ejemplo que enciende todas las cuadrículas de ejes:
for ax in fig.axes:
ax.grid(True)
La figura también tiene sus propios atributos images
, y lines
,
que puede usar para agregar primitivos directamente. Al hacerlo, el sistema de coordenadas predeterminado para el simplemente estará en píxeles (que generalmente no es lo que desea). Si, en cambio, utiliza métodos de nivel de figura para agregar artistas (p. ej., para agregar texto), el sistema de coordenadas predeterminado será "coordenadas de figura", donde (0, 0) es la parte inferior izquierda de la figura y (1, 1 ) es la parte superior derecha de la figura.patches
text
Figure
Figure.text
Al igual que con todos los Artist
s, puede controlar este sistema de coordenadas configurando la propiedad de transformación. Puede usar explícitamente "coordenadas de figura" configurando la Artist
transformación en fig.transFigure
:
import matplotlib.lines as lines
fig = plt.figure()
l1 = lines.Line2D([0, 1], [0, 1], transform=fig.transFigure, figure=fig)
l2 = lines.Line2D([0, 1], [1, 0], transform=fig.transFigure, figure=fig)
fig.lines.extend([l1, l2])
plt.show()
Aquí hay un resumen de los artistas que contiene la figura.
Atributo de figura |
Descripción |
---|---|
hachas |
Una lista de |
parche |
el |
imágenes |
Una lista de |
leyendas |
|
líneas |
Una lista de instancias de Figura |
parches |
Una lista de Figuras |
textos |
Una lista de |
Contenedor de ejes #
El matplotlib.axes.Axes
es el centro del universo de Matplotlib: contiene la gran mayoría de todos los que se Artists
usan en una figura con muchos métodos de ayuda para crearlos y agregarlos
Artists
a sí mismo, así como métodos de ayuda para acceder y personalizar lo Artists
que contiene. Al igual que el
Figure
, contiene a
que es a
para coordenadas cartesianas y a
para coordenadas polares; este parche determina la forma, el fondo y el borde de la región de trazado:Patch
patch
Rectangle
Circle
ax = fig.add_subplot()
rect = ax.patch # a Rectangle instance
rect.set_facecolor('green')
Cuando llama a un método de trazado, por ejemplo, el canónico
plot
y pasa matrices o listas de valores, el método creará una matplotlib.lines.Line2D
instancia, actualizará la línea con todas las Line2D
propiedades pasadas como argumentos de palabras clave, agregará la línea a Axes
y se la devolverá. :
In [213]: x, y = np.random.rand(2, 100)
In [214]: line, = ax.plot(x, y, '-', color='blue', linewidth=2)
plot
devuelve una lista de líneas porque puede pasar múltiples pares x, y para trazar, y estamos desempaquetando el primer elemento de la lista de longitud uno en la variable de línea. La línea ha sido añadida a la
Axes.lines
lista:
In [229]: print(ax.lines)
[<matplotlib.lines.Line2D at 0xd378b0c>]
De manera similar, los métodos que crean parches, como
bar()
crear una lista de rectángulos, agregarán los parches a la Axes.patches
lista:
In [233]: n, bins, rectangles = ax.hist(np.random.randn(1000), 50)
In [234]: rectangles
Out[234]: <BarContainer object of 50 artists>
In [235]: print(len(ax.patches))
Out[235]: 50
No debe agregar objetos directamente a las
listas Axes.lines
o , porque necesita hacer algunas cosas cuando crea y agrega un objeto:Axes.patches
Axes
Establece la propiedad
figure
yaxes
delArtist
;Establece la
Axes
transformación predeterminada (a menos que ya se haya establecido una);Inspecciona los datos contenidos en el
Artist
para actualizar las estructuras de datos que controlan el escalado automático, de modo que los límites de vista se puedan ajustar para contener los datos trazados.
No obstante, puede crear objetos usted mismo y agregarlos directamente al
Axes
uso de métodos auxiliares como add_line
y
add_patch
. Aquí hay una sesión interactiva comentada que ilustra lo que está pasando:
In [262]: fig, ax = plt.subplots()
# create a rectangle instance
In [263]: rect = matplotlib.patches.Rectangle((1, 1), width=5, height=12)
# by default the axes instance is None
In [264]: print(rect.axes)
None
# and the transformation instance is set to the "identity transform"
In [265]: print(rect.get_data_transform())
IdentityTransform()
# now we add the Rectangle to the Axes
In [266]: ax.add_patch(rect)
# and notice that the ax.add_patch method has set the axes
# instance
In [267]: print(rect.axes)
Axes(0.125,0.1;0.775x0.8)
# and the transformation has been set too
In [268]: print(rect.get_data_transform())
CompositeGenericTransform(
TransformWrapper(
BlendedAffine2D(
IdentityTransform(),
IdentityTransform())),
CompositeGenericTransform(
BboxTransformFrom(
TransformedBbox(
Bbox(x0=0.0, y0=0.0, x1=1.0, y1=1.0),
TransformWrapper(
BlendedAffine2D(
IdentityTransform(),
IdentityTransform())))),
BboxTransformTo(
TransformedBbox(
Bbox(x0=0.125, y0=0.10999999999999999, x1=0.9, y1=0.88),
BboxTransformTo(
TransformedBbox(
Bbox(x0=0.0, y0=0.0, x1=6.4, y1=4.8),
Affine2D(
[[100. 0. 0.]
[ 0. 100. 0.]
[ 0. 0. 1.]])))))))
# the default axes transformation is ax.transData
In [269]: print(ax.transData)
CompositeGenericTransform(
TransformWrapper(
BlendedAffine2D(
IdentityTransform(),
IdentityTransform())),
CompositeGenericTransform(
BboxTransformFrom(
TransformedBbox(
Bbox(x0=0.0, y0=0.0, x1=1.0, y1=1.0),
TransformWrapper(
BlendedAffine2D(
IdentityTransform(),
IdentityTransform())))),
BboxTransformTo(
TransformedBbox(
Bbox(x0=0.125, y0=0.10999999999999999, x1=0.9, y1=0.88),
BboxTransformTo(
TransformedBbox(
Bbox(x0=0.0, y0=0.0, x1=6.4, y1=4.8),
Affine2D(
[[100. 0. 0.]
[ 0. 100. 0.]
[ 0. 0. 1.]])))))))
# notice that the xlimits of the Axes have not been changed
In [270]: print(ax.get_xlim())
(0.0, 1.0)
# but the data limits have been updated to encompass the rectangle
In [271]: print(ax.dataLim.bounds)
(1.0, 1.0, 5.0, 12.0)
# we can manually invoke the auto-scaling machinery
In [272]: ax.autoscale_view()
# and now the xlim are updated to encompass the rectangle, plus margins
In [273]: print(ax.get_xlim())
(0.75, 6.25)
# we have to manually force a figure draw
In [274]: fig.canvas.draw()
Hay muchos, muchos Axes
métodos auxiliares para crear primitivos
Artists
y agregarlos a sus respectivos contenedores. La siguiente tabla resume una pequeña muestra de ellos, los tipos Artist
que crean y dónde los almacenan.
Método auxiliar de ejes |
Artista |
Envase |
---|---|---|
|
hacha.textos |
|
|
hacha.parches |
|
|
ax.lines y ax.patches |
|
|
hacha.parches |
|
|
hacha.parches |
|
|
hacha.images |
|
|
hacha.get_legend() |
|
|
ax.lines |
|
|
hacha.colecciones |
|
|
hacha.textos |
Además de todos estos Artists
, el Axes
contiene dos Artist
contenedores importantes: el XAxis
y YAxis
, que manejan el dibujo de las marcas y etiquetas. Estos se almacenan como variables de instancia
xaxis
y
yaxis
. Los contenedores XAxis
y YAxis
se detallarán a continuación, pero tenga en cuenta que Axes
contiene muchos métodos de ayuda que reenvían las llamadas a las
Axis
instancias, por lo que a menudo no necesita trabajar con ellos directamente a menos que lo desee. Por ejemplo, puede establecer el color de fuente de las etiquetas de XAxis
verificación utilizando el Axes
método auxiliar:
ax.tick_params(axis='x', labelcolor='orange')
A continuación se muestra un resumen de los artistas que Axes
contiene el
Atributo de ejes |
Descripción |
---|---|
artistas |
Una |
parche |
|
colecciones |
Una |
imágenes |
una |
líneas |
Una |
parches |
Una |
textos |
Una |
eje x |
una |
eje y |
una |
Se puede acceder a la leyenda mediante get_legend
,
Contenedores de eje #
Las matplotlib.axis.Axis
instancias manejan el dibujo de las líneas de graduación, las líneas de cuadrícula, las etiquetas de graduación y la etiqueta del eje. Puede configurar las marcas izquierda y derecha por separado para el eje y, y las marcas superior e inferior por separado para el eje x. También almacena los datos y los intervalos de vista utilizados en el escalado automático, la panorámica y el zoom, así
Axis
como las instancias que controlan dónde se colocan las marcas y cómo se representan como cadenas.Locator
Formatter
Cada Axis
objeto contiene un label
atributo (esto es lo que se pyplot
modifica en las llamadas a xlabel
y
ylabel
), así como una lista de marcas mayores y menores. Los ticks son
axis.XTick
e axis.YTick
instancias, que contienen las primitivas de línea y texto reales que representan los ticks y las etiquetas de ticks. Debido a que las marcas se crean dinámicamente según sea necesario (p. ej., al desplazarse y hacer zoom), debe acceder a las listas de marcas principales y secundarias a través de sus métodos de acceso
axis.Axis.get_major_ticks
y axis.Axis.get_minor_ticks
. Aunque los ticks contienen todas las primitivas y se tratarán a continuación, las Axis
instancias tienen métodos de acceso que devuelven las líneas de ticks, las etiquetas de ticks, las ubicaciones de ticks, etc.:
fig, ax = plt.subplots()
axis = ax.xaxis
axis.get_ticklocs()
array([0. , 0.2, 0.4, 0.6, 0.8, 1. ])
[Text(0.0, 0, '0.0'), Text(0.2, 0, '0.2'), Text(0.4, 0, '0.4'), Text(0.6000000000000001, 0, '0.6'), Text(0.8, 0, '0.8'), Text(1.0, 0, '1.0')]
tenga en cuenta que hay el doble de líneas de verificación que etiquetas porque, de forma predeterminada, hay líneas de verificación en la parte superior e inferior, pero solo etiquetas de verificación debajo del eje x; sin embargo, esto se puede personalizar.
<a list of 12 Line2D ticklines objects>
Y con los métodos anteriores, solo obtiene listas de ticks principales de forma predeterminada, pero también puede solicitar los ticks menores:
axis.get_ticklabels(minor=True)
axis.get_ticklines(minor=True)
<a list of 0 Line2D ticklines objects>
Aquí hay un resumen de algunos de los métodos de acceso útiles del Axis
(estos tienen configuradores correspondientes cuando son útiles, como
set_major_formatter()
.)
Método de acceso del eje |
Descripción |
---|---|
La escala del Eje, por ejemplo, 'log' o 'linear' |
|
La instancia de intervalo de los límites de la vista Axis |
|
La instancia de intervalo de los límites de datos de Axis |
|
Una lista de líneas de cuadrícula para el Eje |
|
La etiqueta Axis: una |
|
El texto de desplazamiento del eje: una |
|
Una lista de |
|
Una lista de |
|
Una lista de ubicaciones de Tick - palabra clave minor=Verdadero|Falso |
|
La |
|
La |
|
La |
|
La |
|
Una lista de |
|
Una lista de |
|
Encienda o apague la cuadrícula para los ticks mayores o menores |
Aquí hay un ejemplo, no recomendado por su belleza, que personaliza las propiedades de Axes y Tick.
# plt.figure creates a matplotlib.figure.Figure instance
fig = plt.figure()
rect = fig.patch # a rectangle instance
rect.set_facecolor('lightgoldenrodyellow')
ax1 = fig.add_axes([0.1, 0.3, 0.4, 0.4])
rect = ax1.patch
rect.set_facecolor('lightslategray')
for label in ax1.xaxis.get_ticklabels():
# label is a Text instance
label.set_color('red')
label.set_rotation(45)
label.set_fontsize(16)
for line in ax1.yaxis.get_ticklines():
# line is a Line2D instance
line.set_color('green')
line.set_markersize(25)
line.set_markeredgewidth(3)
plt.show()
Contenedores de garrapatas #
El matplotlib.axis.Tick
es el objeto contenedor final en nuestro descenso del Figure
al al
Axes
al Axis
al al Tick
. contiene las Tick
instancias de línea de cuadrícula y marca, así como las instancias de etiqueta para las marcas superior e inferior. Cada uno de estos es accesible directamente como un atributo de Tick
.
Atributo de marca |
Descripción |
---|---|
marca1línea |
una |
tick2line |
una |
cuadricula |
una |
etiqueta1 |
una |
etiqueta2 |
una |
Aquí hay un ejemplo que configura el formateador para las marcas del lado derecho con signos de dólar y los colorea de verde en el lado derecho del eje y.
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
fig, ax = plt.subplots()
ax.plot(100*np.random.rand(20))
# Use automatic StrMethodFormatter
ax.yaxis.set_major_formatter('${x:1.2f}')
ax.yaxis.set_tick_params(which='major', labelcolor='green',
labelleft=False, labelright=True)
plt.show()
Tiempo total de ejecución del script: (0 minutos 1.067 segundos)