Skip to content

Specifying a Marker as a Tuple seems broken in 3.2 #16811

@Erotemic

Description

@Erotemic

Bug report

Bug summary

In matplotlib 3.2 setting a line marker=(3, 2, 0.0) (which should be an asterisk style marker with 3 sides and 0 degrees of rotation) causes an error.

AttributeError: 'IdentityTransform' object has no attribute 'scale'

In version 3.1.2, this error does not occur. It looks like

Code for reproduction

def main():
    import matplotlib.pyplot as plt
    fig = plt.figure()
    fig.add_axes()
    ax = fig.gca()
    ax.plot([0, 1, 2], [0, 1, 2], marker=(3, 2, 0.0))
    fig.savefig('foo.png')


if __name__ == '__main__':
    main()

This results in the error:

Traceback (most recent call last):
  File "/home/joncrall/code/kwplot/dev/mwe_markerstye.py", line 15, in <module>
    main()
  File "/home/joncrall/code/kwplot/dev/mwe_markerstye.py", line 7, in main
    fig.savefig('foo.png')
  File "/home/joncrall/.local/conda/envs/py38/lib/python3.8/site-packages/matplotlib/figure.py", line 2203, in savefig
    self.canvas.print_figure(fname, **kwargs)
  File "/home/joncrall/.local/conda/envs/py38/lib/python3.8/site-packages/matplotlib/backends/backend_qt5agg.py", line 94, in print_figure
    super().print_figure(*args, **kwargs)
  File "/home/joncrall/.local/conda/envs/py38/lib/python3.8/site-packages/matplotlib/backend_bases.py", line 2086, in print_figure
    result = print_method(
  File "/home/joncrall/.local/conda/envs/py38/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py", line 514, in print_png
    FigureCanvasAgg.draw(self)
  File "/home/joncrall/.local/conda/envs/py38/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py", line 393, in draw
    self.figure.draw(self.renderer)
  File "/home/joncrall/.local/conda/envs/py38/lib/python3.8/site-packages/matplotlib/artist.py", line 38, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/joncrall/.local/conda/envs/py38/lib/python3.8/site-packages/matplotlib/figure.py", line 1735, in draw
    mimage._draw_list_compositing_images(
  File "/home/joncrall/.local/conda/envs/py38/lib/python3.8/site-packages/matplotlib/image.py", line 137, in _draw_list_compositing_images
    a.draw(renderer)
  File "/home/joncrall/.local/conda/envs/py38/lib/python3.8/site-packages/matplotlib/artist.py", line 38, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/joncrall/.local/conda/envs/py38/lib/python3.8/site-packages/matplotlib/axes/_base.py", line 2630, in draw
    mimage._draw_list_compositing_images(renderer, self, artists)
  File "/home/joncrall/.local/conda/envs/py38/lib/python3.8/site-packages/matplotlib/image.py", line 137, in _draw_list_compositing_images
    a.draw(renderer)
  File "/home/joncrall/.local/conda/envs/py38/lib/python3.8/site-packages/matplotlib/artist.py", line 38, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/joncrall/.local/conda/envs/py38/lib/python3.8/site-packages/matplotlib/lines.py", line 866, in draw
    marker_trans = marker_trans.scale(w)
AttributeError: 'IdentityTransform' object has no attribute 'scale'

While the 3.1.2 version results in a nice plot:

image

Matplotlib version

  • Operating system: Linux
  • Matplotlib version: 3.2 (via pip)
  • Matplotlib backend: tried agg and pyqt5
  • Python version: 3.7 and 3.8

I've identified a possible solution. The main difference seems to be in the _set_tuple_marker function. In 3.1.2 it was:

    def _set_tuple_marker(self):
        marker = self._marker
        if isinstance(marker[0], Number):
            if len(marker) == 2:
                numsides, rotation = marker[0], 0.0
            elif len(marker) == 3:
                numsides, rotation = marker[0], marker[2]
            symstyle = marker[1]
            if symstyle == 0:
                self._path = Path.unit_regular_polygon(numsides)
                self._joinstyle = 'miter'
            elif symstyle == 1:
                self._path = Path.unit_regular_star(numsides)
                self._joinstyle = 'bevel'
            elif symstyle == 2:
                self._path = Path.unit_regular_asterisk(numsides)
                self._filled = False
                self._joinstyle = 'bevel'
            elif symstyle == 3:
                cbook.warn_deprecated(
                    "3.0", message="Setting a circle marker using `(..., 3)` "
                    "is deprecated since Matplotlib 3.0, and support for it "
                    "will be removed in 3.2.  Directly pass 'o' instead.")
                self._path = Path.unit_circle()
            self._transform = Affine2D().scale(0.5).rotate_deg(rotation)
        else:
            cbook.warn_deprecated(
                "3.0", message="Passing vertices as `(verts, 0)` is "
                "deprecated since Matplotlib 3.0, and support for it will be "
                "removed in 3.2.  Directly pass `verts` instead.")
            verts = np.asarray(marker[0])
            path = Path(verts)
            self._set_custom_marker(path)

and in 3.2 it was cleaned up to:

    def _set_tuple_marker(self):
        marker = self._marker
        print('marker = {!r}'.format(marker))
        if len(marker) == 2:
            numsides, rotation = marker[0], 0.0
        elif len(marker) == 3:
            numsides, rotation = marker[0], marker[2]
        symstyle = marker[1]
        if symstyle == 0:
            self._path = Path.unit_regular_polygon(numsides)
            self._joinstyle = 'miter'
        elif symstyle == 1:
            self._path = Path.unit_regular_star(numsides)
            self._joinstyle = 'bevel'
        elif symstyle == 2:
            self._path = Path.unit_regular_asterisk(numsides)
            self._filled = False
            self._joinstyle = 'bevel'
        else:
            raise ValueError(f"Unexpected tuple marker: {marker}")

However, notice that in the second version self._transform is never set. Also note that in the 3.2 version the rotation param is never used. I expect that the self._transform = Affine2D().scale(0.5).rotate_deg(rotation) line was supposed to be ported, but never was. Adding it back in seems to fix the issue.

I noticed it when looking in the lines.py draw method. I saw most markers had an AffineTransform, but the ones I made using the tuple method of initialization has IdentityTransforms.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions