🌐 AI搜索 & 代理 主页
Skip to content

Commit a1ba476

Browse files
r3ksteImpaler343AdwaithBatchuSreekanth-M8SujalKumar06
committed
Revamp draw_path_collection() API.
Co-authored-by: Pranav <kingprawn5000@gmail.com> Co-authored-by: AdwaithBatchu <adwaithbatchu@gmail.com> Co-authored-by: Sreekanth-M8 <kmsreekanthsai@gmail.com> Co-authored-by: Sujal Kumar <sujaljayantkumar06@gmail.com>
1 parent de6e548 commit a1ba476

13 files changed

+772
-285
lines changed

lib/matplotlib/backend_bases.py

Lines changed: 313 additions & 42 deletions
Large diffs are not rendered by default.

lib/matplotlib/backend_bases.pyi

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,21 +61,20 @@ class RendererBase:
6161
) -> None: ...
6262
def draw_path_collection(
6363
self,
64-
gc: GraphicsContextBase,
64+
vgc: GraphicsContextBase | VectorizedGraphicsContextBase,
6565
master_transform: Transform,
6666
paths: Sequence[Path],
6767
all_transforms: Sequence[ArrayLike],
6868
offsets: ArrayLike | Sequence[ArrayLike],
6969
offset_trans: Transform,
70-
facecolors: ColorType | Sequence[ColorType],
71-
edgecolors: ColorType | Sequence[ColorType],
72-
linewidths: float | Sequence[float],
73-
linestyles: LineStyleType | Sequence[LineStyleType],
74-
antialiaseds: bool | Sequence[bool],
75-
urls: str | Sequence[str],
76-
offset_position: Any,
77-
*,
78-
hatchcolors: ColorType | Sequence[ColorType] | None = None,
70+
facecolors: ColorType | Sequence[ColorType] | None = ...,
71+
edgecolors: ColorType | Sequence[ColorType] | None = ...,
72+
linewidths: float | Sequence[float] | None = ...,
73+
linestyles: LineStyleType | Sequence[LineStyleType] | None = ...,
74+
antialiaseds: bool | Sequence[bool] | None = ...,
75+
urls: str | Sequence[str] | None = ...,
76+
offset_position: Any = ...,
77+
hatchcolors: ColorType | Sequence[ColorType] | None = ...,
7978
) -> None: ...
8079
def draw_quad_mesh(
8180
self,
@@ -137,6 +136,7 @@ class RendererBase:
137136
def get_canvas_width_height(self) -> tuple[float, float]: ...
138137
def get_texmanager(self) -> TexManager: ...
139138
def new_gc(self) -> GraphicsContextBase: ...
139+
def new_vgc(self) -> VectorizedGraphicsContextBase: ...
140140
def points_to_pixels(self, points: ArrayLike) -> ArrayLike: ...
141141
def start_rasterizing(self) -> None: ...
142142
def stop_rasterizing(self) -> None: ...
@@ -189,6 +189,60 @@ class GraphicsContextBase:
189189
randomness: float | None = ...,
190190
) -> None: ...
191191

192+
class VectorizedGraphicsContextBase:
193+
def __init__(self) -> None: ...
194+
def copy_properties(
195+
self,
196+
gc: GraphicsContextBase,
197+
facecolors: ColorType | Sequence[ColorType] | None,
198+
edgecolors: ColorType | Sequence[ColorType] | None,
199+
linewidths: float | Sequence[float] | None,
200+
linestyles: LineStyleType | Sequence[LineStyleType] | None,
201+
antialiaseds: bool | Sequence[bool] | None,
202+
urls: str | Sequence[str] | None,
203+
hatchcolors: ColorType | Sequence[ColorType] | None,
204+
) -> None: ...
205+
def get_alphas(self) -> list[float]: ...
206+
def get_forced_alphas(self) -> list[bool]: ...
207+
def get_antialiaseds(self) -> list[int]: ...
208+
def get_capstyles(self) -> list[Literal["butt", "projecting", "round"]]: ...
209+
def get_clip_rectangle(self) -> Bbox | None: ...
210+
def get_clip_path(
211+
self,
212+
) -> tuple[TransformedPath, Transform] | tuple[None, None]: ...
213+
def get_dashes(self) -> list[LineStyleType]: ...
214+
def get_joinstyles(self) -> list[Literal["miter", "round", "bevel"]]: ...
215+
def get_linewidths(self) -> list[float]: ...
216+
def get_edgecolors(self) -> list[ColorType]: ...
217+
def get_facecolors(self) -> list[ColorType]: ...
218+
def get_hatches(self) -> list[str | None]: ...
219+
def get_hatch_paths(self, density: float = ...) -> list[Path]: ...
220+
def get_hatch_colors(self) -> list[ColorType]: ...
221+
def get_hatch_linewidths(self) -> list[float]: ...
222+
def get_urls(self) -> list[str | None]: ...
223+
def get_gids(self) -> list[int | None]: ...
224+
def get_snaps(self) -> list[bool | None]: ...
225+
def get_sketches_params(self) -> list[tuple[float, float, float] | None]: ...
226+
def set_alphas(self, alphas: list[float]) -> None: ...
227+
def set_antialiaseds(self, antialiaseds: list[int]) -> None: ...
228+
def set_capstyles(self, capstyles: list[CapStyleType]) -> None: ...
229+
def set_clip_rectangle(self, rectangle: Bbox | None) -> None: ...
230+
def set_clip_path(self, path: TransformedPath | None) -> None: ...
231+
def set_dashes(self, dashes: list[tuple[float, ArrayLike | None]]) -> None: ...
232+
def set_joinstyles(self, joinstyles: list[JoinStyleType]) -> None: ...
233+
def set_linewidths(self, linewidths: list[float]) -> None: ...
234+
def set_edgecolors(self, edgecolors: list[ColorType], isRGBA: None = ...) -> None: ...
235+
def set_facecolors(self, facecolors: list[ColorType]) -> None: ...
236+
def set_urls(self, urls: list[str | None]) -> None: ...
237+
def set_gids(self, gids: list[int | None]) -> None: ...
238+
def set_snaps(self, snaps: list[bool | None]) -> None: ...
239+
def set_hatches(self, hatches: list[str | None]) -> None: ...
240+
def set_hatch_colors(self, hatchcolors: list[ColorType]) -> None: ...
241+
def set_hatch_linewidths(self, hatch_linewidths: list[float]) -> None: ...
242+
def set_sketches_params(
243+
self, sketches: list[tuple[float | None, float | None, float | None]]
244+
) -> None: ...
245+
192246
class TimerBase:
193247
callbacks: list[tuple[Callable, tuple, dict[str, Any]]]
194248
def __init__(

lib/matplotlib/backends/backend_pdf.py

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from matplotlib._pylab_helpers import Gcf
3131
from matplotlib.backend_bases import (
3232
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
33-
RendererBase)
33+
RendererBase, VectorizedGraphicsContextBase)
3434
from matplotlib.backends.backend_mixed import MixedModeRenderer
3535
from matplotlib.figure import Figure
3636
from matplotlib.font_manager import get_font, fontManager as _fontManager
@@ -2052,23 +2052,29 @@ def draw_path(self, gc, path, transform, rgbFace=None):
20522052
gc.get_sketch_params())
20532053
self.file.output(self.gc.paint())
20542054

2055-
def draw_path_collection(self, gc, master_transform, paths, all_transforms,
2056-
offsets, offset_trans, facecolors, edgecolors,
2057-
linewidths, linestyles, antialiaseds, urls,
2058-
offset_position, *, hatchcolors=None):
2055+
def draw_path_collection(self, vgc, master_transform, paths, all_transforms,
2056+
offsets, offset_trans, facecolors=None, edgecolors=None,
2057+
linewidths=None, linestyles=None, antialiaseds=None,
2058+
urls=None, offset_position=None, hatchcolors=None):
2059+
2060+
if hatchcolors is None:
2061+
hatchcolors = []
2062+
2063+
if isinstance(gc := vgc, GraphicsContextBase):
2064+
vgc = VectorizedGraphicsContextBase()
2065+
vgc.copy_properties(gc, facecolors, edgecolors, linewidths, linestyles,
2066+
antialiaseds, urls, hatchcolors)
2067+
20592068
# We can only reuse the objects if the presence of fill and
20602069
# stroke (and the amount of alpha for each) is the same for
20612070
# all of them
20622071
can_do_optimization = True
2063-
facecolors = np.asarray(facecolors)
2064-
edgecolors = np.asarray(edgecolors)
2065-
2066-
if hatchcolors is None:
2067-
hatchcolors = []
2072+
facecolors = np.asarray(vgc.get_facecolors())
2073+
edgecolors = np.asarray(vgc.get_edgecolors())
20682074

20692075
if not len(facecolors):
20702076
filled = False
2071-
can_do_optimization = not gc.get_hatch()
2077+
can_do_optimization = not vgc.get_hatches()
20722078
else:
20732079
if np.all(facecolors[:, 3] == facecolors[0, 3]):
20742080
filled = facecolors[0, 3] != 0.0
@@ -2091,21 +2097,27 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms,
20912097
# uses_per_path for the uses
20922098
len_path = len(paths[0].vertices) if len(paths) > 0 else 0
20932099
uses_per_path = self._iter_collection_uses_per_path(
2094-
paths, all_transforms, offsets, facecolors, edgecolors)
2100+
paths, all_transforms, offsets, vgc.get_facecolors(), vgc.get_edgecolors())
20952101
should_do_optimization = \
20962102
len_path + uses_per_path + 5 < len_path * uses_per_path
20972103

20982104
if (not can_do_optimization) or (not should_do_optimization):
20992105
return RendererBase.draw_path_collection(
2100-
self, gc, master_transform, paths, all_transforms,
2101-
offsets, offset_trans, facecolors, edgecolors,
2102-
linewidths, linestyles, antialiaseds, urls,
2103-
offset_position, hatchcolors=hatchcolors)
2106+
self, vgc, master_transform, paths, all_transforms,
2107+
offsets, offset_trans)
2108+
2109+
Njoinstyles = len(vgc._joinstyles)
2110+
Ncapstyles = len(vgc._capstyles)
21042111

2105-
padding = np.max(linewidths)
2112+
padding = np.max(vgc.get_linewidths())
21062113
path_codes = []
2114+
gc = self.new_gc()
21072115
for i, (path, transform) in enumerate(self._iter_collection_raw_paths(
21082116
master_transform, paths, all_transforms)):
2117+
if Njoinstyles:
2118+
gc.set_joinstyle(vgc.get_joinstyles()[i % Njoinstyles])
2119+
if Ncapstyles:
2120+
gc.set_capstyle(vgc.get_capstyles()[i % Ncapstyles])
21092121
name = self.file.pathCollectionObject(
21102122
gc, path, transform, padding, filled, stroked)
21112123
path_codes.append(name)
@@ -2114,9 +2126,7 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms,
21142126
output(*self.gc.push())
21152127
lastx, lasty = 0, 0
21162128
for xo, yo, path_id, gc0, rgbFace in self._iter_collection(
2117-
gc, path_codes, offsets, offset_trans,
2118-
facecolors, edgecolors, linewidths, linestyles,
2119-
antialiaseds, urls, offset_position, hatchcolors=hatchcolors):
2129+
vgc, path_codes, offsets, offset_trans):
21202130

21212131
self.check_gc(gc0, rgbFace)
21222132
dx, dy = xo - lastx, yo - lasty

lib/matplotlib/backends/backend_ps.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
import matplotlib as mpl
2626
from matplotlib import _api, cbook, _path, _text_helpers
2727
from matplotlib.backend_bases import (
28-
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase)
28+
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase, GraphicsContextBase,
29+
VectorizedGraphicsContextBase)
2930
from matplotlib.cbook import is_writable_file_like, file_requires_unicode
3031
from matplotlib.font_manager import get_font
3132
from matplotlib.ft2font import LoadFlags
@@ -670,28 +671,32 @@ def draw_markers(
670671
self._draw_ps(ps, gc, rgbFace, fill=False, stroke=False)
671672

672673
@_log_if_debug_on
673-
def draw_path_collection(self, gc, master_transform, paths, all_transforms,
674-
offsets, offset_trans, facecolors, edgecolors,
675-
linewidths, linestyles, antialiaseds, urls,
676-
offset_position, *, hatchcolors=None):
674+
def draw_path_collection(self, vgc, master_transform, paths, all_transforms,
675+
offsets, offset_trans, facecolors=None, edgecolors=None,
676+
linewidths=None, linestyles=None, antialiaseds=None,
677+
urls=None, offset_position=None, hatchcolors=None):
677678
if hatchcolors is None:
678679
hatchcolors = []
680+
681+
if isinstance(gc := vgc, GraphicsContextBase):
682+
vgc = VectorizedGraphicsContextBase()
683+
vgc.copy_properties(gc, facecolors, edgecolors, linewidths, linestyles,
684+
antialiaseds, urls, hatchcolors)
685+
679686
# Is the optimization worth it? Rough calculation:
680687
# cost of emitting a path in-line is
681688
# (len_path + 2) * uses_per_path
682689
# cost of definition+use is
683690
# (len_path + 3) + 3 * uses_per_path
684691
len_path = len(paths[0].vertices) if len(paths) > 0 else 0
685692
uses_per_path = self._iter_collection_uses_per_path(
686-
paths, all_transforms, offsets, facecolors, edgecolors)
693+
paths, all_transforms, offsets, vgc.get_facecolors(), vgc.get_edgecolors())
687694
should_do_optimization = \
688695
len_path + 3 * uses_per_path + 3 < (len_path + 2) * uses_per_path
689696
if not should_do_optimization:
690697
return RendererBase.draw_path_collection(
691-
self, gc, master_transform, paths, all_transforms,
692-
offsets, offset_trans, facecolors, edgecolors,
693-
linewidths, linestyles, antialiaseds, urls,
694-
offset_position, hatchcolors=hatchcolors)
698+
self, vgc, master_transform, paths, all_transforms,
699+
offsets, offset_trans)
695700

696701
path_codes = []
697702
for i, (path, transform) in enumerate(self._iter_collection_raw_paths(
@@ -708,9 +713,7 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms,
708713
path_codes.append(name)
709714

710715
for xo, yo, path_id, gc0, rgbFace in self._iter_collection(
711-
gc, path_codes, offsets, offset_trans,
712-
facecolors, edgecolors, linewidths, linestyles,
713-
antialiaseds, urls, offset_position, hatchcolors=hatchcolors):
716+
vgc, path_codes, offsets, offset_trans):
714717
ps = f"{xo:g} {yo:g} {path_id}"
715718
self._draw_ps(ps, gc0, rgbFace)
716719

lib/matplotlib/backends/backend_svg.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
import matplotlib as mpl
1717
from matplotlib import cbook, font_manager as fm
1818
from matplotlib.backend_bases import (
19-
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase)
19+
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase, GraphicsContextBase,
20+
VectorizedGraphicsContextBase)
2021
from matplotlib.backends.backend_mixed import MixedModeRenderer
2122
from matplotlib.colors import rgb2hex
2223
from matplotlib.dates import UTC
@@ -733,28 +734,34 @@ def draw_markers(
733734
self.writer.end('a')
734735
writer.end('g')
735736

736-
def draw_path_collection(self, gc, master_transform, paths, all_transforms,
737-
offsets, offset_trans, facecolors, edgecolors,
738-
linewidths, linestyles, antialiaseds, urls,
739-
offset_position, *, hatchcolors=None):
737+
def draw_path_collection(self, vgc, master_transform, paths, all_transforms,
738+
offsets, offset_trans, facecolors=None, edgecolors=None,
739+
linewidths=None, linestyles=None, antialiaseds=None,
740+
urls=None, offset_position=None, hatchcolors=None):
741+
740742
if hatchcolors is None:
741743
hatchcolors = []
744+
745+
if isinstance(gc := vgc, GraphicsContextBase):
746+
vgc = VectorizedGraphicsContextBase()
747+
vgc.copy_properties(gc, facecolors, edgecolors, linewidths, linestyles,
748+
antialiaseds, urls, hatchcolors)
749+
742750
# Is the optimization worth it? Rough calculation:
743751
# cost of emitting a path in-line is
744752
# (len_path + 5) * uses_per_path
745753
# cost of definition+use is
746754
# (len_path + 3) + 9 * uses_per_path
747755
len_path = len(paths[0].vertices) if len(paths) > 0 else 0
748756
uses_per_path = self._iter_collection_uses_per_path(
749-
paths, all_transforms, offsets, facecolors, edgecolors)
757+
paths, all_transforms, offsets, vgc.get_facecolors(), vgc.get_edgecolors())
750758
should_do_optimization = \
751759
len_path + 9 * uses_per_path + 3 < (len_path + 5) * uses_per_path
760+
752761
if not should_do_optimization:
753762
return super().draw_path_collection(
754-
gc, master_transform, paths, all_transforms,
755-
offsets, offset_trans, facecolors, edgecolors,
756-
linewidths, linestyles, antialiaseds, urls,
757-
offset_position, hatchcolors=hatchcolors)
763+
vgc, master_transform, paths, all_transforms,
764+
offsets, offset_trans)
758765

759766
writer = self.writer
760767
path_codes = []
@@ -770,9 +777,7 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms,
770777
writer.end('defs')
771778

772779
for xo, yo, path_id, gc0, rgbFace in self._iter_collection(
773-
gc, path_codes, offsets, offset_trans,
774-
facecolors, edgecolors, linewidths, linestyles,
775-
antialiaseds, urls, offset_position, hatchcolors=hatchcolors):
780+
vgc, path_codes, offsets, offset_trans):
776781
url = gc0.get_url()
777782
if url is not None:
778783
writer.start('a', attrib={'xlink:href': url})

0 commit comments

Comments
 (0)