Skip to content

Commit e285ec6

Browse files
Merge pull request #7 from matplotlib/develop
Working with latest matplotlib, scale_lines also now scales markers.
2 parents a793210 + 4ca387b commit e285ec6

File tree

3 files changed

+167
-3
lines changed

3 files changed

+167
-3
lines changed

.github/workflows/pytest.yml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
strategy:
2020
matrix:
2121
os: [ubuntu-latest, macos-latest]
22-
python-version: ["3.9", "3.10", "3.11"]
22+
python-version: ["3.11", "3.12", "3.13", "3.13t"]
2323

2424
steps:
2525
- uses: actions/checkout@v4
@@ -57,15 +57,24 @@ jobs:
5757
flake8 matplotview --count --select=E9,F63,F7,F82 --show-source --statistics
5858
flake8 matplotview --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
5959
- name: Test with pytest
60+
id: pytest
6061
run: |
6162
pytest
6263
64+
- name: Upload images on failure
65+
uses: actions/upload-artifact@v4
66+
if: ${{ failure() && steps.pytest.conclusion == 'failure' }}
67+
with:
68+
name: test-result-images
69+
retention-days: 1
70+
path: result_images/
71+
6372
test-windows:
6473

6574
runs-on: windows-latest
6675
strategy:
6776
matrix:
68-
python-version: ["3.9", "3.10", "3.11"]
77+
python-version: ["3.11", "3.12", "3.13", "3.13t"]
6978

7079
steps:
7180
- uses: actions/checkout@v4
@@ -82,5 +91,14 @@ jobs:
8291
pip install pytest
8392
pip install -r requirements.txt
8493
- name: Test with pytest
94+
id: pytest
8595
run: |
86-
pytest
96+
pytest
97+
98+
- name: Upload images on failure
99+
uses: actions/upload-artifact@v4
100+
if: ${{ failure() && steps.pytest.conclusion == 'failure' }}
101+
with:
102+
name: test-result-images
103+
retention-days: 1
104+
path: result_images/

matplotview/_transform_renderer.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,76 @@ def _draw_text_as_path(
251251
# checked above... (Above case causes error)
252252
super()._draw_text_as_path(gc, x, y, s, prop, angle, ismath)
253253

254+
def draw_markers(
255+
self,
256+
gc,
257+
marker_path,
258+
marker_trans,
259+
path,
260+
trans,
261+
rgbFace=None,
262+
):
263+
# If the markers need to be scaled accurately (such as in log scale), just use the fallback as each will need
264+
# to be scaled separately.
265+
if (self.__scale_widths):
266+
super().draw_markers(gc, marker_path, marker_trans, path, trans, rgbFace)
267+
return
268+
269+
# Otherwise we transform just the marker offsets (not the marker patch), so they stay the same size.
270+
path = path.deepcopy()
271+
path.vertices = self._get_transfer_transform(trans).transform(path.vertices)
272+
bbox = self._get_axes_display_box()
273+
274+
# Change the clip to the sub-axes box
275+
gc.set_clip_rectangle(bbox)
276+
if (not isinstance(self.__bounding_axes.patch, Rectangle)):
277+
gc.set_clip_path(TransformedPatchPath(self.__bounding_axes.patch))
278+
279+
rgbFace = tuple(rgbFace) if (rgbFace is not None) else None
280+
self.__renderer.draw_markers(gc, marker_path, marker_trans, path, IdentityTransform(), rgbFace)
281+
282+
def draw_path_collection(
283+
self,
284+
gc,
285+
master_transform,
286+
paths,
287+
all_transforms,
288+
offsets,
289+
offset_trans,
290+
facecolors,
291+
edgecolors,
292+
linewidths,
293+
linestyles,
294+
antialiaseds,
295+
urls,
296+
offset_position,
297+
):
298+
# If we want accurate scaling for each marker (such as in log scale), just use superclass implementation...
299+
if (self.__scale_widths):
300+
super().draw_path_collection(
301+
gc, master_transform, paths, all_transforms, offsets, offset_trans, facecolors,
302+
edgecolors, linewidths, linestyles, antialiaseds, urls, offset_position
303+
)
304+
return
305+
306+
# Otherwise we transform just the offsets, and pass them to the backend.
307+
print(offsets)
308+
if (np.any(np.isnan(offsets))):
309+
raise ValueError("???")
310+
offsets = self._get_transfer_transform(offset_trans).transform(offsets)
311+
print(offsets)
312+
bbox = self._get_axes_display_box()
313+
314+
# Change the clip to the sub-axes box
315+
gc.set_clip_rectangle(bbox)
316+
if (not isinstance(self.__bounding_axes.patch, Rectangle)):
317+
gc.set_clip_path(TransformedPatchPath(self.__bounding_axes.patch))
318+
319+
self.__renderer.draw_path_collection(
320+
gc, master_transform, paths, all_transforms, offsets, IdentityTransform(), facecolors,
321+
edgecolors, linewidths, linestyles, antialiaseds, urls, None
322+
)
323+
254324
def draw_gouraud_triangle(
255325
self,
256326
gc: GraphicsContextBase,

matplotview/tests/test_view_rendering.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import sys
2+
13
import numpy as np
24
import matplotlib.pyplot as plt
35
from matplotlib.testing.decorators import check_figures_equal
@@ -240,3 +242,77 @@ def test_stop_viewing(fig_test, fig_ref):
240242

241243
ax1_ref.plot(data)
242244
ax1_ref.text(0.5, 0.5, "Hello")
245+
246+
247+
# On MacOS the results are off by an extremely tiny amount, can't even see in diff. It's close enough...
248+
@check_figures_equal(tol=0.02 if sys.platform.startswith("darwin") else 0)
249+
def test_log_line(fig_test, fig_ref):
250+
data = [i for i in range(1, 10)]
251+
252+
# Test case... Create a view and stop it...
253+
ax1_test, ax2_test = fig_test.subplots(1, 2)
254+
255+
ax1_test.set(xscale="log", yscale="log")
256+
ax1_test.plot(data, "-o")
257+
258+
view(ax2_test, ax1_test, scale_lines=False)
259+
ax2_test.set_xlim(-1, 10)
260+
ax2_test.set_ylim(-1, 10)
261+
262+
# Reference, just don't plot anything at all in the second axes...
263+
ax1_ref, ax2_ref = fig_ref.subplots(1, 2)
264+
265+
ax1_ref.set(xscale="log", yscale="log")
266+
ax1_ref.plot(data, "-o")
267+
ax2_ref.plot(data, "-o")
268+
ax2_ref.set_xlim(-1, 10)
269+
ax2_ref.set_ylim(-1, 10)
270+
271+
272+
@check_figures_equal()
273+
def test_log_scatter(fig_test, fig_ref):
274+
data = [i for i in range(1, 11)]
275+
276+
# Test case... Create a view and stop it...
277+
ax1_test, ax2_test = fig_test.subplots(1, 2)
278+
279+
ax1_test.set(xscale="log", yscale="log")
280+
ax1_test.scatter(data, data)
281+
282+
view(ax2_test, ax1_test, scale_lines=False)
283+
ax2_test.set_xlim(-5, 15)
284+
ax2_test.set_ylim(-5, 15)
285+
286+
# Reference, just don't plot anything at all in the second axes...
287+
ax1_ref, ax2_ref = fig_ref.subplots(1, 2)
288+
289+
ax1_ref.set(xscale="log", yscale="log")
290+
ax1_ref.scatter(data, data)
291+
ax2_ref.scatter(data, data)
292+
ax2_ref.set_xlim(-5, 15)
293+
ax2_ref.set_ylim(-5, 15)
294+
295+
296+
@check_figures_equal()
297+
def test_log_scatter_with_colors(fig_test, fig_ref):
298+
data = [i for i in range(1, 11)]
299+
colors = list("rgbrgbrgbr")
300+
301+
# Test case... Create a view and stop it...
302+
ax1_test, ax2_test = fig_test.subplots(1, 2)
303+
304+
ax1_test.set(xscale="log", yscale="log")
305+
ax1_test.scatter(data, data, color=colors)
306+
307+
view(ax2_test, ax1_test, scale_lines=False)
308+
ax2_test.set_xlim(-5, 15)
309+
ax2_test.set_ylim(-5, 15)
310+
311+
# Reference, just don't plot anything at all in the second axes...
312+
ax1_ref, ax2_ref = fig_ref.subplots(1, 2)
313+
314+
ax1_ref.set(xscale="log", yscale="log")
315+
ax1_ref.scatter(data, data, color=colors)
316+
ax2_ref.scatter(data, data, color=colors)
317+
ax2_ref.set_xlim(-5, 15)
318+
ax2_ref.set_ylim(-5, 15)

0 commit comments

Comments
 (0)