Matplotlib में SVG स्कैटर मार्कर: पाथ जाँचें
सरल SVG पाथ को Matplotlib स्कैटर मार्कर बनाएँ। वास्तविक SVG और PDF निर्यात में केंद्र, दिशा, छेद और आकार की जाँच दोहराएँ।
इस पेज पर
SVG को कस्टम Matplotlib स्कैटर मार्कर बनाने के लिए समर्थित ज्यामिति matplotlib.path.Path में बदलें, उसे (0, 0) के आसपास केंद्रित करें और वह ऑब्जेक्ट scatter(marker=...) को दें। मार्कर का रंग और आकार फिर प्लॉट से आता है। Matplotlib का मार्कर API Path स्वीकारता है; मनमाना SVG दस्तावेज़ मार्कर फ़ाइलनाम की तरह नहीं लेता।
ट्यूटोरियल आयताकार छेद वाला मूल असममित बहुभुज लेता है। नीचे की पूरी स्क्रिप्ट जानबूझकर छोटा SVG उपसमूह संभालती है और जो नहीं बचा सकती उसे नकारती है। हमने Matplotlib 3.10.7 से चलाकर सहेजे SVG और PDF पाथ तथा दोनों रेंडर देखे।
निर्यातित चार्ट के पास एक चित्र चाहिए तो अलग Matplotlib SVG आर्टवर्क संयोजन गाइड लें। स्कैटर मार्कर डेटा निर्देशांकों पर दोहरता है, इसलिए केंद्र, दिशा और आकार अलग जाँचें।
1. एक समर्थित आकृति से शुरू करें
Python में Matplotlib और NumPy तथा आउटपुट फ़ोल्डर लिखने की अनुमति चाहिए। उदाहरण में मूल SVG है, आइकन डाउनलोड नहीं करना। प्लॉट के तीन निर्देशांक उदाहरण मान हैं, शोध अवलोकन नहीं।
पार्सर viewBox वाले SVG रूट में ठीक एक काले फ़िल वाला path लेता है। हर कंटूर Z से बंद हो और हर निर्देशांक जोड़ी से पहले स्पष्ट बड़ा M या L हो। fill-rule="nonzero" में विपरीत दिशा वाले बाहरी कंटूर और छेद का कंपाउंड पाथ समर्थित है।
यह वक्र, relative कमांड, ट्रांसफ़ॉर्म, स्ट्रोक, CSS, कई पाथ एलिमेंट, टेक्स्ट, क्लिपिंग, ग्रेडिएंट और अन्य रंग नकारता है। width तथा height जैसे अतिरिक्त रूट गुण भी नहीं लेता। सीमाएँ उदाहरण जाँचने योग्य बनाती हैं; यह सामान्य SVG आयातक नहीं। संगत इनपुट बनाने से पहले आर्टवर्क की अछूती कॉपी रखें।
Matplotlib Path पूरे SVG रंग मॉडल के बजाय शीर्ष और ड्रॉइंग कोड रखता है। Path API यहाँ के move, line और close ऑपरेशन तय करता है। प्रतीक को कई रंग या प्रभाव चाहिए तो उन्हें सुरक्षित रखने वाला तरीका चुनें, पार्सर में फिट करने के लिए चुपचाप न हटाएँ।
2. पूरा मार्कर उदाहरण चलाएँ
इसे scatter_marker.py सहेजें, फिर उसी फ़ोल्डर में python scatter_marker.py चलाएँ। यह marker-output/marker.svg, scatter.svg, scatter.pdf और PNG प्रीव्यू बनाता है। बना SVG स्रोत और सारी प्लॉट सेटिंग यहाँ हैं।
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)scatter.svg और scatter.pdf दोनों खोलें। उसी आकृति के तीन नीले-हरे रूप दिखें: बाएँ आयताकार छेद और नीचे-दाएँ बढ़ती सीढ़ी। सबसे छोटे मार्कर को इच्छित प्रदर्शन आकार और बड़े दृश्य दोनों पर मिलाएँ।

3. केंद्र जाँचें और Y एक बार पलटें
स्रोत आर्टवर्क x=10…90 और y=10…70 में है। बाउंडिंग-बॉक्स केंद्र (50, 40) है। उसे घटाने से क्षैतिज सीमा −40…40 और लंबवत −30…30 होती है। यह बाउंडिंग-बॉक्स केंद्र है, क्षेत्रफल-केंद्र या दृश्य संतुलन अनुमान नहीं।
नीचे-दाएँ की सीढ़ी उपयोगी है क्योंकि सममित गोला लंबवत पलटाव छिपाता। मूल SVG निर्देशांक तंत्र में धनात्मक Y नीचे जाता है। स्क्रिप्ट सामान्य ऊपर-Y प्लॉट में स्रोत की दिखाई दिशा बचाने के लिए Y एक बार ऋणात्मक करती है।
दोनों कंटूर पर समान परिवर्तन लगता है। उनकी सापेक्ष घुमाव दिशा विपरीत रहती है, इसलिए आयताकार छेद खुला रहता है। SVG का nonzero फ़िल नियम कंटूर दिशा पर निर्भर है; evenodd स्रोत को बराबर मानने के बजाय यहाँ स्पष्ट नकारते हैं।
Matplotlib फिर केंद्रित Path सामान्यीकृत करता है। जाँचे संस्करण में X सीमा −0.5…0.5 और Y −0.375…0.375 है। scatter को दिया बिंदु उन सीमाओं के केंद्र पर आता है। विशेष प्रतीक के लिए अन्य anchor जानबूझकर चुन सकते हैं, लेकिन स्रोत SVG का ऊपर-बायाँ कोना उचित डेटा anchor न मानें।
4. स्कैटर आकार पॉइंट के वर्ग में पढ़ें
scatter API s को पॉइंट के वर्ग में बताता है, एक टाइपोग्राफ़िक पॉइंट 1/72 इंच है। गैर-शून्य किनारा दिखती सीमा बढ़ा सकता है। उदाहरण linewidths=0 और edgecolors="none" रखता है ताकि आकार जाँच केवल भरी ज्यामिति की हो।
इस सामान्यीकृत मार्कर में चौड़ाई एक मार्कर इकाई और ऊँचाई 0.75 इकाई है। इसलिए सहेजी चौड़ाई sqrt(s) पॉइंट और ऊँचाई 0.75 * sqrt(s) पॉइंट है।
s (पॉइंट वर्ग) | अपेक्षित और मापी चौड़ाई | अपेक्षित और मापी ऊँचाई |
|---|---|---|
| 400 | 20 pt | 15 pt |
| 1,600 | 40 pt | 30 pt |
| 3,600 | 60 pt | 45 pt |
ये इसी सामान्यीकृत आकृति के आयाम हैं, उसका रंगा क्षेत्रफल नहीं। अलग अनुपात, anchor या किनारा स्ट्रोक आकार पैरामीटर और दिखते प्रतीक का संबंध बदलता है। इस उदाहरण में s चार गुना करने से आयाम दोगुने होते हैं।
हमने वास्तविक सहेजे SVG निर्देशांक और PDF के भरे-पाथ ऑपरेशन 0.000001 पॉइंट टॉलरेंस से देखे। तीनों मार्कर में अपेक्षित सीमा, केंद्रित डेटा स्थिति और बदले शीर्ष थे। SVG में इमेज एलिमेंट और PDF में इमेज ऑब्जेक्ट नहीं थे।
सहेजा PDF 144 dpi पर रेंडर करके तीन तय भीतरी जगहें देखीं: छेद सफ़ेद, ऊपर-दाएँ कटाव सफ़ेद और नीचे-दाएँ विस्तार नीला-हरा था। वास्तविक SVG का मूल ब्राउज़र रेंडर उन्हीं जाँचों में सही था। इससे चुनी दिशा और छेद जाँचते हैं; रेंडररों में समान एंटीएलियास किनारे या मनमाने SVG समर्थन का दावा नहीं।
5. आकार बदलने से पहले कारण सुधारें
| लक्षण | जाँच और सुधार |
|---|---|
| पार्सर असमर्थित सुविधा त्रुटि दे | उस सुविधा को देखें। अलग संगत बहुभुज इनपुट बनाएँ या अधिक पूर्ण परिवर्तन तरीका जाँचें। प्रभाव बचाए बिना गुण हटाने से आर्टवर्क बदल सकता है। |
| आकृति उलटी हो | देखें कि फ़ंक्शन से पहले Y पलटा था क्या। बदलाव एक बार लगाएँ और असममित विवरण मिलाएँ। |
| प्रतीक डेटा बिंदु से दूर हो | सीमा और चुना anchor देखें। फ़ंक्शन viewBox की खाली जगह से स्वतंत्र आर्टवर्क सीमा केंद्रित करता है। |
| छेद भर जाए | कंटूर दिशा और फ़िल नियम देखें। इस nonzero नमूने में विपरीत दिशा रखें; पार्सर evenodd ज्यामिति नहीं बदलता। |
| सहेजी फ़ाइल में रास्टर प्रतीक हो | निर्यातित एलिमेंट या संसाधन देखें। केवल SVG/PDF नाम हर प्लॉट तत्व के वेक्टर होने का प्रमाण नहीं। |
| छोटे मार्कर उपयोगी विवरण खो दें | अंतिम आकार पर चित्र देखें। मार्कर बढ़ाएँ, प्रतीक सरल करें या श्रेणी स्पष्ट बताने वाला तैयार मार्कर लें। |
इस उदाहरण से बाहर फ़ाइल जाँच के लिए SVG के भीतर रास्टर ढूँढना देखें। पूरे चित्र के लिए प्रकाशन आकार पर फ़ॉन्ट आकार और रेखा चौड़ाई पढ़ें; सही पाथ भी छोटी legend या भरे पैनल में जटिल हो सकता है।
अंतिम चित्र में अपना मार्कर लेने से पहले सबसे छोटा आकार, legend रूप, ओवरलैप बिंदु और निर्यातित SVG/PDF देखें। डेटा, अक्ष, लेबल और स्केल मैपिंग अपने प्लॉट कार्यप्रवाह में रखें। कस्टम आइकन इन संख्यात्मक परिभाषाओं की जगह नहीं।
जब रास्टर आर्टवर्क को नया पाथ चाहिए
एकमात्र बचा प्रतीक सपाट रास्टर हो तो PerfectVector का वैज्ञानिक आरेख से SVG कार्यप्रवाह संपादन योग्य आर्टवर्क वापस दे सकता है। मार्कर प्रक्रिया में लेने से पहले रूपरेखा और हर छेद मूल से मिलाएँ। साफ़ SVG पहले से हो तो उसी को स्रोत रखें।
वेक्टर रिकवरी चार्ट का मूल डेटा नहीं बनाती या इस सीमित पार्सर की संगतता नहीं देती। फ़ोटो और निरंतर-टोन चित्र का रास्टर रूप ज़रूरी हो तो उसे रखें और उपयुक्त इमेज-आधारित placement तरीका चुनें।
अक्सर पूछे जाने वाले सवाल
क्या SVG फ़ाइलनाम सीधे Matplotlib scatter को दे सकता हूँ? नहीं। मार्कर API समर्थित विवरण और Matplotlib Path लेता है। उदाहरण scatter से पहले सीमित SVG पाथ को उस ऑब्जेक्ट में बदलता है।
कस्टम मार्कर उलटा क्यों है? SVG और प्लॉट की Y दिशा अलग हो सकती है। उदाहरण SVG Y एक बार ऋणात्मक करता है; दो बार पलटने से बचने के लिए असममित विवरण देखें।
क्या s मेरे SVG का रंगा क्षेत्रफल है? उसे मापा रंगा क्षेत्रफल न मानें। Scatter में s पॉइंट वर्ग है, जबकि सामान्यीकृत आकृति और किनारा स्ट्रोक दिखते आयाम तय करते हैं। इस नमूने की चौड़ाई s = 400, 1600, 3600 पर 20, 40, 60 पॉइंट है।
क्या कोड हर SVG सुविधा बचाता है? नहीं। यह स्पष्ट absolute M, L, Z और बंद कंटूर वाला एक काला nonzero-भरा पाथ लेता है। असमर्थित रंगाई, ज्यामिति कमांड, ट्रांसफ़ॉर्म और अतिरिक्त एलिमेंट त्रुटि देते हैं।
स्रोत
- Matplotlib scatter API — आकार पैरामीटर, मार्कर इनपुट और किनारा चौड़ाई का संबंध।
- Matplotlib 3.10.7 मार्कर API — जाँचे संस्करण के Path मार्कर और सामान्यीकृत निर्देशांक।
- Matplotlib Path API — शीर्ष, ड्रॉइंग कोड और बंद कंटूर।
- SVG निर्देशांक तंत्र — दिशा जाँच की मूल निर्देशांक दिशाएँ।
- SVG फ़िल नियम — कंटूर दिशा का nonzero छेद पर प्रभाव।
केवल रास्टर प्रतीक हो तो संपादन योग्य आरेख आर्टवर्क वापस पाएँ, रूपरेखा और छेद स्रोत से मिलाएँ और डिलीवरी से पहले असली चित्र में बदला पाथ जाँचें।
Blog से और

LaTeX में SVG: आकार रखें, फ़िगर लेबल टाइपसेट करें
SVG चित्र के लिए PDF या PDF तथा LaTeX कार्यप्रवाह चुनें। लेबल संपादन योग्य रखें, Inkscape निर्भरताएँ समझें और अंतिम दस्तावेज़ PDF जाँचें।

Konva हिट जाँच में पारदर्शी SVG क्षेत्र छोड़ें
Konva में पारदर्शी SVG इमेज क्षेत्र क्लिक न पकड़ें। कैश आधारित हिट जाँच दोहराएँ, छेद व बैकग्राउंड जाँचें और स्रोत बदलने पर हिट फिर बनाएँ।
