Dấu điểm SVG trong Matplotlib: kiểm tra đường dẫn
Dùng đường dẫn SVG đơn giản làm dấu điểm scatter Matplotlib. Tái tạo kiểm tra căn giữa, hướng, lỗ và kích thước trong bản xuất SVG và PDF thực tế.
Trên trang này
Để dùng SVG làm dấu điểm scatter tùy chỉnh trong Matplotlib, chuyển hình học được hỗ trợ thành matplotlib.path.Path, căn giữa quanh (0, 0) và truyền đối tượng đó vào scatter(marker=...). Màu và cỡ dấu điểm sau đó do biểu đồ quyết định. API dấu điểm Matplotlib chấp nhận Path; nó không nhận tài liệu SVG tùy ý dưới dạng tên tệp dấu điểm.
Hướng dẫn này dùng đa giác bất đối xứng tự tạo có lỗ chữ nhật. Mã hoàn chỉnh bên dưới xử lý một tập con SVG chủ ý nhỏ và từ chối tính năng không thể giữ. Chúng tôi chạy với Matplotlib 3.10.7, kiểm tra đường dẫn SVG, PDF đã lưu và kiểm tra cả hai bản kết xuất.
Nếu muốn một minh họa bên cạnh biểu đồ xuất ra, dùng hướng dẫn kết hợp thiết kế SVG trong Matplotlib riêng. Dấu scatter lặp tại tọa độ dữ liệu nên tâm, hướng và kích thước cần kiểm tra khác.
1. Bắt đầu với một hình được hỗ trợ
Bạn cần Python có Matplotlib và NumPy, cùng quyền ghi thư mục đầu ra. Ví dụ gồm SVG tự tạo nên không cần tải biểu tượng. Ba tọa độ được vẽ là giá trị minh họa, không phải quan sát nghiên cứu.
Bộ phân tích chỉ nhận đúng một path tô đen trong phần tử gốc SVG có viewBox. Mỗi đường bao phải đóng bằng Z; mỗi cặp tọa độ cần lệnh viết hoa M hoặc L rõ ràng. Nó hỗ trợ đường dẫn phức hợp với đường bao ngoài và lỗ dùng hướng ngược nhau theo fill-rule="nonzero".
Nó từ chối đường cong, lệnh tương đối, phép biến đổi, nét, CSS, nhiều phần tử path, văn bản, cắt hiển thị, chuyển sắc và màu khác. Nó cũng từ chối thuộc tính gốc thêm như width và height. Giới hạn này giúp ví dụ kiểm tra được; đây không phải bộ nhập SVG tổng quát. Giữ bản thiết kế gốc chưa sửa trước khi chuẩn bị đầu vào tương thích.
Matplotlib Path lưu đỉnh và mã vẽ thay vì toàn bộ mô hình tô vẽ SVG. Path API định nghĩa thao tác di chuyển, đường thẳng và đóng dùng ở đây. Nếu biểu tượng cần nhiều màu hoặc hiệu ứng, chọn quy trình giữ chúng thay vì âm thầm bỏ để vừa bộ phân tích này.
2. Chạy ví dụ dấu điểm đầy đủ
Lưu thành scatter_marker.py, rồi chạy python scatter_marker.py trong cùng thư mục. Mã tạo marker-output/marker.svg, scatter.svg, scatter.pdf và bản xem PNG. Nguồn SVG được tạo cùng mọi cài đặt biểu đồ đều có ở đây.
from pathlib import Path as FilePath
import re
import xml.etree.ElementTree as ET
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.path import Path
import numpy as np
SVG = '''<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 80">
<path fill="#000000" fill-rule="nonzero"
d="M10 10 L70 10 L70 30 L90 30 L90 70 L10 70 Z
M25 25 L25 55 L45 55 L45 25 Z"/>
</svg>'''
def svg_marker(svg_text):
"""One black, nonzero-filled path; explicit absolute M/L/Z only."""
namespace = "{http://www.w3.org/2000/svg}"
root = ET.fromstring(svg_text)
if root.tag != namespace + "svg" or set(root.attrib) != {"viewBox"}:
raise ValueError("Use only an SVG root with a viewBox")
view = np.array([float(value) for value in root.attrib["viewBox"].split()])
if view.shape != (4,) or not np.isfinite(view).all() or (view[2:] <= 0).any():
raise ValueError("Invalid viewBox")
if len(root) != 1 or root[0].tag != namespace + "path":
raise ValueError("Use exactly one path, with no groups or other elements")
node = root[0]
if any((text or "").strip() for text in [root.text, node.text, node.tail]):
raise ValueError("Text content is not supported")
if set(node.attrib) - {"d", "fill", "fill-rule"} or len(node):
raise ValueError("Unsupported path attribute or child element")
if node.get("fill", "black") not in {"black", "#000", "#000000"}:
raise ValueError("Use one solid black fill")
if node.get("fill-rule", "nonzero") != "nonzero":
raise ValueError("Use nonzero winding; evenodd is not converted here")
data = node.get("d", "")
pattern = r"[MLZ]|[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?"
tokens = re.findall(pattern, data)
if re.sub(pattern, "", data).strip(" ,\n\r\t"):
raise ValueError("Only explicit absolute M, L and Z commands are supported")
vertices, codes = [], []
index, start, open_contour, lines = 0, None, False, 0
while index < len(tokens):
command = tokens[index]
if command in {"M", "L"}:
if index + 2 >= len(tokens) or tokens[index + 1] in {"M", "L", "Z"} or tokens[index + 2] in {"M", "L", "Z"}:
raise ValueError("Each M/L needs one explicit coordinate pair")
point = tuple(float(value) for value in tokens[index + 1:index + 3])
if not np.isfinite(point).all():
raise ValueError("Coordinates must be finite")
if command == "M":
if open_contour:
raise ValueError("Close each contour with Z")
start, open_contour, lines = point, True, 0
codes.append(Path.MOVETO)
else:
if not open_contour:
raise ValueError("Start each contour with M")
lines += 1
codes.append(Path.LINETO)
vertices.append(point)
index += 3
elif command == "Z":
if not open_contour or lines < 2:
raise ValueError("A closed contour needs at least three vertices")
vertices.append(start)
codes.append(Path.CLOSEPOLY)
open_contour = False
index += 1
else:
raise ValueError("Repeat M/L explicitly before coordinate pairs")
if open_contour or not vertices:
raise ValueError("Supply nonempty closed contours")
path = Path(np.array(vertices), codes)
box = path.get_extents()
if box.width <= 0 or box.height <= 0:
raise ValueError("Path needs nonzero width and height")
if box.x0 < view[0] or box.y0 < view[1] or box.x1 > view[0] + view[2] or box.y1 > view[1] + view[3]:
raise ValueError("Path outside viewBox: resolve clipping before import")
center = np.array([(box.x0 + box.x1) / 2, (box.y0 + box.y1) / 2])
centered = (path.vertices - center) * np.array([1, -1])
return Path(centered, path.codes)
if __name__ == "__main__":
output = FilePath("marker-output")
output.mkdir(exist_ok=True)
(output / "marker.svg").write_text(SVG)
marker = svg_marker(SVG)
plt.rcParams.update({"svg.fonttype": "none", "pdf.fonttype": 42,
"font.family": "DejaVu Sans", "font.size": 11})
fig, ax = plt.subplots(figsize=(8, 3), dpi=144)
fig.subplots_adjust(left=.1, right=.96, bottom=.24, top=.8)
ax.scatter([1, 2, 3], [1.3, 2.4, 1.6], s=[400, 1600, 3600],
marker=marker, color="#2f6977", linewidths=0, edgecolors="none")
ax.set(xlim=(0, 4), ylim=(0, 4), xlabel="Illustrative x", ylabel="Illustrative y",
title="Original SVG marker: s = 400, 1600, 3600 points squared")
ax.spines[["top", "right"]].set_visible(False)
fig.savefig(output / "scatter.svg", format="svg")
fig.savefig(output / "scatter.pdf", format="pdf")
fig.savefig(output / "scatter.png", format="png")
plt.close(fig)Mở cả scatter.svg và scatter.pdf. Bạn cần thấy ba bản xanh ngọc của cùng hình: lỗ chữ nhật bên trái và bậc nhô về phía dưới phải. So sánh dấu nhỏ nhất tại cỡ hiển thị dự kiến cũng như khi phóng lớn.

3. Kiểm tra tâm và lật Y một lần
Thiết kế nguồn chiếm x=10…90 và y=10…70. Tâm hộp giới hạn là (50, 40). Trừ tâm đó tạo giới hạn −40…40 theo ngang và −30…30 theo dọc. Đây là căn theo tâm hộp giới hạn, không phải trọng tâm hoặc ước lượng cân bằng thị giác.
Bậc dưới phải của nguồn hữu ích vì hình tròn đối xứng sẽ che việc lật dọc. Trong hệ tọa độ SVG ban đầu, Y dương hướng xuống. Mã đổi dấu Y một lần để giữ hướng hiển thị của nguồn trong biểu đồ Y hướng lên thông thường.
Cả hai đường bao nhận cùng phép biến đổi. Hướng tương đối vẫn ngược nhau nên khoảng chữ nhật vẫn là lỗ. Quy tắc tô nonzero SVG phụ thuộc hướng đường bao; nguồn evenodd bị từ chối rõ ràng ở đây thay vì coi tương đương.
Matplotlib sau đó chuẩn hóa Path đã căn giữa. Trong phiên bản thử, kết quả trải −0.5…0.5 theo X và −0.375…0.375 theo Y. Điểm đưa vào scatter nằm tại tâm các giới hạn đó. Bạn có thể chủ ý chọn neo khác cho biểu tượng đặc thù, nhưng đừng cho rằng góc trên trái SVG là neo dữ liệu phù hợp.
4. Đọc cỡ scatter theo point vuông
API scatter định nghĩa s theo point vuông, với một point kiểu chữ bằng 1/72 inch. Viền dấu điểm khác không có thể tăng kích thước nhìn thấy. Ví dụ đặt linewidths=0 và edgecolors="none" để kiểm tra cỡ tập trung vào hình học có tô.
Với dấu chuẩn hóa này, chiều rộng là một đơn vị dấu điểm và chiều cao 0,75 đơn vị. Vì vậy chiều rộng lưu là sqrt(s) point, chiều cao là 0.75 * sqrt(s) point.
s (point vuông) | Chiều rộng dự kiến và đo được | Chiều cao dự kiến và đo được |
|---|---|---|
| 400 | 20 pt | 15 pt |
| 1.600 | 40 pt | 30 pt |
| 3.600 | 60 pt | 45 pt |
Đây là kích thước của hình chuẩn hóa cụ thể này, không phải diện tích tô. Tỷ lệ khung hình, neo hoặc nét viền khác làm đổi quan hệ giữa tham số cỡ và biểu tượng nhìn thấy. Tăng s bốn lần làm kích thước gấp đôi trong ví dụ.
Chúng tôi kiểm tra tọa độ SVG thực đã lưu và các thao tác đường có tô của PDF với dung sai số 0,000001 point. Cả ba dấu có giới hạn, vị trí căn giữa điểm dữ liệu và đỉnh đã biến đổi đúng dự kiến. SVG lưu không có phần tử ảnh và PDF không có đối tượng ảnh.
Chúng tôi cũng kết xuất PDF đã lưu ở 144 dpi và kiểm tra ba vị trí bên trong đã nêu: lỗ trắng, khuyết trên phải trắng và phần nhô dưới phải xanh ngọc. Kết xuất gốc trong trình duyệt của SVG thực vượt qua cùng kiểm tra. Điều này xác minh hướng và khoảng trống đã chọn; không khẳng định mép khử răng cưa giống hệt giữa trình kết xuất hoặc hỗ trợ SVG tùy ý.
5. Sửa nguyên nhân trước khi chỉnh kích thước
| Triệu chứng | Kiểm tra và khắc phục |
|---|---|
| Bộ phân tích báo lỗi tính năng không hỗ trợ | Kiểm tra tính năng được nêu. Chuẩn bị đầu vào đa giác tương thích riêng hoặc dùng phương pháp chuyển đổi đầy đủ hơn và thử nó. Bỏ thuộc tính mà không giữ hiệu ứng có thể đổi hình. |
| Hình bị lộn ngược | Kiểm tra Y có bị đảo trước hàm này không. Áp dụng đổi tọa độ một lần rồi so sánh chi tiết bất đối xứng. |
| Biểu tượng lệch điểm dữ liệu | Kiểm tra giới hạn và neo đã chọn. Hàm căn giữa giới hạn hình bất kể khoảng trắng trong viewBox. |
| Lỗ bị tô kín | Kiểm tra hướng đường bao và quy tắc tô. Giữ hướng ngược nhau cho mẫu nonzero này; bộ phân tích không chuyển hình học evenodd. |
| Tệp đã lưu chứa biểu tượng raster | Kiểm tra phần tử hoặc tài nguyên xuất. Chỉ tên tệp SVG hay PDF không chứng minh mọi thành phần đồ thị là vector. |
| Dấu nhỏ mất chi tiết hữu ích | Xem hình ở cỡ cuối. Tăng dấu, đơn giản biểu tượng hoặc dùng dấu có sẵn nếu truyền đạt danh mục rõ hơn. |
Để kiểm tra tệp ngoài mẫu này, xem cách tìm nội dung raster trong SVG. Với cả hình, xem cỡ chữ và độ rộng nét ở kích thước xuất bản; đường dẫn dấu đúng vẫn có thể quá phức tạp cho chú giải nhỏ hoặc bảng hình chật.
Trước khi dùng dấu riêng trong hình hoàn chỉnh, kiểm tra cỡ nhỏ nhất, chú giải, các điểm chồng lấn và bản xuất SVG/PDF. Giữ dữ liệu biểu đồ, trục, nhãn và ánh xạ tỷ lệ trong quy trình vẽ. Biểu tượng tùy chỉnh không thay những định nghĩa số đó.
Khi thiết kế raster cần đường dẫn mới
Nếu chỉ còn biểu tượng là hình vẽ raster phẳng, quy trình sơ đồ khoa học sang SVG của PerfectVector có thể giúp khôi phục thiết kế chỉnh được. So sánh đường bao khôi phục và mọi khoảng trống với bản gốc trước khi thích ứng vào quy trình dấu điểm. Giữ SVG sạch sẵn có làm nguồn nếu bạn đã có.
Khôi phục vector không tái tạo dữ liệu nền của biểu đồ hoặc bảo đảm tương thích bộ phân tích giới hạn này. Giữ ảnh chụp và minh họa chuyển tông liên tục khi diện mạo raster là một phần hình, rồi chọn phương pháp đặt ảnh phù hợp nội dung đó.
Câu hỏi thường gặp
Có thể đưa thẳng tên tệp SVG vào Matplotlib scatter không? Không. API dấu điểm nhận các mô tả được hỗ trợ, gồm Matplotlib Path. Ví dụ chuyển đường dẫn SVG giới hạn thành đối tượng đó trước khi gọi scatter.
Vì sao dấu tùy chỉnh bị lộn ngược? SVG nguồn và biểu đồ có thể dùng hướng Y khác nhau. Ví dụ đổi dấu SVG Y một lần; kiểm tra chi tiết bất đối xứng để tránh lật hai lần.
s có bằng diện tích tô của hình SVG không? Đừng dùng nó như giá trị diện tích tô đo được. Scatter định nghĩa s theo point vuông, còn hình chuẩn hóa và nét viền xác định kích thước nhìn thấy. Mẫu này có chiều rộng 20, 40 và 60 point tại s 400, 1600 và 3600.
Mã này có giữ mọi tính năng SVG không? Không. Nó hỗ trợ một đường tô đen nonzero với lệnh tuyệt đối M, L và Z rõ ràng cùng đường bao kín. Cách tô, lệnh hình học, phép biến đổi và phần tử bổ sung không được hỗ trợ sẽ gây lỗi.
Nguồn
- Matplotlib scatter API — Định nghĩa tham số cỡ, đầu vào dấu và tương tác độ rộng viền.
- API dấu điểm Matplotlib 3.10.7 — Mô tả dấu Path và tọa độ dấu chuẩn hóa cho bản đã thử.
- Matplotlib Path API — Định nghĩa đỉnh, mã vẽ và đường bao kín.
- Hệ tọa độ SVG — Xác lập hướng tọa độ ban đầu dùng trong kiểm tra hướng.
- Quy tắc tô SVG — Giải thích hướng đường bao ảnh hưởng lỗ tô nonzero ra sao.
Với biểu tượng chỉ có raster, khôi phục thiết kế sơ đồ chỉnh được, so sánh đường bao và lỗ với nguồn rồi thử đường dẫn đã điều chỉnh trong hình thực trước khi bàn giao.
Thêm từ blog

SVG trong LaTeX: Giữ hình và dàn chữ nhãn minh họa
Chọn quy trình PDF hoặc PDF kèm LaTeX cho minh họa SVG. Giữ nhãn chỉnh sửa được, hiểu yêu cầu phụ thuộc vào Inkscape và kiểm tra PDF tài liệu cuối.

Bỏ qua vùng SVG trong suốt khi nhận nhấp chuột Konva
Cho vùng ảnh SVG trong suốt bỏ qua nhấp chuột trong Konva. Thử vùng tương tác dựa trên bộ đệm, kiểm tra lỗ và nền, rồi dựng lại sau khi đổi nguồn.
