# Using villares PVector (python implementation) in py5

**URL:** https://discourse.processing.org/t/using-villares-pvector-python-implementation-in-py5/33268
**Category:** Gallery
**Created:** [November 2, 2021, 6:19pm UTC](https://discourse.processing.org/t/using-villares-pvector-python-implementation-in-py5/33268 "2021-11-02T18:19:09Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![monkstone](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/monkstone/32/64_2.png) [@monkstone](https://discourse.processing.org/u/monkstone)
#### Post date: [November 2, 2021, 6:19pm UTC](https://discourse.processing.org/t/using-villares-pvector-python-implementation-in-py5/33268/1 "2021-11-02T18:19:09Z")

</div>

@villares has created a proposed new [python implementation of PVector](https://github.com/villares/sketch-a-day/blob/main/2021/sketch_2021_11_02a_pvector_py5/pvector_for_py5.py) for use with py5. I’m not a fan of camel case in python (or ruby) so I changed the signature of `PVector.fromAngle` and also enclosed it as a module. But here’s my translation of [morph.rb](https://github.com/ruby-processing/JRubyArt-examples/blob/master/processing_app/library/vecmath/vec2d/morph.rb) to morph.py making use of numpy along the way:-

```python
import py5
from vector.pvector import PVector
import numpy as np

ALPHA = 45
OMEGA = 405
THETA = 9
state = False

def settings():
    py5.size(200, 200)

def setup():
    global circle, square, morph
    circle = []
    square = []
    morph = []
    angles = range(ALPHA, OMEGA, THETA)
    py5.frame_rate(15)
    for angle in angles:
        circle.append(PVector.from_angle(py5.radians(angle), 50))
        morph.append(PVector(0, 0))
    nvalues = -np.arange(-50, 51)
    pvalues = np.arange(-50, 51)
    for x in np.nditer(pvalues[::10]): # top
        square.append(PVector(x, -50))
    for y in np.nditer(pvalues[::10]): # right side
        square.append(PVector(50, y))
    for x in np.nditer(nvalues[::-10]): # bottom
        square.append(PVector(x, 50))
    for y in np.nditer(nvalues[::-10]): # left side
        square.append(PVector(-50, y))

def draw():
    global state
    py5.background(51)
    total_distance = 0
    for i in range(len(circle)):
        v1 = circle[i] if state else square[i]
        v2 = morph[i]
        v2 = v2.lerp(v1, 0.1)
        total_distance += v1.dist(v2)
    if (total_distance < 0.08):
        state = not(state)
    py5.translate(py5.width / 2.0, py5.height / 2.0)
    py5.no_fill()
    py5.stroke(255)
    py5.stroke_weight(4)
    py5.begin_shape()
    for vec in morph:
        py5.vertex(vec.x, vec.y)
    py5.end_shape(py5.CLOSE)
py5.run_sketch()

```

It took longer than expected with some of my usual grievances with python syntax bugging me again, including ternary operator and unexpected indexing of `numpy` arrays using `nditer` however `numpy` scores on performance ground, and gets round limitations of iterating `regular` python ranges (things I take for granted in ruby). One for @hx2a and @tabreturn to look at.

---

<div class="post-metadata">

### Author: ![hx2A](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/hx2a/32/14322_2.png) [@hx2A](https://discourse.processing.org/u/hx2A)
#### Post date: [November 3, 2021, 2:40am UTC](https://discourse.processing.org/t/using-villares-pvector-python-implementation-in-py5/33268/2 "2021-11-03T02:40:19Z")

</div>

Thanks for sharing this. I never used `np.nditer` before but just read the documentation. Apparently I’ve been missing out.

It’s too bad you can’t use `py5.vertices(morph)` at the end of the `draw()` function to draw all of the vertices without that for loop. I do think `py5.vertices([[v.x, v.y] for v in morph])` might work though.

Your example is interesting and helps inform my thinking.

---

<div class="post-metadata">

### Author: ![monkstone](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/monkstone/32/64_2.png) [@monkstone](https://discourse.processing.org/u/monkstone)
#### Post date: [November 3, 2021, 3:54pm UTC](https://discourse.processing.org/t/using-villares-pvector-python-implementation-in-py5/33268/3 "2021-11-03T15:54:01Z")

</div>

Turns out `nditer` actually can do what I wanted in a more elegant way (which also avoids crazy indexing):-

```python
    nvalues = -np.arange(-50, 50, 10)
    pvalues = np.arange(-50, 50, 10)
    for x in np.nditer(pvalues): # top
        square.append(PVector(x, -50))
    for y in np.nditer(pvalues): # right side
        square.append(PVector(50, y))
    for x in np.nditer(nvalues): # bottom
        square.append(PVector(x, 50))
    for y in np.nditer(nvalues): # left side
        square.append(PVector(-50, y))

```

But unfortunately I cannot use py5.vertices as suggested, however that might be a consideration when creating a vector class (for my ruby processing Vec2D and Vec3D classes I have created to vertex methods for PShape and and custom renderer).

---

<div class="post-metadata">

### Author: ![hx2A](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/hx2a/32/14322_2.png) [@hx2A](https://discourse.processing.org/u/hx2A)
#### Post date: [November 3, 2021, 10:13pm UTC](https://discourse.processing.org/t/using-villares-pvector-python-implementation-in-py5/33268/4 "2021-11-03T22:13:32Z")

</div>

> [@monkstone](#):
>
> But unfortunately I cannot use py5.vertices as suggested, however that might be a consideration when creating a vector class

Interesting. In my opinion it would be better if you could use it that way, and I will certainly think about this when creating a vector class.

---

<div class="post-metadata">

### Author: ![monkstone](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/monkstone/32/64_2.png) [@monkstone](https://discourse.processing.org/u/monkstone)
#### Post date: [November 4, 2021, 7:16am UTC](https://discourse.processing.org/t/using-villares-pvector-python-implementation-in-py5/33268/5 "2021-11-04T07:16:51Z")

</div>

@hx2A If you create a Vec2D class (along lines of @villares PVector) and add a method:-

```python
def to_array(self):
        return [self.x, self.y]

```

Then the following works just dandy:-

```python
py5.vertices([v.to_array() for v in morph])

```

Which as you say avoids looping through morph…

If you just add `to_array` method to `PVector` then you get the following error

```bash
vertex() with x, y, and z coordinates can only be used with a renderer that supports 3D, such as P3D. Use a version without a z-coordinate instead.

```

Another strong argument for a separate Vec2D class, along with cross product error (_returns vector instead of scalar_) etc etc.
