PerfectVector
작성: Irene Kim7분 읽기

Matplotlib SVG: 그래프와 로고를 경로로 유지하기

Matplotlib 그래프를 SVG로 내보내고 svgutils로 별도의 로고 경로를 합성하세요. 전달 파일에서 삽입된 픽셀, 배치와 글꼴 변경을 확인합니다.

목차

Matplotlib 그림 안에서 로고를 벡터로 유지하려면 그래프를 SVG로 내보내고 로고의 기존 SVG 도형과 합성하세요. OffsetImage로 PNG를 배치하면 벡터 그래프 선과 래스터 이미지가 함께 있는 SVG가 만들어질 수 있습니다. 확장자만으로 어느 부분이 경로인지 알 수는 없습니다.

이 가이드는 작업을 나눕니다. Matplotlib이 데이터로 그래프를 그리고 svgutils가 옆에 장식용 배지를 배치합니다. 원본 그림이 이미 벡터라면 그대로 사용하세요. 적합한 래스터 일러스트만 남았다면 그 일러스트를 따로 복원하세요. 수치 표식, 축과 레이블은 그래프 소스에 유지하세요.

간단한 작업 흐름

그래프를 내보내고 별도 그림을 합성한 뒤 결과 SVG를 확인하고, 실제 전달할 파일을 다시 여세요. 다음 데이터 수정 시 그림을 다시 생성할 수 있도록 그래프 스크립트와 그림 원본을 보관하세요.

그래프 소스에 속하는 요소 선택하기

로고는 그림이고 축 눈금은 그래프의 일부입니다. 둘을 하나의 이미지로 취급하면 이후 수정이 어려워집니다.

그림 내용권장 소스확인할 사항
선, 마커, 축과 데이터 레이블Matplotlib 그래프 코드값, 레이블과 그래프 표현 방식
기존 벡터 로고 또는 일러스트SVG 원본경로, 경계와 의존성
래스터 사진 또는 현미경 이미지 패널원본 래스터 이미지최종 크기에서의 해상도
벡터 원본을 잃어버린 단순한 장식 모티프별도로 검토한 복원 후보모양 충실도와 원하지 않는 영역

일부 패널이 사진이라면 그림 전체가 벡터일 필요는 없습니다. 사진은 래스터로 유지하세요. 목표는 각 구성 요소에 맞는 소스를 보존하고 합친 결과를 확인하는 것입니다.

Matplotlib의 savefig 참고 문서는 출력 형식을 명시적으로 선택하는 방법을 설명합니다. OffsetImage API는 SVG 경로 가져오기 도구가 아니라 이미지 컨테이너를 설명합니다. 파일 단위 진단은 SVG 안의 래스터 이미지 찾는 방법을 참고하세요.

전달 파일에 포함되는 내용

Python 3.12, Matplotlib 3.10.7, svgutils 0.3.4로 예제를 실행했습니다. 배지는 직접 그린 2개 경로 그림입니다. 그래프의 네 값은 설명용 데이터이며 실험이나 제품 벤치마크가 아닙니다.

두 파일 모두 같은 그래프를 사용합니다. 왼쪽은 OffsetImage로 32 × 32 PNG 배지를 삽입하고, 오른쪽은 SVG 경로를 내보낸 그래프와 합성합니다. 확대 영역은 실제 전달 파일에서 가져왔습니다.

배지 영역을 확대한 실제 Matplotlib SVG 파일: 왼쪽은 삽입된 PNG 배지, 오른쪽은 합성한 SVG 배지 경로
두 파일 모두 그래프는 벡터로 유지됩니다. 이 예제에서 래스터 버전은 이미지 요소 하나를 포함하고, 합성 버전은 그림 경로 두 개를 추가하며 이미지 요소는 없습니다.

SVG 요소를 세어 다음 결과를 얻었습니다.

파일이미지 요소경로 요소텍스트 요소
그래프만 있음0815
PNG 배지가 있는 그래프1815
SVG 배지 경로가 있는 그래프01015

이 개수는 이 작은 예제에 해당합니다. 경로 개수는 품질 점수가 아니며 이미지 요소가 0개라고 모든 SVG 기능이 다른 애플리케이션에서도 유지된다는 뜻은 아닙니다. 다만 이 합성 파일의 배지가 삽입된 PNG가 아니라 도형임은 확인할 수 있습니다.

예상 가능한 경계로 그래프 내보내기

프로젝트 환경에 여기서 사용한 버전을 설치하세요.

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

다음을 plot.py로 저장하고 빈 작업 폴더에서 실행하세요.

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)

축은 그림의 일부만 차지하며 오른쪽에 배지 공간을 남깁니다. 내보낸 파일의 viewBox는 0 0 432 216이고 바깥 크기는 432pt × 216pt입니다.

외부 그림을 배치하는 동안 이 경계를 유지하세요. savefig 문서가 설명하듯 bbox_inches="tight"를 추가하면 저장 경계가 달라집니다. 여백을 꼭 맞게 자르려면 내보낸 viewBox를 확인하고 이후 합성 좌표를 갱신하세요.

svg.fonttype="none" 설정은 예제 레이블을 텍스트로 유지합니다. Matplotlib의 글꼴 문서는 SVG 텍스트와 경로 출력 선택을 설명합니다. 편집 가능한 텍스트는 실제 사용 환경에 적합한 글꼴이 있어야 합니다. 고정된 글자 모양이 필요하면 경로 출력을 의도적으로 선택하고 레이블 편집을 위해 그래프 소스를 보관하세요. SVG 글꼴 변경 가이드는 이 절충을 다룹니다.

래스터화하지 않고 그림 합성하기

이 직접 만든 배지를 plot.svg 옆에 badge.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>

그런 다음 아래 합성 스크립트를 실행하세요.

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")

svgutils 그림 합성 튜토리얼의 불러오기, 변환, 추가, 저장 방식을 따릅니다. svgutils 0.3.4가 지원하는 인수 scale_x를 사용했습니다. 이전 튜토리얼에는 다른 크기 조절 인수가 나옵니다.

100단위 배지 그림은 너비 64단위가 됩니다. 왼쪽 위 모서리는 그래프 좌표계의 (332, 76)에 있습니다. 바깥 크기와 viewBox를 명시해 이 예제의 배치를 분명하게 합니다. 이는 데이터 좌표가 아니라 페이지 좌표이므로 그래프의 데이터 지점을 이동해도 배지가 따라 움직이지는 않습니다.

변하는 데이터 지점에 연결된 주석에는 그래프 좌표를 내보낸 페이지 좌표에 의도적으로 매핑하거나 그 연결을 제공하는 합성 도구를 사용하세요. 고정 페이지 배치는 모서리 로고나 별도의 일러스트 패널에 적합합니다.

SVG 원본에는 경로 이외의 기능도 있을 수 있습니다. 이미 PNG를 삽입한 SVG는 합성해도 혼합 콘텐츠로 남습니다. 복잡한 파일을 합칠 때 참조 ID, 글꼴과 외부 링크 에셋도 확인하세요. 이 예제의 배지는 그런 의존성을 피합니다.

파일을 확인하고 수정 테스트하기

브라우저나 대상 편집기에서 vector-logo.svg를 여세요. 배지 중앙 구멍, 그래프 레이블과 그 사이 여백을 확인하세요. 확대뿐 아니라 실제 사용할 크기에서도 파일을 확인하세요.

간단한 XML 검사로 미리보기에 의존하지 않고 구조를 확인할 수 있습니다.

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)))

제공한 예제에서는 image 0, path 10, text 15가 출력됩니다. 래스터 비교에서는 그래프의 경로 8개를 유지하면서 image 1이 출력됩니다. 해당 비교의 이미지 참조에는 PNG 데이터가 들어 있습니다. 누락된 외부 로고 파일이 아니라 자체 포함된 래스터 콘텐츠입니다.

이제 plot.py에서 마지막 설명용 y값을 바꾸고 그래프와 합성을 다시 실행하세요. 그래프는 바뀌지만 배지는 확보한 페이지 위치에 남아 있어야 합니다. 이 수정 검사는 한 번은 올바르게 보이지만 오래된 그래프 내보내기에 의존하는 작업 흐름을 찾아냅니다.

다음 전달 단계는 별도로 확인하세요. 그림을 문서에 넣는다면 LaTeX SVG 작업 흐름이 내보내기와 레이블 선택을 설명합니다. 브라우저 미리보기가 성공했다고 학술지 요구사항 준수나 최종 PDF에서의 보존이 보장되는 것은 아닙니다.

복원이 필요한 그림만 복원하기

그래프 소스가 있다면 그 소스에서 내보내세요. 벡터화는 스크린샷에서 수치 데이터나 그래프 명령을 복원할 수 없습니다.

PerfectVector는 단순한 장식용 로고나 일러스트가 래스터로만 남은 경우에 적합합니다. 과학 그림 복원 작업 흐름으로 해당 그림만 자르고 벡터 후보를 미리 본 뒤 구멍, 얇은 모양과 원하지 않는 배경 영역을 확인하세요. 축, 측정 표식과 레이블은 추적에서 제외하세요. 검토를 통과한 그림 SVG를 네이티브 그래프와 합성하고 전달 파일 검사를 반복하세요.

벡터 원본이 있으면 항상 사용하세요. 추적에서 중요한 세부가 사라지면 단순한 표식은 직접 다시 그리세요. 사진 패널은 래스터로 유지하세요. 이미지 벡터화 개요는 추적을 선택하기 전에 무엇을 복원할 수 있는지 설명합니다.

FAQ

Matplotlib 그림을 SVG로 저장하면 PNG 로고도 벡터가 되나요? 아닙니다. 테스트한 OffsetImage 작업 흐름에서 그래프는 벡터 도형으로 내보내지지만 PNG 로고는 SVG 안의 이미지 요소로 남습니다.

SVG 로고를 데이터 좌표로 배치할 수 있나요? 여기서 보여 준 합성은 내보낸 페이지 좌표를 사용합니다. 데이터 지점에 연결된 로고에는 명시적 좌표 매핑이나 연결을 유지하는 도구가 필요합니다.

레이블이 경로로 바뀐 이유는 무엇인가요? Matplotlib의 SVG 글꼴 출력 설정이 레이블을 텍스트로 내보낼지 글리프 경로로 내보낼지 제어합니다. 내보내기 전에 설정을 고르고 이후 문구 변경을 위해 그래프 소스를 보관하세요.

Sources

  1. Matplotlib — savefig — 명시적 SVG 내보내기와 꼭 맞는 바운딩 박스의 영향을 설명합니다.
  2. Matplotlib — OffsetImage — 래스터 비교에 사용한 이미지 컨테이너의 동작을 설명합니다.
  3. Matplotlib — Matplotlib의 글꼴 — SVG 텍스트와 글리프 경로 출력 선택을 설명합니다.
  4. svgutils — 출판 품질 그림 만들기 — 별도 그래프 내보내기, SVG 합성, 변환과 완성한 그림 저장을 설명합니다.

그래프는 코드에서 내보내고 그림은 별도로 유지하세요. 장식 모티프가 래스터로만 남았다면 SVG 그림 후보를 준비하고 구멍과 경계를 확인하세요. 그래프와 합성한 뒤 실제 전달 파일의 픽셀, 배치와 레이블 변경을 확인하세요.

블로그의 다른 글

편집하기 쉬운
더 깔끔한 SVG로 다시 시작하세요