🌐 AI搜索 & 代理 主页
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
355 changes: 313 additions & 42 deletions lib/matplotlib/backend_bases.py

Large diffs are not rendered by default.

74 changes: 64 additions & 10 deletions lib/matplotlib/backend_bases.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,20 @@ class RendererBase:
) -> None: ...
def draw_path_collection(
self,
gc: GraphicsContextBase,
vgc: GraphicsContextBase | VectorizedGraphicsContextBase,
master_transform: Transform,
paths: Sequence[Path],
all_transforms: Sequence[ArrayLike],
offsets: ArrayLike | Sequence[ArrayLike],
offset_trans: Transform,
facecolors: ColorType | Sequence[ColorType],
edgecolors: ColorType | Sequence[ColorType],
linewidths: float | Sequence[float],
linestyles: LineStyleType | Sequence[LineStyleType],
antialiaseds: bool | Sequence[bool],
urls: str | Sequence[str],
offset_position: Any,
*,
hatchcolors: ColorType | Sequence[ColorType] | None = None,
facecolors: ColorType | Sequence[ColorType] | None = ...,
edgecolors: ColorType | Sequence[ColorType] | None = ...,
linewidths: float | Sequence[float] | None = ...,
linestyles: LineStyleType | Sequence[LineStyleType] | None = ...,
antialiaseds: bool | Sequence[bool] | None = ...,
urls: str | Sequence[str] | None = ...,
offset_position: Any = ...,
hatchcolors: ColorType | Sequence[ColorType] | None = ...,
) -> None: ...
def draw_quad_mesh(
self,
Expand Down Expand Up @@ -137,6 +136,7 @@ class RendererBase:
def get_canvas_width_height(self) -> tuple[float, float]: ...
def get_texmanager(self) -> TexManager: ...
def new_gc(self) -> GraphicsContextBase: ...
def new_vgc(self) -> VectorizedGraphicsContextBase: ...
def points_to_pixels(self, points: ArrayLike) -> ArrayLike: ...
def start_rasterizing(self) -> None: ...
def stop_rasterizing(self) -> None: ...
Expand Down Expand Up @@ -189,6 +189,60 @@ class GraphicsContextBase:
randomness: float | None = ...,
) -> None: ...

class VectorizedGraphicsContextBase:
def __init__(self) -> None: ...
def copy_properties(
self,
gc: GraphicsContextBase,
facecolors: ColorType | Sequence[ColorType] | None,
edgecolors: ColorType | Sequence[ColorType] | None,
linewidths: float | Sequence[float] | None,
linestyles: LineStyleType | Sequence[LineStyleType] | None,
antialiaseds: bool | Sequence[bool] | None,
urls: str | Sequence[str] | None,
hatchcolors: ColorType | Sequence[ColorType] | None,
) -> None: ...
def get_alphas(self) -> list[float]: ...
def get_forced_alphas(self) -> list[bool]: ...
def get_antialiaseds(self) -> list[int]: ...
def get_capstyles(self) -> list[Literal["butt", "projecting", "round"]]: ...
def get_clip_rectangle(self) -> Bbox | None: ...
def get_clip_path(
self,
) -> tuple[TransformedPath, Transform] | tuple[None, None]: ...
def get_dashes(self) -> list[LineStyleType]: ...
def get_joinstyles(self) -> list[Literal["miter", "round", "bevel"]]: ...
def get_linewidths(self) -> list[float]: ...
def get_edgecolors(self) -> list[ColorType]: ...
def get_facecolors(self) -> list[ColorType]: ...
def get_hatches(self) -> list[str | None]: ...
def get_hatch_paths(self, density: float = ...) -> list[Path]: ...
def get_hatch_colors(self) -> list[ColorType]: ...
def get_hatch_linewidths(self) -> list[float]: ...
def get_urls(self) -> list[str | None]: ...
def get_gids(self) -> list[int | None]: ...
def get_snaps(self) -> list[bool | None]: ...
def get_sketches_params(self) -> list[tuple[float, float, float] | None]: ...
def set_alphas(self, alphas: list[float]) -> None: ...
def set_antialiaseds(self, antialiaseds: list[int]) -> None: ...
def set_capstyles(self, capstyles: list[CapStyleType]) -> None: ...
def set_clip_rectangle(self, rectangle: Bbox | None) -> None: ...
def set_clip_path(self, path: TransformedPath | None) -> None: ...
def set_dashes(self, dashes: list[tuple[float, ArrayLike | None]]) -> None: ...
def set_joinstyles(self, joinstyles: list[JoinStyleType]) -> None: ...
def set_linewidths(self, linewidths: list[float]) -> None: ...
def set_edgecolors(self, edgecolors: list[ColorType], isRGBA: None = ...) -> None: ...
def set_facecolors(self, facecolors: list[ColorType]) -> None: ...
def set_urls(self, urls: list[str | None]) -> None: ...
def set_gids(self, gids: list[int | None]) -> None: ...
def set_snaps(self, snaps: list[bool | None]) -> None: ...
def set_hatches(self, hatches: list[str | None]) -> None: ...
def set_hatch_colors(self, hatchcolors: list[ColorType]) -> None: ...
def set_hatch_linewidths(self, hatch_linewidths: list[float]) -> None: ...
def set_sketches_params(
self, sketches: list[tuple[float | None, float | None, float | None]]
) -> None: ...

class TimerBase:
callbacks: list[tuple[Callable, tuple, dict[str, Any]]]
def __init__(
Expand Down
50 changes: 30 additions & 20 deletions lib/matplotlib/backends/backend_pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from matplotlib._pylab_helpers import Gcf
from matplotlib.backend_bases import (
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
RendererBase)
RendererBase, VectorizedGraphicsContextBase)
from matplotlib.backends.backend_mixed import MixedModeRenderer
from matplotlib.figure import Figure
from matplotlib.font_manager import get_font, fontManager as _fontManager
Expand Down Expand Up @@ -2052,23 +2052,29 @@ def draw_path(self, gc, path, transform, rgbFace=None):
gc.get_sketch_params())
self.file.output(self.gc.paint())

def draw_path_collection(self, gc, master_transform, paths, all_transforms,
offsets, offset_trans, facecolors, edgecolors,
linewidths, linestyles, antialiaseds, urls,
offset_position, *, hatchcolors=None):
def draw_path_collection(self, vgc, master_transform, paths, all_transforms,
offsets, offset_trans, facecolors=None, edgecolors=None,
linewidths=None, linestyles=None, antialiaseds=None,
urls=None, offset_position=None, hatchcolors=None):

if hatchcolors is None:
hatchcolors = []

if isinstance(gc := vgc, GraphicsContextBase):
vgc = VectorizedGraphicsContextBase()
vgc.copy_properties(gc, facecolors, edgecolors, linewidths, linestyles,
antialiaseds, urls, hatchcolors)

# We can only reuse the objects if the presence of fill and
# stroke (and the amount of alpha for each) is the same for
# all of them
can_do_optimization = True
facecolors = np.asarray(facecolors)
edgecolors = np.asarray(edgecolors)

if hatchcolors is None:
hatchcolors = []
facecolors = np.asarray(vgc.get_facecolors())
edgecolors = np.asarray(vgc.get_edgecolors())

if not len(facecolors):
filled = False
can_do_optimization = not gc.get_hatch()
can_do_optimization = not vgc.get_hatches()
else:
if np.all(facecolors[:, 3] == facecolors[0, 3]):
filled = facecolors[0, 3] != 0.0
Expand All @@ -2091,21 +2097,27 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms,
# uses_per_path for the uses
len_path = len(paths[0].vertices) if len(paths) > 0 else 0
uses_per_path = self._iter_collection_uses_per_path(
paths, all_transforms, offsets, facecolors, edgecolors)
paths, all_transforms, offsets, vgc.get_facecolors(), vgc.get_edgecolors())
should_do_optimization = \
len_path + uses_per_path + 5 < len_path * uses_per_path

if (not can_do_optimization) or (not should_do_optimization):
return RendererBase.draw_path_collection(
self, gc, master_transform, paths, all_transforms,
offsets, offset_trans, facecolors, edgecolors,
linewidths, linestyles, antialiaseds, urls,
offset_position, hatchcolors=hatchcolors)
self, vgc, master_transform, paths, all_transforms,
offsets, offset_trans)

Njoinstyles = len(vgc._joinstyles)
Ncapstyles = len(vgc._capstyles)

padding = np.max(linewidths)
padding = np.max(vgc.get_linewidths())
path_codes = []
gc = self.new_gc()
for i, (path, transform) in enumerate(self._iter_collection_raw_paths(
master_transform, paths, all_transforms)):
if Njoinstyles:
gc.set_joinstyle(vgc.get_joinstyles()[i % Njoinstyles])
if Ncapstyles:
gc.set_capstyle(vgc.get_capstyles()[i % Ncapstyles])
name = self.file.pathCollectionObject(
gc, path, transform, padding, filled, stroked)
path_codes.append(name)
Expand All @@ -2114,9 +2126,7 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms,
output(*self.gc.push())
lastx, lasty = 0, 0
for xo, yo, path_id, gc0, rgbFace in self._iter_collection(
gc, path_codes, offsets, offset_trans,
facecolors, edgecolors, linewidths, linestyles,
antialiaseds, urls, offset_position, hatchcolors=hatchcolors):
vgc, path_codes, offsets, offset_trans):

self.check_gc(gc0, rgbFace)
dx, dy = xo - lastx, yo - lasty
Expand Down
29 changes: 16 additions & 13 deletions lib/matplotlib/backends/backend_ps.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
import matplotlib as mpl
from matplotlib import _api, cbook, _path, _text_helpers
from matplotlib.backend_bases import (
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase)
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase, GraphicsContextBase,
VectorizedGraphicsContextBase)
from matplotlib.cbook import is_writable_file_like, file_requires_unicode
from matplotlib.font_manager import get_font
from matplotlib.ft2font import LoadFlags
Expand Down Expand Up @@ -670,28 +671,32 @@ def draw_markers(
self._draw_ps(ps, gc, rgbFace, fill=False, stroke=False)

@_log_if_debug_on
def draw_path_collection(self, gc, master_transform, paths, all_transforms,
offsets, offset_trans, facecolors, edgecolors,
linewidths, linestyles, antialiaseds, urls,
offset_position, *, hatchcolors=None):
def draw_path_collection(self, vgc, master_transform, paths, all_transforms,
offsets, offset_trans, facecolors=None, edgecolors=None,
linewidths=None, linestyles=None, antialiaseds=None,
urls=None, offset_position=None, hatchcolors=None):
if hatchcolors is None:
hatchcolors = []

if isinstance(gc := vgc, GraphicsContextBase):
vgc = VectorizedGraphicsContextBase()
vgc.copy_properties(gc, facecolors, edgecolors, linewidths, linestyles,
antialiaseds, urls, hatchcolors)

# Is the optimization worth it? Rough calculation:
# cost of emitting a path in-line is
# (len_path + 2) * uses_per_path
# cost of definition+use is
# (len_path + 3) + 3 * uses_per_path
len_path = len(paths[0].vertices) if len(paths) > 0 else 0
uses_per_path = self._iter_collection_uses_per_path(
paths, all_transforms, offsets, facecolors, edgecolors)
paths, all_transforms, offsets, vgc.get_facecolors(), vgc.get_edgecolors())
should_do_optimization = \
len_path + 3 * uses_per_path + 3 < (len_path + 2) * uses_per_path
if not should_do_optimization:
return RendererBase.draw_path_collection(
self, gc, master_transform, paths, all_transforms,
offsets, offset_trans, facecolors, edgecolors,
linewidths, linestyles, antialiaseds, urls,
offset_position, hatchcolors=hatchcolors)
self, vgc, master_transform, paths, all_transforms,
offsets, offset_trans)

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

for xo, yo, path_id, gc0, rgbFace in self._iter_collection(
gc, path_codes, offsets, offset_trans,
facecolors, edgecolors, linewidths, linestyles,
antialiaseds, urls, offset_position, hatchcolors=hatchcolors):
vgc, path_codes, offsets, offset_trans):
ps = f"{xo:g} {yo:g} {path_id}"
self._draw_ps(ps, gc0, rgbFace)

Expand Down
31 changes: 18 additions & 13 deletions lib/matplotlib/backends/backend_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
import matplotlib as mpl
from matplotlib import cbook, font_manager as fm
from matplotlib.backend_bases import (
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase)
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase, GraphicsContextBase,
VectorizedGraphicsContextBase)
from matplotlib.backends.backend_mixed import MixedModeRenderer
from matplotlib.colors import rgb2hex
from matplotlib.dates import UTC
Expand Down Expand Up @@ -733,28 +734,34 @@ def draw_markers(
self.writer.end('a')
writer.end('g')

def draw_path_collection(self, gc, master_transform, paths, all_transforms,
offsets, offset_trans, facecolors, edgecolors,
linewidths, linestyles, antialiaseds, urls,
offset_position, *, hatchcolors=None):
def draw_path_collection(self, vgc, master_transform, paths, all_transforms,
offsets, offset_trans, facecolors=None, edgecolors=None,
linewidths=None, linestyles=None, antialiaseds=None,
urls=None, offset_position=None, hatchcolors=None):

if hatchcolors is None:
hatchcolors = []

if isinstance(gc := vgc, GraphicsContextBase):
vgc = VectorizedGraphicsContextBase()
vgc.copy_properties(gc, facecolors, edgecolors, linewidths, linestyles,
antialiaseds, urls, hatchcolors)

# Is the optimization worth it? Rough calculation:
# cost of emitting a path in-line is
# (len_path + 5) * uses_per_path
# cost of definition+use is
# (len_path + 3) + 9 * uses_per_path
len_path = len(paths[0].vertices) if len(paths) > 0 else 0
uses_per_path = self._iter_collection_uses_per_path(
paths, all_transforms, offsets, facecolors, edgecolors)
paths, all_transforms, offsets, vgc.get_facecolors(), vgc.get_edgecolors())
should_do_optimization = \
len_path + 9 * uses_per_path + 3 < (len_path + 5) * uses_per_path

if not should_do_optimization:
return super().draw_path_collection(
gc, master_transform, paths, all_transforms,
offsets, offset_trans, facecolors, edgecolors,
linewidths, linestyles, antialiaseds, urls,
offset_position, hatchcolors=hatchcolors)
vgc, master_transform, paths, all_transforms,
offsets, offset_trans)

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

for xo, yo, path_id, gc0, rgbFace in self._iter_collection(
gc, path_codes, offsets, offset_trans,
facecolors, edgecolors, linewidths, linestyles,
antialiaseds, urls, offset_position, hatchcolors=hatchcolors):
vgc, path_codes, offsets, offset_trans):
url = gc0.get_url()
if url is not None:
writer.start('a', attrib={'xlink:href': url})
Expand Down
Loading
Loading