PerfectVector
Por Irene Kim9 min de lectura

SVG en Matplotlib: conserva el gráfico y el logotipo como trazados

Exporta tu gráfico de Matplotlib como SVG, compón trazados de logotipo separados con svgutils y comprueba píxeles incrustados, colocación y cambios de fuente en el archivo entregado.

En esta página

Para conservar un logotipo vectorial dentro de una figura de Matplotlib, exporta el gráfico como SVG y combínalo con la geometría SVG existente del logotipo. Colocar un PNG con OffsetImage puede producir un SVG que contenga una imagen raster junto a líneas vectoriales del gráfico. La extensión por sí sola no indica qué partes son trazados.

Esta guía mantiene esos trabajos separados: Matplotlib dibuja el gráfico a partir de sus datos y svgutils coloca un emblema decorativo a su lado. Si la ilustración original ya es vectorial, úsala. Si solo queda una ilustración raster adecuada, recupérala por separado. Mantén los elementos numéricos, los ejes y las etiquetas en el código de origen del gráfico.

El flujo breve

Exporta el gráfico, compón la ilustración separada, inspecciona el SVG resultante y vuelve a abrir el archivo exacto que entregarás. Conserva el script del gráfico y el maestro de la ilustración para que la siguiente revisión de datos pueda regenerar la figura.

Elige qué corresponde al código de origen del gráfico

Un logotipo es una ilustración; una marca del eje forma parte del gráfico. Tratar ambos como una sola imagen dificulta las revisiones posteriores.

Contenido de la figuraOrigen preferidoQué verificar
Líneas, marcadores, ejes y etiquetas de datosCódigo del gráfico de MatplotlibValores, etiquetas y decisiones de representación
Logotipo o ilustración vectorial existenteSu maestro SVGTrazados, límites y dependencias
Fotografía raster o panel de microscopíaImagen raster originalResolución al tamaño final
Motivo decorativo sencillo cuyo origen vectorial se ha perdidoUn candidato recuperado e inspeccionado por separadoFidelidad de las formas y regiones no deseadas

No hace falta una figura completamente vectorial cuando algunos paneles son fotografías. Consérvalos como raster. El objetivo es mantener el origen adecuado para cada componente y después comprobar el resultado ensamblado.

La referencia de savefig de Matplotlib documenta cómo seleccionar explícitamente un formato de salida. Su API OffsetImage describe un contenedor de imagen, no un importador de trazados SVG. Para diagnosticar el archivo, consulta cómo encontrar imágenes raster dentro de un SVG.

Qué contienen los archivos entregados

Ejecutamos el ejemplo con Python 3.12, Matplotlib 3.10.7 y svgutils 0.3.4. El emblema es un dibujo original de dos trazados. Los cuatro valores representados son datos ilustrativos, no un experimento ni una prueba comparativa de producto.

La comparación utiliza el mismo gráfico en ambos archivos. A la izquierda se inserta un emblema PNG de 32 × 32 con OffsetImage. A la derecha se combinan sus trazados SVG con el gráfico exportado. Las regiones ampliadas proceden de esos archivos entregados reales.

Archivos SVG reales de Matplotlib con regiones del emblema ampliadas: un emblema PNG incrustado a la izquierda y trazados de emblema SVG compuestos a la derecha
El gráfico sigue siendo vectorial en ambos archivos. En este ejemplo, la versión raster contiene un elemento de imagen; la versión compuesta añade dos trazados de ilustración y no contiene ningún elemento de imagen.

Contar los elementos SVG dio estos resultados:

ArchivoElementos de imagenElementos de trazadoElementos de texto
Solo el gráfico0815
Gráfico con emblema PNG1815
Gráfico con trazados del emblema SVG01015

Estos recuentos corresponden a este ejemplo pequeño. El número de trazados no es una puntuación de calidad, y cero elementos de imagen no demuestra que todas las funciones SVG sobrevivan en otra aplicación. Sí demuestra que el emblema de este archivo compuesto es geometría en lugar de un PNG incrustado.

Exporta un gráfico con límites predecibles

Instala las versiones utilizadas aquí en un entorno de proyecto:

python -m pip install matplotlib==3.10.7 svgutils==0.3.4

Guarda esto como plot.py y ejecútalo en una carpeta de trabajo vacía:

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
 
plt.rcParams["svg.fonttype"] = "none"
 
fig = plt.figure(figsize=(6, 3), dpi=72)
ax = fig.add_axes([0.14, 0.22, 0.58, 0.65])
ax.plot([0, 1, 2, 3], [1, 2, 1.5, 3],
        marker="o", color="#173b40")
ax.set(xlabel="Example x", ylabel="Example y",
       title="Illustrative data only")
ax.spines[["top", "right"]].set_visible(False)
fig.savefig("plot.svg", format="svg")
plt.close(fig)

Los ejes ocupan solo parte de la figura, dejando espacio para el emblema a la derecha. Esta exportación tiene un viewBox de 0 0 432 216, con dimensiones exteriores de 432pt por 216pt.

Mantén estables esos límites al colocar ilustraciones externas. Añadir bbox_inches="tight" cambia los límites guardados, como explica la documentación de savefig. Si necesitas un recorte ajustado, inspecciona el viewBox exportado y actualiza después las coordenadas de composición.

El ajuste svg.fonttype="none" conserva las etiquetas del ejemplo como texto. La documentación de fuentes de Matplotlib describe las opciones de salida SVG como texto y trazados. El texto editable sigue necesitando una fuente adecuada en el entorno receptor. Si necesitas formas de letras fijas, elige deliberadamente la salida de trazados y conserva el código del gráfico para editar las etiquetas. La guía de cambios de fuente SVG explica esa elección.

Compón la ilustración sin rasterizarla

Guarda este emblema original como badge.svg junto a plot.svg:

<svg xmlns="http://www.w3.org/2000/svg"
     width="100" height="100" viewBox="0 0 100 100">
  <path fill="#173b40" fill-rule="evenodd"
        d="M30 5H70L95 30V70L70 95H30L5 70V30Z
           M34 17L17 34V66L34 83H66L83 66V34L66 17Z"/>
  <path fill="#28bfa3" d="M53 23L30 55H47L43 77L70 43H53Z"/>
</svg>

Después ejecuta este script de composición:

import svgutils.transform as sg
 
page = sg.SVGFigure("432pt", "216pt")
page.root.set("viewBox", "0 0 432 216")
 
chart = sg.fromfile("plot.svg").getroot()
badge = sg.fromfile("badge.svg").getroot()
badge.moveto(332, 76, scale_x=0.64)
 
page.append([chart, badge])
page.save("vector-logo.svg")

Esto sigue el método de cargar, transformar, añadir y guardar del tutorial de composición de figuras de svgutils. Utilizamos scale_x, el argumento admitido por svgutils 0.3.4; el tutorial antiguo muestra otro argumento de escala.

La ilustración de 100 unidades del emblema pasa a tener 64 unidades de ancho. Su esquina superior izquierda se sitúa en (332, 76) dentro del sistema de coordenadas del gráfico. Las dimensiones exteriores explícitas y el viewBox hacen inequívoca esa colocación en este ejemplo. Son coordenadas de página, no de datos: mover un punto de datos en el gráfico no moverá el emblema con él.

Para anotaciones vinculadas a un punto de datos que cambia, mantén una correspondencia deliberada entre las coordenadas del gráfico y la página exportada, o utiliza una herramienta de composición que proporcione esa asociación. Una colocación fija en la página sirve para un logotipo en una esquina o un panel ilustrativo separado.

El maestro SVG puede contener funciones más allá de los trazados. Un SVG que ya incrusta un PNG sigue teniendo contenido mixto al componerse. Comprueba también los ID referenciados, las fuentes y los recursos enlazados externamente al combinar archivos más complejos. Este ejemplo evita esas dependencias en el emblema.

Inspecciona el archivo y después prueba una revisión

Abre vector-logo.svg en un navegador o en tu editor previsto. Comprueba la abertura central del emblema, las etiquetas del gráfico y el espacio vacío entre ambos. Inspecciona el archivo al tamaño al que realmente lo utilizarás y también ampliado.

Una pequeña comprobación XML puede confirmar la estructura sin depender de la vista previa:

import xml.etree.ElementTree as ET
 
root = ET.parse("vector-logo.svg").getroot()
ns = "{http://www.w3.org/2000/svg}"
for tag in ("image", "path", "text"):
    print(tag, len(root.findall(".//" + ns + tag)))

Para el ejemplo proporcionado, esto imprime image 0, path 10 y text 15. La comparación raster imprime image 1, mientras conserva los ocho trazados del gráfico. En esa comparación, la referencia de imagen contiene datos PNG; es contenido raster autónomo, no un archivo de logotipo externo que falta.

Ahora cambia el último valor ilustrativo del eje y en plot.py, vuelve a ejecutarlo y vuelve a ejecutar la composición. El gráfico debería cambiar mientras el emblema permanece en su posición reservada de página. Esa comprobación de revisión detecta un flujo que se ve bien una vez, pero depende de una exportación antigua del gráfico.

Comprueba por separado el siguiente paso de entrega. Si la figura se incorporará a un documento, el flujo SVG para LaTeX explica las opciones de exportación y etiquetas. Una vista previa correcta en el navegador por sí sola no demuestra el cumplimiento de requisitos de una revista ni la conservación en un PDF final.

Recupera solo la ilustración que necesite recuperación

Cuando exista el código de origen del gráfico, exporta desde él. La vectorización no puede restaurar datos numéricos ni comandos de representación a partir de una captura.

PerfectVector encaja en el caso más concreto en el que un logotipo o ilustración decorativa sencilla solo se conserva como imagen raster. Con su flujo de recuperación de ilustraciones científicas, recorta hasta esa ilustración, previsualiza el vector candidato e inspecciona aberturas, formas finas y regiones de fondo no deseadas. Mantén los ejes, las marcas de medidas y las etiquetas fuera de la vectorización. Combina el SVG de ilustración aprobado con el gráfico nativo y repite después las comprobaciones del archivo entregado.

Usa el maestro vectorial original siempre que lo tengas. Redibuja manualmente una marca sencilla cuando la vectorización pierda un detalle importante. Conserva los paneles fotográficos como raster. La introducción a la vectorización de imágenes explica qué puede recuperar la vectorización antes de elegir ese método.

Preguntas frecuentes

¿Guardar una figura de Matplotlib como SVG convierte un logotipo PNG en vector? No. En el flujo probado con OffsetImage, el gráfico se exporta como geometría vectorial mientras el logotipo PNG sigue siendo un elemento de imagen dentro del SVG.

¿Puedo colocar el logotipo SVG utilizando coordenadas de datos? La composición mostrada aquí utiliza coordenadas de la página exportada. Un logotipo vinculado a un punto de datos necesita una correspondencia explícita de coordenadas o una herramienta que mantenga esa asociación.

¿Por qué mis etiquetas se convirtieron en trazados? El ajuste de salida de fuentes SVG de Matplotlib controla si las etiquetas se exportan como texto o como trazados de glifos. Elige ese ajuste antes de exportar y conserva el código del gráfico para cambios posteriores de palabras.

Fuentes

  1. Matplotlib — savefig — Exportación SVG explícita y efecto de los cuadros delimitadores ajustados.
  2. Matplotlib — OffsetImage — Comportamiento del contenedor de imagen utilizado en la comparación raster.
  3. Matplotlib — Fuentes en Matplotlib — Opciones de salida SVG de texto y trazados de glifos.
  4. svgutils — Crear figuras de calidad para publicación — Exportación separada del gráfico, composición SVG, transformaciones y guardado de una figura ensamblada.

Exporta el gráfico desde su código y conserva la ilustración separada. Si solo queda un motivo decorativo raster, prepara un SVG candidato de la ilustración, inspecciona sus aberturas y límites, combínalo después con el gráfico y comprueba píxeles, colocación y cambios de etiquetas en el archivo exacto entregado.

Más del blog

Empieza con un SVG más limpio
y fácil de editar