diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..fc9f855 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" # Location of your workflow files + schedule: + interval: "weekly" # Options: daily, weekly, monthly diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6135e19..031ede2 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,18 +24,20 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 + with: + persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 83075c8..f8c31fa 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -1,5 +1,7 @@ name: Validate Python Code +permissions: + contents: read on: push: @@ -17,12 +19,14 @@ 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@v3 + - uses: actions/checkout@v4 + with: + persist-credentials: false - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -53,20 +57,31 @@ 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@v3 + - uses: actions/checkout@v4 + with: + persist-credentials: false - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -76,5 +91,14 @@ jobs: pip install pytest pip install -r requirements.txt - name: Test with pytest + id: pytest run: | - pytest \ No newline at end of file + 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/ diff --git a/matplotview/_transform_renderer.py b/matplotview/_transform_renderer.py index a61d1ba..4bfd180 100644 --- a/matplotview/_transform_renderer.py +++ b/matplotview/_transform_renderer.py @@ -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, diff --git a/matplotview/tests/test_view_rendering.py b/matplotview/tests/test_view_rendering.py index 03b9547..05d44e1 100644 --- a/matplotview/tests/test_view_rendering.py +++ b/matplotview/tests/test_view_rendering.py @@ -1,3 +1,5 @@ +import sys + import numpy as np import matplotlib.pyplot as plt from matplotlib.testing.decorators import check_figures_equal @@ -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) diff --git a/setup.py b/setup.py index 2f0e9c4..9e53965 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ import setuptools -VERSION = "1.0.1" +VERSION = "1.0.2" with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read()
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: