How to draw a collection of oriented triangles ?

I would like to draw several triangles (same size, same color) with different individual orientations.
Scatter plot does not allow to specify individual orientations and I've a hard time with PatchCollection.

What would be the easiest way ? Is there an example somewhere around by any chance ?

Nicolas

I?ve had great success using PathPatch and AffineTransform for this purpose:

from matplotlib import pyplot as pltfrom matplotlib.path import
Pathfrom matplotlib.transforms import Affine2Dfrom matplotlib.patches
import PathPatch

unit_triangle = Path.unit_regular_polygon(3)
def make_triangle(x, y, rot_deg, color, scale):
    path = Path(unit_triangle.vertices * scale, unit_triangle.codes)
    trans = Affine2D().translate(x, y).rotate_deg_around(x, y, rot_deg)
    t_path = path.transformed(trans)
    patch = PathPatch(t_path, facecolor=color)
    return patch

ax = plt.gca()
for x, y, rot_deg in [(1, 1, 90), (2, 2, 45), (-1, 1, 128)]:
    patch = make_triangle(x, y, rot_deg, "blue", 1)
    ax.add_patch(patch)
# Patches don't automatically change the visible range of the axes
like scatter does.
ax.autoscale()

?

···

On Sat, Nov 26, 2016 at 9:21 AM, Nicolas P. Rougier < Nicolas.Rougier at inria.fr> wrote:

I would like to draw several triangles (same size, same color) with
different individual orientations.
Scatter plot does not allow to specify individual orientations and I've a
hard time with PatchCollection.

What would be the easiest way ? Is there an example somewhere around by
any chance ?

Nicolas
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users at python.org
https://mail.python.org/mailman/listinfo/matplotlib-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20161126/6bffc926/attachment.html>

Thank you Joshua, I'll start from your code. My other problem is that I also need to update rotation and position (for an animation). Hope this will work with patch collection and updating individual transform.

Nicolas

···

On 26 Nov 2016, at 15:53, Joshua Klein <mobiusklein at gmail.com> wrote:

I?ve had great success using PathPatch and AffineTransform for this purpose:

from matplotlib import pyplot as
plt

from matplotlib.path import
Path

from matplotlib.transforms import
Affine2D

from matplotlib.patches import
PathPatch

unit_triangle = Path.unit_regular_polygon(
3
)

def make_triangle(x, y, rot_deg, color, scale):

    path = Path(unit_triangle.vertices * scale, unit_triangle.codes)
    trans = Affine2D().translate(x, y).rotate_deg_around(x, y, rot_deg)
    t_path = path.transformed(trans)
    patch = PathPatch(t_path, facecolor=color)
    
return
patch

ax = plt.gca()

for x, y, rot_deg in [(1, 1, 90), (2, 2, 45), (-1, 1, 128
)]:
    patch = make_triangle(x, y, rot_deg,
"blue", 1
)
    ax.add_patch(patch)

# Patches don't automatically change the visible range of the axes like scatter does.

ax.autoscale()

On Sat, Nov 26, 2016 at 9:21 AM, Nicolas P. Rougier <Nicolas.Rougier at inria.fr> wrote:

I would like to draw several triangles (same size, same color) with different individual orientations.
Scatter plot does not allow to specify individual orientations and I've a hard time with PatchCollection.

What would be the easiest way ? Is there an example somewhere around by any chance ?

Nicolas
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users at python.org
https://mail.python.org/mailman/listinfo/matplotlib-users

I don?t think my code ever directly works with a PatchCollection object,
just individual patches which possess distinct properties. Here?s an
example using animations:

import matplotlib
matplotlib.use("Tkagg")from matplotlib import pyplot as pltfrom
matplotlib.path import Pathfrom matplotlib.transforms import
Affine2Dfrom matplotlib.patches import PathPatchfrom matplotlib import
animationimport numpy as np

unit_triangle = Path.unit_regular_polygon(3)
def make_triangle(x, y, rot_deg, color, scale):
    path = Path(unit_triangle.vertices * scale, unit_triangle.codes)
    trans = Affine2D().translate(x, y).rotate_deg_around(x, y, rot_deg)
    t_path = path.transformed(trans)
    patch = PathPatch(t_path, facecolor=color)
    return patch

triangles = [(1, 1, 90), (2, 2, 45), (-1, 1, 128)]
patches = []
def step_fn(i):
    next_step = []
    # Random walk update each triangle's position
    for tri in triangles:
        x = tri[0] + np.random.random() - 0.5
        y = tri[1] + np.random.random() - 0.5
        rot = tri[2] + (np.random.random() - 0.5) * 45
        next_step.append((x, y, rot))
    triangles[:] = next_step

    # Remove the old patches
    while patches:
        patch = patches.pop()
        patch.remove()

    # Add the new patches
    patches[:] = [make_triangle(x, y, rot_deg, "blue", 0.2) for x, y,
rot_deg in triangles]
    for patch in patches:
        plt.gca().add_patch(patch)
    plt.autoscale()

fig = plt.figure()
a = animation.FuncAnimation(fig, step_fn, blit=False, interval=10)

plt.show()

?

···

On Sat, Nov 26, 2016 at 12:20 PM, Nicolas P. Rougier < Nicolas.Rougier at inria.fr> wrote:

Thank you Joshua, I'll start from your code. My other problem is that I
also need to update rotation and position (for an animation). Hope this
will work with patch collection and updating individual transform.

Nicolas

> On 26 Nov 2016, at 15:53, Joshua Klein <mobiusklein at gmail.com> wrote:
>
> I?ve had great success using PathPatch and AffineTransform for this
purpose:
>
> from matplotlib import pyplot as
> plt
>
> from matplotlib.path import
> Path
>
> from matplotlib.transforms import
> Affine2D
>
> from matplotlib.patches import
> PathPatch
>
> unit_triangle = Path.unit_regular_polygon(
> 3
> )
>
>
> def make_triangle(x, y, rot_deg, color, scale):
>
> path = Path(unit_triangle.vertices * scale, unit_triangle.codes)
> trans = Affine2D().translate(x, y).rotate_deg_around(x, y, rot_deg)
> t_path = path.transformed(trans)
> patch = PathPatch(t_path, facecolor=color)
>
> return
> patch
>
> ax = plt.gca()
>
>
> for x, y, rot_deg in [(1, 1, 90), (2, 2, 45), (-1, 1, 128
> )]:
> patch = make_triangle(x, y, rot_deg,
> "blue", 1
> )
> ax.add_patch(patch)
>
>
> # Patches don't automatically change the visible range of the axes like
scatter does.
>
> ax.autoscale()
>
>
> On Sat, Nov 26, 2016 at 9:21 AM, Nicolas P. Rougier < > Nicolas.Rougier at inria.fr> wrote:
>
> I would like to draw several triangles (same size, same color) with
different individual orientations.
> Scatter plot does not allow to specify individual orientations and I've
a hard time with PatchCollection.
>
> What would be the easiest way ? Is there an example somewhere around by
any chance ?
>
>
> Nicolas
> _______________________________________________
> Matplotlib-users mailing list
> Matplotlib-users at python.org
> https://mail.python.org/mailman/listinfo/matplotlib-users
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20161126/ceb8c20a/attachment.html>

Thanks. I end up using a PathCollection with a single path. The advantage is that you can split a path into several disconnected paths but the update can still be made at once (scaling, translating and rotation). This makes things relatively fast.

Code is available at: https://gist.github.com/rougier/b82fe08f1840f4277b52fb8bfbdb3cc7

Nicolas

···

On 26 Nov 2016, at 21:47, Joshua Klein <mobiusklein at gmail.com> wrote:

I don?t think my code ever directly works with a PatchCollection object, just individual patches which possess distinct properties. Here?s an example using animations:

import
matplotlib
matplotlib.use(
"Tkagg"
)

from matplotlib import pyplot as
plt

from matplotlib.path import
Path

from matplotlib.transforms import
Affine2D

from matplotlib.patches import
PathPatch

from matplotlib import
animation

import numpy as
np

unit_triangle = Path.unit_regular_polygon(
3
)

def make_triangle(x, y, rot_deg, color, scale):

    path = Path(unit_triangle.vertices * scale, unit_triangle.codes)
    trans = Affine2D().translate(x, y).rotate_deg_around(x, y, rot_deg)
    t_path = path.transformed(trans)
    patch = PathPatch(t_path, facecolor=color)
    
return
patch

triangles = [(
1, 1, 90), (2, 2, 45), (-1, 1, 128
)]
patches = []

def step_fn(i):

    next_step = []
    
# Random walk update each triangle's position

for tri in
triangles:
        x = tri[
0] + np.random.random() - 0.5

        y = tri[
1] + np.random.random() - 0.5

        rot = tri[
2] + (np.random.random() - 0.5) * 45

        next_step.append((x, y, rot))
    triangles[:] = next_step

# Remove the old patches

while
patches:
        patch = patches.pop()
        patch.remove()

# Add the new patches

    patches[:] = [make_triangle(x, y, rot_deg,
"blue", 0.2) for x, y, rot_deg in
triangles]
    
for patch in
patches:
        plt.gca().add_patch(patch)
    plt.autoscale()

fig = plt.figure()
a = animation.FuncAnimation(fig, step_fn, blit=
False, interval=10
)

plt.show()

On Sat, Nov 26, 2016 at 12:20 PM, Nicolas P. Rougier <Nicolas.Rougier at inria.fr> wrote:

Thank you Joshua, I'll start from your code. My other problem is that I also need to update rotation and position (for an animation). Hope this will work with patch collection and updating individual transform.

Nicolas

> On 26 Nov 2016, at 15:53, Joshua Klein <mobiusklein at gmail.com> wrote:
>
> I?ve had great success using PathPatch and AffineTransform for this purpose:
>
> from matplotlib import pyplot as
> plt
>
> from matplotlib.path import
> Path
>
> from matplotlib.transforms import
> Affine2D
>
> from matplotlib.patches import
> PathPatch
>
> unit_triangle = Path.unit_regular_polygon(
> 3
> )
>
>
> def make_triangle(x, y, rot_deg, color, scale):
>
> path = Path(unit_triangle.vertices * scale, unit_triangle.codes)
> trans = Affine2D().translate(x, y).rotate_deg_around(x, y, rot_deg)
> t_path = path.transformed(trans)
> patch = PathPatch(t_path, facecolor=color)
>
> return
> patch
>
> ax = plt.gca()
>
>
> for x, y, rot_deg in [(1, 1, 90), (2, 2, 45), (-1, 1, 128
> )]:
> patch = make_triangle(x, y, rot_deg,
> "blue", 1
> )
> ax.add_patch(patch)
>
>
> # Patches don't automatically change the visible range of the axes like scatter does.
>
> ax.autoscale()
>
>
> On Sat, Nov 26, 2016 at 9:21 AM, Nicolas P. Rougier <Nicolas.Rougier at inria.fr> wrote:
>
> I would like to draw several triangles (same size, same color) with different individual orientations.
> Scatter plot does not allow to specify individual orientations and I've a hard time with PatchCollection.
>
> What would be the easiest way ? Is there an example somewhere around by any chance ?
>
>
> Nicolas
> _______________________________________________
> Matplotlib-users mailing list
> Matplotlib-users at python.org
> https://mail.python.org/mailman/listinfo/matplotlib-users
>