Índice:
- Introducción.
- El libro.
- La hoja de cálculos.
- La celda.
- Los estilos.
- Los gráficos (este capítulo).
Hasta ahora hemos pasado un poco por encima sobre cómo crear gráficos con openpyxl
. Hemos visto como crear hojas de gráfico o chartsheets pero sin redundar mucho en ello. En este nuevo capítulo vamos a ver más en detalle el tema de los gráficos en openpyxl
.
Empezamos importando lo que vayamos a necesitar. Veréis que hay unas cuantas cosas que no habíamos utilizado hasta ahora:
import random
from copy import deepcopy
import openpyxl
from openpyxl.chart import (
LineChart, Reference, ScatterChart, Series, BarChart
)
from openpyxl.styles import colors
Creamos un libro que contendrá una hoja o pestaña y unos datos que usaremos a lo largo del capítulo:
def create_new_wb():
wb = openpyxl.Workbook()
ws = wb.active
ws = wb.active
header = [f"H{i + 1:02}" for i in range(10)]
ws.append(header)
for i in range(10):
row = [random.random() for _ in range(10)]
ws.append(row)
return wb, ws
wb, ws = create_new_wb()
Lo guardamos y visualizamos para que veáis cómo queda:
wb.save("new.xlsx")
wb.close()
Nuestro primer gráfico
Para empezar, vamos a hacer un gráfico de línea y luego iremos viendo más en detalle las diferentes partes. Lo hacemos y luego lo explicamos:
wb, ws = create_new_wb()
values = Reference(ws, min_col=1, max_col=2, min_row=1, max_row=11)
print(values)
print(type(values))
Lo anterior mostrará:
'Sheet'!$A$1:$B$11
<class 'openpyxl.chart.reference.Reference'>
Lo que acabamos de hacer es coger unos valores usando la clase Reference
la cual nos permite seleccionar de qué hoja vamos a coger los valores y qué rango de celdas vamos a usar (las dos primeras columnas).
grafico = LineChart()
Creamos un gráfico de línea usando LineChart
.
grafico.add_data(values, titles_from_data=True)
Añadimos los datos. Por defecto usará las columnas como series a no ser que le indiquemos lo contrario.
grafico.title = "Ejemplo"
Añadimos el título del gráfico. Este título puede que aparezca o no dependiendo del estilo que le demos al gráfico.
grafico.style = 10
Luego hablaremos más en detalle sobre esto…
grafico.x_axis.title = "Eje x"
grafico.y_axis.title = "Eje y"
Los títulos de los ejes.
serie = grafico.series[0]
serie.marker.symbol = None
serie.graphicalProperties.line.solidFill = colors.BLACK
Accedemos a la primera serie de datos del LineChart
y le indicamos que queremos que use el color negro y que no use marcadores.
serie = grafico.series[1]
serie.marker.symbol = "circle"
serie.graphicalProperties.line.solidFill = colors.BLUE
Lo mismo para la segunda serie, pero en este caso queremos marcadores de tipo diamante y que la línea sea azul.
ws.add_chart(grafico, "K1")
Añadimos el gráfico a la hoja y guardamos y visualizamos para ver el resultado:
wb.save("new.xlsx")
wb.close()
El mismo gráfico solo se puede usar una vez en la misma hoja, por tanto, lo siguiente dará error:
ws.add_chart(grafico, "K15")
wb.save("new.xlsx")
Si queremos usar el mismo gráfico y modificar esa misma instancia deberemos crear copias. Vamos a crear copias y vamos a mostrar el mismo gráfico solo cambiando el estilo para ver los estilos que tenemos. Regeneramos de nuevo el libro y la hoja para evitar el error anterior:
wb, ws = create_new_wb()
for i in range(1, 30):
g = deepcopy(grafico)
g.style = i
ws.add_chart(g, f"K{i * 15}")
Si lo guardamos y lo visualizamos veremos algo parecido a lo siguiente:
wb.save("new.xlsx")
wb.close()
Lo de los estilos lo hemos metido numerado y hacen referencia a estilos que vemos en el menú en Microsoft Excel:
Como lo anterior y la forma como lo estamos usando no es muy sencilla de ver vamos a ser más explícitos y modificar las partes del gráfico que consideremos sin necesidad de recurrir a estilos que pueden cambiar, no tienen porque verse de forma similar en diferentes programas de hojas de cálculo,…
Anatomía de un gráfico
Antes de nada vamos a reiniciar el libro y la hoja:
wb, ws = create_new_wb()
Vamos a añadir ahora un diagrama de dispersión, ScatterChart
, usando dos columnas y sobre esto vamos a ir viendo diferentes cosas del gráfico:
g = ScatterChart()
xvalues = Reference(ws, min_col=1, max_col=1, min_row=2, max_row=11)
yvalues = Reference(ws, min_col=2, max_col=2, min_row=2, max_row=11)
serie = Series(yvalues, xvalues)
g.series.append(serie)
Como hemos visto antes, podemos darle nombre a los ejes:
g.x_axis.title = "Eje x"
g.y_axis.title = "Eje y"
Pero también podemos definir muchas otras cosas:
# Los números eran aleatorios entre 0 y 1
g.x_axis.scaling.min = 0
g.x_axis.scaling.max = 1
g.y_axis.scaling.min = 0
g.y_axis.scaling.max = 1
Definimos el rango del eje usando scaling.min
y/o scaling.max
.
Podemos elegir si queremos que los valores del eje vayan del mínimo al máximo, forma por defecto, pero también podríamos querer que los valores fueran al reves, con los valores máximos al principio y los mínimos al final:
g.x_axis.scaling.orientation = "maxMin"
print(g.legend)
g.legend = None
El print
mostrará:
<openpyxl.chart.legend.Legend object>
Parameters:
legendPos='r', legendEntry=[], layout=None, overlay=None, spPr=None, txPr=None
Podemos eliminar la leyenda o colocarla en otro sitio del que viene por defecto ('r'
por right). Podemos elegir entre 'r'
, ‘l
‘, ‘t
‘, ‘b
‘, right, left, top, bottom, respectivamente, o algunas combinaciones entre ellas. Por ejemplo, podemos combinar cualquiera de izquierda y derecha con cualquiera de arriba y abajo: ‘lb
‘, ‘lt
‘, ‘rb
‘, ‘rt
‘ para colocarlas abajo a la izquierda, arriba a la izquierda, abajo a la derecha o arriba a la derecha, respectivamente.
La serie, como es un diagrama de dispersión, querremos que no aparezcan rayas y solo aparezcan puntos con el marcador que consideremos (en este caso voy a usar círculos rojos):
RED = colors.COLOR_INDEX[2]
serie.marker.symbol = "circle"
serie.marker.graphicalProperties.solidFill = RED
serie.graphicalProperties.line.noFill = True
El eje “y” quiero que aparezca en la parte derecha en lugar de en la parte izquierda:
g.y_axis.crossesAt = 1
g.y_axis.crosses = "max"
Añadimos el gráfico y guardamos el documento:
ws.add_chart(g, "K1")
wb.save("new.xlsx")
Combinar gráficos
Podemos combinar varios gráficos en uno, por ejemplo, un diagrama de barras y un gráfico de línea. Vamos a ver cómo hacer esto. Empezamos creando un libro y hoja nuevos:
wb, ws = create_new_wb()
Instanciamos LineChart
y BarChart
:
gl = LineChart()
gb = BarChart()
Añadimos los datos que vamos a usar:
values_line = Reference(ws, min_col=1, max_col=1, min_row=2, max_row=11)
values_bar = Reference(ws, min_col=2, max_col=2, min_row=2, max_row=11)
gl.add_data(values_line)
gb.add_data(values_bar)
Eliminamos las leyendas de ambos gráficos:
gl.legend = None
gb.legend = None
Al gráfico de barra le ponemos el eje “y” en la parte derecha del gráfico:
gb.y_axis.crosses = "max"
Damos nombres a los ejes:
gl.x_axis.title = "Eje a a compartir"
gl.y_axis.title = "Eje y línea"
gb.y_axis.title = "Eje y barra"
Fundimos ambos gráficos en uno:
gl += gb
Añadimos el gráfico a la hoja. Y guardamos el gráfico y lo visualizamos:
ws.add_chart(gl, "K1")
wb.save("new.xlsx")
Tipos de gráficos
Se pueden usar muchos tipos de gráficos. Algunos de ellos ya los hemos visto mientras que otros solo los vamos a nombrar para saber lo que hacen y como usarlos. Me voy a saltar cualquier gráfico 3D porque nunca, repito, ¡¡NUNCA!!, deberéis usarlos ya que siempre hay alternativas mejores de visualizar datos sin recurrir a una supuesta tercera dimensión en una pantalla o papel:
LineChart
: Para dibujar gráficos de línea. Hemos visto algún ejemplo más arriba.ScatterChart
: Para dibujar diagramas de dispersión. Hemos visto algún ejemplo más arriba.BarChart
: Para dibujar gráficos de columnas. Hemos visto algún ejemplo más arriba.AreaChart
: Son similares a los gráficos de línea pero el área por debajo de la línea se rellena hasta el eje horizontal.BubbleChart
: Son similares a los gráficos de dispersión pero nos permiten añadir una tercera dimensión que lo representamos mediante el tamaño del círculo. Una cuarta dimensión se podría representar con el color del círculo.PieChart
: Son gráficos de quesitos. Ideales para mostrar porcentajes.DoughnutChart
: Similares a los gráficos de quesitos.RadarChart
: Podríamos verlo como un gráfico de área pero en coordenadas polares.StockChart
: Útiles para mostrar gráficos agregados. Parecido a lo que puede hacer un un gráfico de caja o de bigotes.SurfaceChart
: Útiles para dibujar datos en un grid como contornos o isolíneas.
Más información sobre todo esto aquí.
Hojas de gráficos
Desde un principio vimos que podíamos crear hojas de gráficos (chartsheets) pero no hemos vuelto a hablar de ello hasta ahora. Ahora, que hemos visto los gráficos por encima, ha llegado el momento de hablar de las hojas de gráfico.
Básicamente, una hoja de gráfico es una hoja o pestaña dedicada únicamente a mostrar un gráfico.
Vamos a empezar creando un libro y hoja nuevos:
wb, ws = create_new_wb()
Creamos, además, una nueva hoja de gráfico:
cs = wb.create_chartsheet()
Creamos un nuevo gráfico:
g = BarChart()
values = Reference(ws, min_col=1, max_col=1, min_row=2, max_row=11)
g.add_data(values)
g.legend = None
Y, en el momento que tenemos el gráfico como queremos, lo añadimos a una hoja de gráfico en lugar de añadirlo a una posición (celda) en una hoja de trabajo. Lo podemos hacer de la siguiente forma:
cs.add_chart(g)
Si ahora guardamos y visualizamos no funcionará en LibreOffice Calc…:
wb.save("new.xlsx")
Resumiendo
Hemos visto de forma superficial como poder insertar gráficos en una hoja de cálculos o en una hoja dedicada (chartsheet). En general, se pueden hacer gráficos simples con excel pero para cosas avanzadas quizá siga siendo mejor recurrir a otras librerías y luego incrustar la imagen como pudimos ver en anteriores capítulos. Muchas de las cosas relacionadas con gráficos no me han estado funcionando en LibreOffice Calc por lo que parece que Microsoft Excel es superior en este sentido y algún código que escribáis con openpyxl
no se verá como esperas en LibreOffice 🙁