Change dimension of cube using MatrixTransform in vispy - vispy

import numpy as np
from vispy import app, scene
from vispy.visuals import transforms
canvas = scene.SceneCanvas(keys='interactive', show=True)
vb = canvas.central_widget.add_view()
vb.camera = 'turntable'
vb.camera.rect = (-10, -10, 20, 20)
box = scene.visuals.Box(width=1, height=2, depth=3, color=(0, 0, 1, 0.3),
edge_color='green')
vb.add(box)
# Define a scale and translate transformation :
box.transform = transforms.STTransform(translate=(0., 0., 0.),
scale=(1., 1., 1.))
#canvas.events.key_press.connect
def on_key_press(ev):
tr = np.array(box.transform.translate)
sc = np.array(box.transform.scale)
if ev.text in '+':
tr[0] += .1
elif ev.text == '-':
tr[0] -= .1
elif ev.text == '(':
sc[0] += .1
elif ev.text == ')':
sc[0] -= .1
box.transform.translate = tr
box.transform.scale = sc
print('Translate (x, y, z): ', list(tr),
'\nScale (x, y, z): ', list(sc), '\n')
if __name__ == '__main__':
import sys
if sys.flags.interactive != 1:
app.run()
In the above code if I add a MatrixTransform, and rotate the cube and then apply scaling, the cube becomes a Rhombus
What I would like to achieve is to rotate the cube in a canvas and scale it only in X direction, without other dimensions getting affected

I think we covered this in a vispy repository bug report. The solution was to swap the order of the matrix transform and st transform in your multiplication. If this is still an issue, could you provide your code when you are using the matrix and we'll continue debugging this. Thanks.

Related

Paraview python 'Zoom to Box'

I am trying to make a script which does basically what tool 'Zoom to Box' does. Track option is out of question as it doesn't track camera movement.
I've found this online, fixed it to work, but keep getting '3d cam position is yet TODO' This is very old and maybe there are new options to do this? Thanks for the tips...
I could also try doing it by using classic camera commands like:
source=GetActiveSource()
#view = GetRenderView()
#view.CameraFocalPoint = [1, 0, 0]
#view.CameraViewAngle = 90
#view.CameraViewUp = [0, 0, 0]
#view.CameraPosition = [0, 0, 0]
#view.ViewSize = [1528, 542]
#view.ResetCamera()
But I'm not sure there is a way to zoom?
Fixed script from the link above:
source=GetActiveSource()
rep = Show(source)
# run the pipeline here to get the bounds
Render()
bounds = source.GetDataInformation().GetBounds()
bounds_dx = bounds[1] - bounds[0]
bounds_dy = bounds[3] - bounds[2]
bounds_dz = bounds[5] - bounds[4]
bounds_cx = (bounds[0] + bounds[1])/2.0
bounds_cy = (bounds[2] + bounds[3])/2.0
bounds_cz = (bounds[4] + bounds[5])/2.0
if bounds_dx == 0:
# yz
dimMode = 2
aspect = bounds_dz/bounds_dy
elif bounds_dy == 0:
# xz
dimMode = 1
aspect = bounds_dz/bounds_dx
elif bounds_dz == 0:
# xy
dimMode = 0
aspect = bounds_dy/bounds_dx
else:
# 3d
dimMode = 3
aspect = 1.0 # TODO
lastObj = source
view = GetRenderView()
# view.ViewTime = steps[step] # unwanted
# view.UseOffscreenRenderingForScreenshots = 0 # obsolete
rep = Show(lastObj)
# rep.Representation = 'Outline' # unwanted
Render()
# position the camera
# far = config.camFac
far = 1
near = 0
if dimMode == 0:
# xy
pos = max(bounds_dx, bounds_dy)
camUp = [0.0, 1.0, 0.0]
camPos = [bounds_cx, bounds_cy, pos*far]
camFoc = [bounds_cx, bounds_cy, -pos*near]
elif dimMode == 1:
# xz
pos = max(bounds_dx, bounds_dz)
camUp = [0.0, 0.0, 1.0]
camPos = [bounds_cx, -pos*far, bounds_cz]
camFoc = [bounds_cx, pos*near, bounds_cz]
elif dimMode == 2:
# yz
pos = max(bounds_dy, bounds_dz)
camUp = [0.0, 0.0, 1.0]
camPos = [ pos*far, bounds_cy, bounds_cz]
camFoc = [-pos*near, bounds_cy, bounds_cz]
else:
# 3d
print('3d cam position is yet TODO')
camUp=[0,0,0]
camPos=[1,0,0]
camFoc=[0,0,0]
view = GetRenderView()
view.CameraViewUp = camUp
view.CameraPosition = camPos
view.CameraFocalPoint = camFoc
#view.UseOffscreenRenderingForScreenshots = 0 # obsolete
view.CenterAxesVisibility = 0
ren = Render()
#width = int(config.outputWidth)
#height = int(config.outputWidth*aspect)
So I just went ahead and did it this way:
import sys
from paraview.simple import *
# Camera Position
# positional coordinates of the camera
# zoom is achieved by adjusting x, y, z values (moving camera closer/further away) depending on focal point
# e. g. [10,0,4] - camera will be looking at object from this coordinate
CamPos = sys.argv[1]
# Camera Focal Point
# point of interest for the camera
# the point will be in the center of the screen and camera will rotate towards him in its position
# e. g. [0,0,0] - camera will focus its center on this coordinate
CamFocPoint = sys.argv[2]
# Camera View Up
# defining which way is up in the view
# uses values <-1;1> for each vector component
# to achieve angled view, use same value '1' for two vector components
# e. g. [0,0,1] - achieves having highest z component at the top
CamViewUp = sys.argv[3]
# getting active view
camera = GetActiveCamera()
# setting based on user definition
camera.SetPosition(CamPos[0], CamPos[1], CamPos[2])
camera.SetFocalPoint(CamFocPoint[0], CamFocPoint[1], CamFocPoint[2])
camera.SetViewUp(CamViewUp[0], CamViewUp[1], CamViewUp[2])
# making sure angle is right
camera.SetViewAngle(30)
# rendering view
Render()

How to detect curve shaped clusters in 2D array? Python

What is the smartest way to detect curves in a 2d dataset? There must be a way to cluster data points by defining maximum distance to neighbor. My goal is to apply polyfit function over each curve and use this template for alike datasets.
Example of data:
array([[ 0., 0., 0., ..., 2020., 2020., 2020.],
[ 51., 76., 194., ..., 1862., 1915., 2021.]])
Figured out this can be done with Agglomerative Clustering, here's the code and result:
from sklearn.cluster import AgglomerativeClustering
#Reshape data
a = array[:, 0].flatten()
b = array[:, 1].flatten()
array_new = np.matrix([a,b])
array_new = np.squeeze(np.asarray(array_new))
array_new1 = array_new.T
#Clustering algorithm
n_clusters = None
model = AgglomerativeClustering(n_clusters=n_clusters,
affinity='euclidean',
linkage='single',
compute_full_tree=True,
distance_threshold=15)
model.fit(array_new1)
labels = model.labels_
n_clusters = len(list(set(labels)))
print(n_clusters)
cmap = plt.get_cmap('rainbow')
colors = [cmap(i) for i in np.linspace(0, 1, n_clusters)]
plt.figure(figsize=(15,15))
for i, color in enumerate(colors, start=1):
plt.scatter(array_new1[labels==i,0], array_new1[labels==i,1], color=color)
plt.gca().invert_yaxis()
plt.show()
![](https://i.stack.imgur.com/utwqP.png)
#plotting result
data = pd.DataFrame({'x' : array_new1[:,0],
'y' : array_new1[:,1],
'label' : labels})
data.sort_values(by='label')
counter = 0
plt.figure(figsize=(15,15))
plt.scatter(5*array[:, 0], array[:, 1])
for i in range(n_clusters):
if len(data.loc[data['label'] == i].iloc[:,0]) > 50 \
and len(data.loc[data['label'] == i].iloc[:,0]) < 1000:
counter += 1
z = np.polyfit(data.loc[data['label'] == i].iloc[:,0],
data.loc[data['label'] == i].iloc[:,1],
2)
p = np.poly1d(z)
xp = np.linspace(0, tasku_sk, 50)
#plt.scatter(data.loc[data['label'] == i].iloc[:,0],
# data.loc[data['label'] == i].iloc[:,1])
plt.plot(5*xp, p(xp), c='r', lw=4)
plt.gca().invert_yaxis()
plt.show()
print(counter)
![](https://i.stack.imgur.com/AQHOf.png)
22
Yes.
The supposedly oldest of all clustering algorithms: single-link.

How to create Bezier curves from B-Splines in Sympy?

I need to draw a smooth curve through some points, which I then want to show as an SVG path. So I create a B-Spline with scipy.interpolate, and can access some arrays that I suppose fully define it. Does someone know a reasonably simple way to create Bezier curves from these arrays?
import numpy as np
from scipy import interpolate
x = np.array([-1, 0, 2])
y = np.array([ 0, 2, 0])
x = np.r_[x, x[0]]
y = np.r_[y, y[0]]
tck, u = interpolate.splprep([x, y], s=0, per=True)
cx = tck[1][0]
cy = tck[1][1]
print( 'knots: ', list(tck[0]) )
print( 'coefficients x: ', list(cx) )
print( 'coefficients y: ', list(cy) )
print( 'degree: ', tck[2] )
print( 'parameter: ', list(u) )
The red points are the 3 initial points in x and y. The green points are the 6 coefficients in cx and cy. (Their values repeat after the 3rd, so each green point has two green index numbers.)
Return values tck and u are described scipy.interpolate.splprep documentation
knots: [-1.0, -0.722, -0.372, 0.0, 0.277, 0.627, 1.0, 1.277, 1.627, 2.0]
# 0 1 2 3 4 5
coefficients x: [ 3.719, -2.137, -0.053, 3.719, -2.137, -0.053]
coefficients y: [-0.752, -0.930, 3.336, -0.752, -0.930, 3.336]
degree: 3
parameter: [0.0, 0.277, 0.627, 1.0]
Not sure starting with a B-Spline makes sense: form a catmull-rom curve through the points (with the virtual "before first" and "after last" overlaid on real points) and then convert that to a bezier curve using a relatively trivial transform? E.g. given your points p0, p1, and p2, the first segment would be a catmull-rom curve {p2,p0,p1,p2} for the segment p1--p2, {p0,p1,p2,p0} will yield p2--p0, and {p1, p2, p0, p1} will yield p0--p1. Then you trivially convert those and now you have your SVG path.
As demonstrator, hit up https://editor.p5js.org/ and paste in the following code:
var points = [{x:150, y:100 },{x:50, y:300 },{x:300, y:300 }];
// add virtual points:
points = points.concat(points);
function setup() {
createCanvas(400, 400);
tension = createSlider(1, 200, 100);
}
function draw() {
background(220);
points.forEach(p => ellipse(p.x, p.y, 4));
for (let n=0; n<3; n++) {
let [c1, c2, c3, c4] = points.slice(n,n+4);
let t = 0.06 * tension.value();
bezier(
// on-curve start point
c2.x, c2.y,
// control point 1
c2.x + (c3.x - c1.x)/t,
c2.y + (c3.y - c1.y)/t,
// control point 2
c3.x - (c4.x - c2.x)/t,
c3.y - (c4.y - c2.y)/t,
// on-curve end point
c3.x, c3.y
);
}
}
Which will look like this:
Converting that to Python code should be an almost effortless exercise: there is barely any code for us to write =)
And, of course, now you're left with creating the SVG path, but that's hardly an issue: you know all the Bezier points now, so just start building your <path d=...> string while you iterate.
A B-spline curve is just a collection of Bezier curves joined together. Therefore, it is certainly possible to convert it back to multiple Bezier curves without any loss of shape fidelity. The algorithm involved is called "knot insertion" and there are different ways to do this with the two most famous algorithm being Boehm's algorithm and Oslo algorithm. You can refer this link for more details.
Here is an almost direct answer to your question (but for the non-periodic case):
import aggdraw
import numpy as np
import scipy.interpolate as si
from PIL import Image
# from https://stackoverflow.com/a/35007804/2849934
def scipy_bspline(cv, degree=3):
""" cv: Array of control vertices
degree: Curve degree
"""
count = cv.shape[0]
degree = np.clip(degree, 1, count-1)
kv = np.clip(np.arange(count+degree+1)-degree, 0, count-degree)
max_param = count - (degree * (1-periodic))
spline = si.BSpline(kv, cv, degree)
return spline, max_param
# based on https://math.stackexchange.com/a/421572/396192
def bspline_to_bezier(cv):
cv_len = cv.shape[0]
assert cv_len >= 4, "Provide at least 4 control vertices"
spline, max_param = scipy_bspline(cv, degree=3)
for i in range(1, max_param):
spline = si.insert(i, spline, 2)
return spline.c[:3 * max_param + 1]
def draw_bezier(d, bezier):
path = aggdraw.Path()
path.moveto(*bezier[0])
for i in range(1, len(bezier) - 1, 3):
v1, v2, v = bezier[i:i+3]
path.curveto(*v1, *v2, *v)
d.path(path, aggdraw.Pen("black", 2))
cv = np.array([[ 40., 148.], [ 40., 48.],
[244., 24.], [160., 120.],
[240., 144.], [210., 260.],
[110., 250.]])
im = Image.fromarray(np.ones((400, 400, 3), dtype=np.uint8) * 255)
bezier = bspline_to_bezier(cv)
d = aggdraw.Draw(im)
draw_bezier(d, bezier)
d.flush()
# show/save im
I didn't look much into the periodic case, but hopefully it's not too difficult.

How to make scoreborad in tkinter

I would like to implement a scoreboard using a tkinter.
and i want make if the distance between the object bullet and the object enemy is less than 10, I want to increase the score by 10.
How do I add code?
Thank you in advance.
from tkinter import *
import time
import random
WIDTH = 800
HEIGHT = 800
class Ball:
def __init__(self, canvas, color, size, x, y, xspeed, yspeed):
self.canvas = canvas
self.color = color
self.size = size
self.x = x
self.y = y
self.xspeed = xspeed
self.yspeed = yspeed
self.id = canvas.create_oval(x, y, x+size, y+size, fill=color)
def move(self):
self.canvas.move(self.id, self.xspeed, self.yspeed)
(x1, y1, x2, y2) = self.canvas.coords(self.id)
(self.x, self.y) = (x1, y1)
if x1 <= 0 or x2 >= WIDTH:
self.xspeed = - self.xspeed
if y1 <= 0 or y2 >= HEIGHT:
self.yspeed = - self.yspeed
bullets = []
def fire(event):
bullets.append(Ball(canvas, "red", 10, 150, 250, 10, 0))
def up(event):
spaceship.yspeed-=1
def down(event):
spaceship.yspeed+=1
window = Tk()
canvas = Canvas(window, width=WIDTH, height=HEIGHT)
canvas.pack()
canvas.bind("<Button-1>", fire)
window.bind("<Up>",up)
window.bind("<Down>",down)
spaceship = Ball(canvas, "green", 100, 100, 200, 0, 0)
enemy = Ball(canvas, "red", 100, 500, 200, 5, 0)
while True:
for bullet in bullets:
bullet.move()
if (bullet.x+bullet.size) >= WIDTH:
canvas.delete(bullet.id)
bullets.remove(bullet)
enemy.move()
spaceship.move()
window.update()
time.sleep(0.03)
There are many ways to improve your program but I will concentrate on the collision aspect only.
Tkinter canvas has several methods; find_closest, find_enclosed and find_overlapping (See here) to allow you to detect where objects are in relation to each other. find_closest would be my first choice.
find_closest should take the x, y coordinates of the 'enemy' and a 'halo distance' (your less than 10 pixels). This will return the id's of objects nearby. If one of those objects is a bullet, then add 10 points to the score.
Some other things to fix/work on
You don't have a tkinter.mainloop. You should
Your method for moving the spaceship by changing the speed rather than the xy coords is poor and ends up with a very fast moving spaceship.

matplotlib - Keyboard shortcuts to pan left/right/up/down

In matplotlib, is there a keyboard alternative to dragging a plot with the left mouse click for panning in the four directions?
Reason is, apart from the fact that it seems like an obvious keyboard shortcut, I'm printing the xdata value every time I left-click. It would be useful to drag without clicking the plot.
Otherwise, is there a way to connect to a double-click event? That way I could print my value only on that event. For the moment I have solved by printing on right-click.
def on_dbl_click(event):
if event.dblclick:
print event.x, event.y
fig, ax = plt.subplots(1, 1)
fig.canvas.mpl_connect('button_press_event', on_dbl_click)
You just need to test if the event has dblcilck set (doc)
This is how I added a "ctrl+c" shortcut to a matplotlib figure. Any figure created with the function below will copy a picture of the figure to the clipboard through "ctrl+c".
import matplotlib.pyplot as plt
from PyQt4 import QtGui
def figure(num = None):
"""Creates and returns a matplotlib figure and adds a 'ctrl+c' shortcut that copies figure to clipboard"""
def on_ctrl_c_click(event):
if event.key == 'ctrl+c' or event.key == 'ctrl+C':
QtGui.QApplication.clipboard().setPixmap(QtGui.QPixmap.grabWidget(fig.canvas))
fig = plt.figure(num)
fig.canvas.mpl_connect('key_press_event', on_ctrl_c_click)
return fig
Here's a simple function to allow panning in all 4 directions using the arrow keys.
import matplotlib.pyplot as plt
def pan_nav(event):
ax_tmp = plt.gca()
if event.key == 'left':
lims = ax_tmp.get_xlim()
adjust = (lims[1] - lims[0]) * 0.9
ax_tmp.set_xlim((lims[0] - adjust, lims[1] - adjust))
plt.draw()
elif event.key == 'right':
lims = ax_tmp.get_xlim()
adjust = (lims[1] - lims[0]) * 0.9
ax_tmp.set_xlim((lims[0] + adjust, lims[1] + adjust))
plt.draw()
elif event.key == 'down':
lims = ax_tmp.get_ylim()
adjust = (lims[1] - lims[0]) * 0.9
ax_tmp.set_ylim((lims[0] - adjust, lims[1] - adjust))
plt.draw()
elif event.key == 'up':
lims = ax_tmp.get_ylim()
adjust = (lims[1] - lims[0]) * 0.9
ax_tmp.set_ylim((lims[0] + adjust, lims[1] + adjust))
plt.draw()
fig = plt.figure()
fig.canvas.mpl_connect('key_press_event', pan_nav)
plt.plot(1, 1, 'ko') # plot something