Integración de gráficos de Matplotlib en un PDF en Python con borb

El formato de documento portátil (PDF) no es un formato WYSIWYG (Lo que ves es lo que obtienes). Fue desarrollado para ser independiente de la plataforma, independiente de los...

Introducción

El Portable Document Format (PDF) no es un formato WYSIWYG (lo que ves es lo que obtienes). Fue desarrollado para ser independiente de la plataforma, independiente del sistema operativo subyacente y los motores de renderizado.

Para lograr esto, PDF se construyó para poder interactuar a través de algo más parecido a un lenguaje de programación, y se basa en una serie de instrucciones y operaciones para lograr un resultado. De hecho, PDF está basado en un lenguaje de secuencias de comandos: Posdata, que fue el primer lenguaje de descripción de página independiente del dispositivo.

En esta guía, utilizaremos borracho, una biblioteca de Python dedicada a leer, manipular y generar documentos PDF. Ofrece un modelo de bajo nivel (que le permite acceder a las coordenadas y el diseño exactos si elige usarlos) y un modelo de alto nivel (donde puede delegar los cálculos precisos de márgenes, posiciones, etc. a un administrador de diseño) .

Matplotlib es una biblioteca de visualización de datos que impulsó a toda una generación de ingenieros a comenzar a visualizar datos y el motor detrás de muchas otras bibliotecas populares como Seaborn.

Dado lo comunes que son los documentos PDF para crear informes (que a menudo incluyen gráficos), veremos cómo integrar gráficos de Matplotlib en un documento PDF usando borb.

Instalación de borb (y Matplotlib) {#instalación de borbandmatplotlib}

borb puede descargarse desde la fuente en GitHub, o instalarse a través de pip:

1
$ pip install borb

Matplotlib se puede instalar a través de pip:

1
$ pip install matplotlib

Integración de gráficos de Matplotlib en documentos PDF con borb

Antes de que podamos crear un gráfico, como un gráfico circular, vamos a escribir una pequeña función de utilidad que genera “N” colores, distribuidos uniformemente entre el espectro de colores.

Esto nos ayudará cuando necesitemos crear un gráfico y colorear cada sección:

1
2
3
4
5
6
7
8
9
from borb.pdf.canvas.color.color import HSVColor, HexColor
from decimal import Decimal
import typing

def create_n_colors(n: int) -> typing.List[str]:
  # The base color is borb-blue
  base_hsv_color: HSVColor = HSVColor.from_rgb(HexColor("56cbf9"))
  # This array comprehension creates n HSVColor objects, transforms then to RGB, and then returns their hex string
  return [HSVColor(base_hsv_color.hue + Decimal(x / 360), Decimal(1), Decimal(1)).to_rgb().to_hex_string() for x in range(0, 360, int(360/n))]

{.icon aria-hidden=“true”}

Nota: HSL (tono, saturación, luminosidad) y HSV/HSB (tono, saturación, valor/tono, saturación, brillo) son representaciones alternativas del color RGB modelo.

HSL y HSV/HSB fueron diseñados en la década de 1970 por investigadores de gráficos por computadora para alinearse más estrechamente con la forma en que la visión humana percibe los atributos de creación de color. En estos modelos, los colores de cada tonalidad se disponen en un corte radial, alrededor de un eje central de colores neutros que va desde el negro en la parte inferior hasta el blanco en la parte superior:

espectro de cono hsv


[Créditos: wikimedia (CC BY-SA 3.0) licencia]{.small}

La ventaja de usar esta representación para Color es que podemos dividir fácilmente el espectro de colores en partes iguales.

Ahora podemos definir una función create_pie_chart() (o una función para otros tipos de gráficos):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# New import(s)
import matplotlib.pyplot as plt
from borb.pdf.canvas.layout.image.chart import Chart
from borb.pdf.canvas.layout.layout_element import Alignment

def create_piechart(labels: typing.List[str], data: typing.List[float]):

  # Symetric figure to ensure equal aspect ratio
  fig1, ax1 = plt.subplots(figsize=(4, 4))
  ax1.pie(
    data,
    explode=[0 for _ in range(0, len(labels))],
    labels=labels,
    autopct="%1.1f%%",
    shadow=True,
    startangle=90,
    colors=create_n_colors(len(labels)),
  )

  ax1.axis("equal")  # Equal aspect ratio ensures that pie is drawn as a circle.

  return Chart(
    plt.gcf(),
    width=Decimal(200),
    height=Decimal(200),
    horizontal_alignment=Alignment.CENTERED,
  )

Aquí, hemos usado Matplotlib para crear un gráfico circular, a través de la función pie().

If you'd like to learn more about creating Pie Charts, read our Guía de gráficos circulares de Matplotlib!

La función gcf() de la instancia PyPlot devuelve la cifra actual (get current figure). Esta figura se puede incrustar en un documento PDF, inyectándola en un constructor de ‘Gráfico’, junto con sus argumentos de personalización como ‘ancho’, ‘alto’ y ‘alineación_horizontal’.

¡Eso es todo! Simplemente proporciona una figura de Matplotlib al constructor Chart.

Adición de un gráfico Matplotlib a un documento PDF

Ahora es el momento de crear nuestro ‘Documento’ PDF básico y agregarle contenido.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# New import(s)
from borb.pdf.document import Document
from borb.pdf.page.page import Page
from borb.pdf.pdf import PDF
from borb.pdf.canvas.layout.page_layout.multi_column_layout import MultiColumnLayout
from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout
from borb.pdf.canvas.layout.text.paragraph import Paragraph

# Create empty Document
pdf = Document()

# Create empty Page
page = Page()

# Add Page to Document
pdf.append_page(page)

# Create PageLayout
layout: PageLayout = MultiColumnLayout(page)

# Write title
layout.add(Paragraph("About Lorem Ipsum", 
                     font_size=Decimal(20), 
                     font="Helvetica-Bold"))

Usaremos guiones en este PDF para asegurarnos de que el texto se pueda distribuir aún mejor. La separación silábica en borb es bastante sencilla:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# New import(s)
from borb.pdf.canvas.layout.hyphenation.hyphenation import Hyphenation

# Create hyphenation algorithm
hyphenation_algorithm: Hyphenation = Hyphenation("en-gb")

# Write paragraph
layout.add(Paragraph(
    """
    Lorem Ipsum is simply dummy text of the printing and typesetting industry. 
    Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, 
    when an unknown printer took a galley of type and scrambled it to make a type specimen book. 
    It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. 
    It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, 
    and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
    """, text_alignment=Alignment.JUSTIFIED, hyphenation=hyphenation_algorithm))

Ahora podemos agregar un gráfico circular usando la función que declaramos anteriormente;

1
2
3
# Write graph
layout.add(create_piechart(["Loren", "Ipsum", "Dolor"], 
                           [0.6, 0.3, 0.1]))

A continuación vamos a escribir tres objetos Paragraph más.
Uno de ellos va a ser más una cita (borde en el costado, fuente diferente, etc.).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# Write paragraph
layout.add(Paragraph(
    """
    Contrary to popular belief, Lorem Ipsum is not simply random text. 
    It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. 
    Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, 
    consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, 
    discovered the undoubtable source.
    """, text_alignment=Alignment.JUSTIFIED, hyphenation=hyphenation_algorithm))

# Write paragraph
layout.add(Paragraph(
    """
    Lorem Ipsum is simply dummy text of the printing and typesetting industry. 
    """, 
    font="Courier-Bold",
    text_alignment=Alignment.JUSTIFIED, 
    hyphenation=hyphenation_algorithm,
    border_color=HexColor("56cbf9"),
    border_width=Decimal(3),
    border_left=True,
    padding_left=Decimal(5),
    padding_bottom=Decimal(5),
))

# Write paragraph
layout.add(Paragraph(
    """
    Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" 
    (The Extremes of Good and Evil) by Cicero, written in 45 BC. 
    This book is a treatise on the theory of ethics, very popular during the Renaissance.
    """, text_alignment=Alignment.JUSTIFIED, hyphenation=hyphenation_algorithm))

Agreguemos otra parcela

1
2
3
# Write graph
layout.add(create_piechart(["Loren", "Ipsum", "Dolor", "Sit", "Amet"], 
                           [600, 30, 89, 100, 203]))

Y un Párrafo más de contenido

1
2
3
4
5
6
7
8
9
# Write paragraph
layout.add(Paragraph(
    """
    It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. 
    The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', 
    making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, 
    and a search for 'lorem ipsum' will uncover many web sites still in their infancy. 
    Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).
    """, text_alignment=Alignment.JUSTIFIED, hyphenation=hyphenation_algorithm))

Finalmente, podemos almacenar el Documento:

1
2
3
# Write to disk
with open("output.pdf", "wb") as pdf_file_handle:
  PDF.dumps(pdf_file_handle, pdf)

Ejecutar este código da como resultado un documento PDF que se ve así:

integrando gráficos de matplotlib en pdf con python y borb

Conclusión

En esta guía, ha aprendido cómo integrar gráficos de Matplotlib en un PDF usando borb. A partir de aquí, ¡el cielo es el límite! Cuanto más creativo sea con la visualización de datos, mejores serán sus archivos PDF.