Skip to content
24 changes: 21 additions & 3 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
python-version: ["3.9", "3.10", "3.11"]
python-version: ["3.11", "3.12", "3.13", "3.13t"]

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -57,15 +57,24 @@ jobs:
flake8 matplotview --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 matplotview --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
id: pytest
run: |
pytest

- name: Upload images on failure
uses: actions/upload-artifact@v4
if: ${{ failure() && steps.pytest.conclusion == 'failure' }}
with:
name: test-result-images
retention-days: 1
path: result_images/

test-windows:

runs-on: windows-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11"]
python-version: ["3.11", "3.12", "3.13", "3.13t"]

steps:
- uses: actions/checkout@v4
Expand All @@ -82,5 +91,14 @@ jobs:
pip install pytest
pip install -r requirements.txt
- name: Test with pytest
id: pytest
run: |
pytest
pytest

- name: Upload images on failure
uses: actions/upload-artifact@v4
if: ${{ failure() && steps.pytest.conclusion == 'failure' }}
with:
name: test-result-images
retention-days: 1
path: result_images/
70 changes: 70 additions & 0 deletions matplotview/_transform_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,76 @@ def _draw_text_as_path(
# checked above... (Above case causes error)
super()._draw_text_as_path(gc, x, y, s, prop, angle, ismath)

def draw_markers(
self,
gc,
marker_path,
marker_trans,
path,
trans,
rgbFace=None,
):
# If the markers need to be scaled accurately (such as in log scale), just use the fallback as each will need
# to be scaled separately.
if (self.__scale_widths):
super().draw_markers(gc, marker_path, marker_trans, path, trans, rgbFace)
return

# Otherwise we transform just the marker offsets (not the marker patch), so they stay the same size.
path = path.deepcopy()
path.vertices = self._get_transfer_transform(trans).transform(path.vertices)
bbox = self._get_axes_display_box()

# Change the clip to the sub-axes box
gc.set_clip_rectangle(bbox)
if (not isinstance(self.__bounding_axes.patch, Rectangle)):
gc.set_clip_path(TransformedPatchPath(self.__bounding_axes.patch))

rgbFace = tuple(rgbFace) if (rgbFace is not None) else None
self.__renderer.draw_markers(gc, marker_path, marker_trans, path, IdentityTransform(), rgbFace)

def draw_path_collection(
self,
gc,
master_transform,
paths,
all_transforms,
offsets,
offset_trans,
facecolors,
edgecolors,
linewidths,
linestyles,
antialiaseds,
urls,
offset_position,
):
# If we want accurate scaling for each marker (such as in log scale), just use superclass implementation...
if (self.__scale_widths):
super().draw_path_collection(
gc, master_transform, paths, all_transforms, offsets, offset_trans, facecolors,
edgecolors, linewidths, linestyles, antialiaseds, urls, offset_position
)
return

# Otherwise we transform just the offsets, and pass them to the backend.
print(offsets)
if (np.any(np.isnan(offsets))):
raise ValueError("???")
offsets = self._get_transfer_transform(offset_trans).transform(offsets)
print(offsets)
bbox = self._get_axes_display_box()

# Change the clip to the sub-axes box
gc.set_clip_rectangle(bbox)
if (not isinstance(self.__bounding_axes.patch, Rectangle)):
gc.set_clip_path(TransformedPatchPath(self.__bounding_axes.patch))

self.__renderer.draw_path_collection(
gc, master_transform, paths, all_transforms, offsets, IdentityTransform(), facecolors,
edgecolors, linewidths, linestyles, antialiaseds, urls, None
)

def draw_gouraud_triangle(
self,
gc: GraphicsContextBase,
Expand Down
76 changes: 76 additions & 0 deletions matplotview/tests/test_view_rendering.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import sys

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.testing.decorators import check_figures_equal
Expand Down Expand Up @@ -240,3 +242,77 @@ def test_stop_viewing(fig_test, fig_ref):

ax1_ref.plot(data)
ax1_ref.text(0.5, 0.5, "Hello")


# On MacOS the results are off by an extremely tiny amount, can't even see in diff. It's close enough...
@check_figures_equal(tol=0.02 if sys.platform.startswith("darwin") else 0)
def test_log_line(fig_test, fig_ref):
data = [i for i in range(1, 10)]

# Test case... Create a view and stop it...
ax1_test, ax2_test = fig_test.subplots(1, 2)

ax1_test.set(xscale="log", yscale="log")
ax1_test.plot(data, "-o")

view(ax2_test, ax1_test, scale_lines=False)
ax2_test.set_xlim(-1, 10)
ax2_test.set_ylim(-1, 10)

# Reference, just don't plot anything at all in the second axes...
ax1_ref, ax2_ref = fig_ref.subplots(1, 2)

ax1_ref.set(xscale="log", yscale="log")
ax1_ref.plot(data, "-o")
ax2_ref.plot(data, "-o")
ax2_ref.set_xlim(-1, 10)
ax2_ref.set_ylim(-1, 10)


@check_figures_equal()
def test_log_scatter(fig_test, fig_ref):
data = [i for i in range(1, 11)]

# Test case... Create a view and stop it...
ax1_test, ax2_test = fig_test.subplots(1, 2)

ax1_test.set(xscale="log", yscale="log")
ax1_test.scatter(data, data)

view(ax2_test, ax1_test, scale_lines=False)
ax2_test.set_xlim(-5, 15)
ax2_test.set_ylim(-5, 15)

# Reference, just don't plot anything at all in the second axes...
ax1_ref, ax2_ref = fig_ref.subplots(1, 2)

ax1_ref.set(xscale="log", yscale="log")
ax1_ref.scatter(data, data)
ax2_ref.scatter(data, data)
ax2_ref.set_xlim(-5, 15)
ax2_ref.set_ylim(-5, 15)


@check_figures_equal()
def test_log_scatter_with_colors(fig_test, fig_ref):
data = [i for i in range(1, 11)]
colors = list("rgbrgbrgbr")

# Test case... Create a view and stop it...
ax1_test, ax2_test = fig_test.subplots(1, 2)

ax1_test.set(xscale="log", yscale="log")
ax1_test.scatter(data, data, color=colors)

view(ax2_test, ax1_test, scale_lines=False)
ax2_test.set_xlim(-5, 15)
ax2_test.set_ylim(-5, 15)

# Reference, just don't plot anything at all in the second axes...
ax1_ref, ax2_ref = fig_ref.subplots(1, 2)

ax1_ref.set(xscale="log", yscale="log")
ax1_ref.scatter(data, data, color=colors)
ax2_ref.scatter(data, data, color=colors)
ax2_ref.set_xlim(-5, 15)
ax2_ref.set_ylim(-5, 15)
Loading