Matplotlib'de SVG Nokta İşaretçileri: Yolu Kontrol Edin
Basit SVG yolunu Matplotlib scatter işaretçisi olarak kullanın. Gerçek SVG ve PDF çıktılarında merkez, yön, delik ve boyut kontrollerini tekrarlayın.
Bu sayfada
SVG'yi özel Matplotlib scatter işaretçisi olarak kullanmak için desteklenen geometriyi matplotlib.path.Path nesnesine dönüştürün, (0, 0) çevresinde ortalayın ve nesneyi scatter(marker=...) çağrısına geçirin. İşaretçinin rengi ve boyutu sonra grafikten gelir. Matplotlib'in işaretçi API'si Path kabul eder; rastgele SVG belgesini işaretçi dosya adı olarak almaz.
Bu öğretici dikdörtgen delikli özgün asimetrik çokgen kullanır. Aşağıdaki tam betik, bilinçli olarak küçük tutulmuş SVG alt kümesini işler ve koruyamadığı özellikleri reddeder. Matplotlib 3.10.7 ile çalıştırdık, kaydedilen SVG ve PDF yollarını inceleyip iki görüntü çıktısını kontrol ettik.
Dışa aktarılan grafiğin yanında tek çizim istiyorsanız ayrı Matplotlib SVG tasarım birleştirme rehberini kullanın. Scatter işaretçisi veri koordinatlarında tekrarlandığı için merkezi, yönü ve boyutu farklı kontrol gerektirir.
1. Desteklenen tek şekille başlayın
Matplotlib ve NumPy bulunan Python ve çıktı dizinine yazma izni gerekir. Örnek özgün SVG'sini içerir; simge indirmeniz gerekmez. Çizilen üç koordinat araştırma gözlemi değil, örnek değerlerdir.
Ayrıştırıcı, viewBox içeren SVG kökünde tam bir adet siyah dolgulu path kabul eder. Her kontur Z ile kapanmalıdır; her koordinat çifti açık büyük harf M veya L gerektirir. fill-rule="nonzero" altında ters yönlü dış kontur ve delik içeren bileşik yolu destekler.
Eğrileri, göreli komutları, dönüşümleri, konturları, CSS'yi, birden fazla path öğesini, metni, kırpmayı, gradyanları ve diğer renkleri reddeder. width ve height gibi ek kök özniteliklerini de reddeder. Bu kısıtlama örneği incelenebilir kılar; genel SVG içe aktarıcısı değildir. Uyumlu girdi hazırlamadan önce tasarımınızın dokunulmamış kopyasını saklayın.
Matplotlib Path, tam SVG boyama modeli yerine köşeler ve çizim kodları saklar. Path API'si, burada kullanılan taşıma, çizgi ve kapama işlemlerini tanımlar. Sembolünüz çok renk veya efekt gerektiriyorsa bunları ayrıştırıcıya uydurmak için sessizce atmak yerine koruyan iş akışı seçin.
2. Tam işaretçi örneğini çalıştırın
Bunu scatter_marker.py olarak kaydedip aynı dizinde python scatter_marker.py çalıştırın. marker-output/marker.svg, scatter.svg, scatter.pdf ve PNG önizlemesi oluşturur. Üretilen SVG kaynağı ve tüm grafik ayarları buraya dahildir.
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)Hem scatter.svg hem scatter.pdf dosyasını açın. Aynı şeklin üç turkuaz sürümünü görmelisiniz: solda dikdörtgen delik, sağ alta uzanan basamak. En küçük işaretçiyi büyütülmüş görünümün yanı sıra hedef gösterim boyutunda karşılaştırın.

3. Merkezi kontrol edip Y'yi bir kez çevirin
Kaynak tasarım x=10…90 ve y=10…70 aralığını kaplar. Sınırlayıcı kutu merkezi (50, 40) değeridir. Bu merkezi çıkarmak yatayda −40…40, dikeyde −30…30 sınırlarını verir. Bu sınırlayıcı kutuya göre ortalamadır; ağırlık merkezi veya görsel denge tahmini değildir.
Kaynağın sağ alt basamağı yararlıdır; simetrik daire dikey çevirmeyi gizlerdi. Başlangıç SVG koordinat sisteminde pozitif Y aşağıyı gösterir. Betik, normal yukarı Y grafiğinde kaynağın görünen yönünü korumak için Y'yi bir kez negatifler.
İki kontur da aynı dönüşümü alır. Göreli yönleri ters kaldığından dikdörtgen açıklık delik olarak kalır. SVG'nin nonzero dolgu kuralı kontur yönüne bağlıdır; evenodd kaynak burada eşdeğer sayılmak yerine açıkça reddedilir.
Matplotlib ardından ortalanmış Path'i normalleştirir. Test edilen sürümde sonuç X'te −0.5…0.5, Y'de −0.375…0.375 aralığına uzanır. scatter çağrısına verilen nokta bu sınırların merkezine düşer. Özel sembol için bilinçli başka bağlantı noktası seçebilirsiniz, ancak kaynak SVG'nin sol üst köşesinin uygun veri bağlantı noktası olduğunu varsaymayın.
4. Scatter boyutunu punto kare olarak okuyun
scatter API'si, s değerini punto kare olarak tanımlar; bir tipografik punto 1/72 inçtir. Sıfır olmayan işaretçi kenarı görünür boyutu büyütebilir. Örnek, boyut kontrolünü dolgulu geometriyle sınırlamak için linewidths=0 ve edgecolors="none" ayarlar.
Bu normalleştirilmiş işaretçide genişlik bir işaretçi birimi, yükseklik 0,75 birimdir. Dolayısıyla kaydedilen genişliği sqrt(s) punto, yüksekliği 0.75 * sqrt(s) puntodur.
s (punto kare) | Beklenen ve ölçülen genişlik | Beklenen ve ölçülen yükseklik |
|---|---|---|
| 400 | 20 pt | 15 pt |
| 1.600 | 40 pt | 30 pt |
| 3.600 | 60 pt | 45 pt |
Bunlar bu belirli normalleştirilmiş şeklin ölçüleridir; boyalı alanı değildir. Farklı en boy oranı, bağlantı noktası veya kenar konturu, boyut parametresiyle görünür sembol arasındaki ilişkiyi değiştirir. Bu örnekte s değerini dört kat artırmak ölçüleri ikiye katlar.
Gerçek kaydedilen SVG koordinatlarını ve PDF'nin dolgulu yol işlemlerini 0,000001 punto sayısal toleransla inceledik. Üç işaretçinin tamamında beklenen sınırlar, ortalanmış veri yerleşimi ve dönüştürülmüş köşeler vardı. Kaydedilen SVG görsel öğesi, PDF ise görsel nesnesi içermiyordu.
Kaydedilen PDF'yi 144 dpi'da görüntüleyip belirtilen üç iç konumu da kontrol ettik: delik beyaz, sağ üst çentik beyaz, sağ alt uzantı turkuazdı. Gerçek SVG'nin yerel tarayıcı görüntüsü aynı iç kontrolleri geçti. Bu, seçilen yönü ve açıklığı doğrular; görüntüleyicilerde aynı yumuşatılmış kenarları veya rastgele SVG tasarımlarını desteklediğini iddia etmez.
5. Boyutu ayarlamadan önce nedeni düzeltin
| Belirti | Kontrol ve düzeltme |
|---|---|
| Ayrıştırıcı desteklenmeyen özellik hatası veriyor | Adı verilen özelliği inceleyin. Ayrı uyumlu çokgen girdi hazırlayın veya daha kapsamlı dönüşüm yöntemi kullanıp test edin. Etkisini korumadan öznitelik silmek tasarımı değiştirebilir. |
| Şekil baş aşağı | Bu işlevden önce Y'nin zaten ters çevrilip çevrilmediğini kontrol edin. Koordinat değişimini bir kez uygulayıp asimetrik özelliği karşılaştırın. |
| Sembol veri noktasından uzakta | Sınırlarını ve seçilen bağlantı noktasını inceleyin. Bu işlev viewBox boşluğundan bağımsız olarak tasarım sınırlarını ortalar. |
| Delik doluyor | Kontur yönlerini ve dolgu kuralını inceleyin. Bu nonzero dolgulu örnekte ters yönleri koruyun; ayrıştırıcı evenodd geometrisini dönüştürmez. |
| Kaydedilen dosya raster sembol içeriyor | Dışa aktarılan öğeleri veya kaynakları inceleyin. SVG veya PDF dosya adı tek başına çizilen her öğenin vektör olduğunu kanıtlamaz. |
| Küçük işaretçiler yararlı ayrıntıyı kaybediyor | Görseli son boyutunda inceleyin. İşaretçiyi büyütün, sembolü sadeleştirin veya kategoriyi daha açık iletiyorsa yerleşik işaretçi kullanın. |
Bu örnek dışındaki dosya incelemesi için SVG içinde raster içerik bulmaya bakın. Bütün görsel için yayın boyutunda yazı boyutu ve çizgi kalınlığını inceleyin; doğru işaretçi yolu bile küçük açıklama veya kalabalık panel için fazla karmaşık olabilir.
Kendi işaretçinizi bitmiş görselde kullanmadan önce en küçük boyutunu, açıklama görünümünü, örtüşen noktaları ve SVG/PDF çıktısını kontrol edin. Grafik verilerini, eksenleri, etiketleri ve ölçek eşlemesini grafik iş akışınızda tutun. Özel simge bu sayısal tanımları değiştirmez.
Raster tasarım yeni yol gerektirdiğinde
Elde kalan tek sembol düz raster çizimse PerfectVector'ın bilimsel diyagramdan SVG'ye iş akışı, düzenlenebilir tasarımı geri kazanmaya yardımcı olabilir. İşaretçi sürecine uyarlamadan önce geri kazanılan dış hattı ve her açıklığı özgün tasarımla karşılaştırın. Temiz SVG'niz varsa kaynak olarak onu koruyun.
Vektör geri kazanma, grafiğin temel verisini yeniden kurmaz veya bu kısıtlı ayrıştırıcıyla uyumu garanti etmez. Raster görünümleri görselin parçasıysa fotoğrafları ve sürekli tonlu çizimleri koruyun; bu içeriğe uygun görsel yerleştirme yöntemi seçin.
Sık sorulan sorular
SVG dosya adını doğrudan Matplotlib scatter'a geçirebilir miyim? Hayır. İşaretçi API'si Matplotlib Path dahil desteklenen işaretçi tanımlarını kabul eder. Bu örnek scatter çağrısından önce kısıtlı SVG yolunu o nesneye dönüştürür.
Özel işaretçim neden baş aşağı? Kaynak SVG ve grafik farklı Y yönleri kullanabilir. Bu örnek SVG Y'sini bir kez negatifler; iki kez çevirmemek için asimetrik özelliği inceleyin.
s, SVG şeklimin boyalı alanına eşit mi? Ölçülmüş boyalı alan değeri olarak kullanmayın. Scatter s'yi punto kare olarak tanımlar; normalleştirilmiş şekil ve kenar konturu görünür ölçülerini belirler. Bu örnekte 400, 1600 ve 3600 s değerlerinde genişlikler 20, 40 ve 60 puntodur.
Bu kod her SVG özelliğini korur mu? Hayır. Açık mutlak M, L ve Z komutları ve kapalı konturlarla tek siyah nonzero dolgulu yolu destekler. Desteklenmeyen boya, geometri komutları, dönüşümler ve ek öğeler hata verir.
Kaynaklar
- Matplotlib scatter API — Boyut parametresini, işaretçi girdisini ve kenar kalınlığı etkileşimini tanımlar.
- Matplotlib 3.10.7 işaretçi API'si — Test edilen sürüm için Path işaretçilerini ve normalleştirilmiş işaretçi koordinatlarını belgeler.
- Matplotlib Path API — Köşeleri, çizim kodlarını ve kapalı konturları tanımlar.
- SVG koordinat sistemleri — Yön kontrolünde kullanılan başlangıç koordinat yönlerini belirler.
- SVG dolgu kuralları — Kontur yönünün nonzero dolgulu açıklığı nasıl etkilediğini açıklar.
Yalnızca raster sembol için düzenlenebilir diyagram tasarımını geri kazanın, dış hattını ve deliklerini kaynakla karşılaştırın, ardından teslimden önce uyarlanmış yolu gerçek görselinizde test edin.
Bloga daha fazlası

LaTeX'te SVG: Şekilleri koruyun, etiketleri dizin
SVG çiziminiz için PDF veya PDF ve LaTeX iş akışını seçin. Etiketleri düzenlenebilir tutun, Inkscape bağımlılıklarını anlayın ve belgenin son PDF'sini kontrol edin.

Konva Tıklamalarında Şeffaf SVG Alanlarını Yok Sayın
Konva'da şeffaf SVG alanlarının tıklamaları geçirmesini sağlayın. Önbellek tabanlı isabeti, delikleri ve zeminleri test edip kaynak değişince alanı yeniden oluşturun.
