set_datawith no data. Does that work? Or do you get an error?
mesh_data, is this a MeshData object or is this just the vertices?
This does not appear to be the data coordinates. I would expect that the corners of the screen would be negative at origin and positive at (800,600). Am I not getting the correct transform?
import numpy as np from vispy import visuals, scene, app canvas = scene.SceneCanvas(keys='interactive', show=True) view = canvas.central_widget.add_view() view.camera = scene.TurntableCamera(fov=45) view.camera.distance = 1000 sctr = scene.visuals.create_visual_node(visuals.MarkersVisual) scatter = sctr(parent=view.scene) scatter.set_data(np.stack([np.arange(100) * 100, np.arange(100) * 100, np.linspace(0, 5, 100)], axis=1)) print(canvas.size) >>> (800, 600) transform = scatter.node_transform(view) print(transform.imap((0, 0))) >>> [ 683.63844969 -1185.20109842 790.42826329 1.58113909] print(transform.imap((800, 600))) >>> [ 684.80214175 -1185.00753309 789.71082439 1.58113909] app.run()
create_visual_node. Instead use
scene.visuals.Markerswhich is the same thing, but already done for you. I've been seeing this function pop up a couple times in user code lately. Is there a tutorial or example somewhere that showed it being used?
scatter.transforms.get_transform(...)and read its docstring. It lets you choose which "levels" of the overall series of transforms you use and are considering.
Thanks David. Most of the vispy examples/tutorial/visuals and examples/basics/visuals seem to have used create_visual_node. I saw that it didn't really add much, but I thought that might be a future thing vispy was encouraging users to do. I'll move away from it.
For transforms from mouse event reported coordinates to coordinates in the visual coordinate system, it seems like I would want to transform from canvas to visual:
Visual - arbitrary local coordinate frame of the visual. Vertex buffers used by the visual are usually specified in this coordinate system.
Canvas - This coordinate system represents the logical pixel coordinates of the canvas. It has its origin in the top-left corner of the canvas, and is typically the coordinate system that mouse and touch events are reported in.
transform = scatter.transforms.get_transform('canvas', 'visual') print(transform.map((0, 0))) >>> [ 683.63844969 -1185.20109842 790.42826329 1.58113909] print(transform.map((800, 600))) >>> [ 684.80214175 -1185.00753309 789.71082439 1.58113909]
Seems like the same answer. I guess i'm not sure if even transforming a 2d pixel coordinate to a 3d data coordinate even makes sense. I guess I need to study this a little more to understand what it is doing. Has anyone else talked about selecting 3d data using mouse events? I got the mouse event/camera part fine, just this transformation part has me stuck.
@ericgyounkin About the examples, it looks like the
examples/tutorial use it a lot when they are making their own Visuals and need to use them with the SceneCanvas. I'll have to look into updating the 5 non-tutorial ones that use it. Thanks.
I don't use the TurntableCamera a lot, but it may be messing up your results. I'll try playing with your example code with the 'panzoom' camera later. You may also need to define an STTransform on the visual
scatter.transform = STTransform, but it's early here and I can't seem to get things to make sense.
This works for me ^
import numpy as np from vispy import scene, app from vispy.visuals.transforms import STTransform from vispy.scene import visuals canvas = scene.SceneCanvas(keys='interactive', show=True) view = canvas.central_widget.add_view() #view.camera = scene.TurntableCamera(fov=45) #view.camera.distance = 1000 view.camera = 'panzoom' scatter = visuals.Markers(parent=view.scene) data = np.stack([np.arange(100) * 100, np.arange(100) * 100, np.linspace(0, 5, 100)], axis=1) scatter.set_data(data) print(canvas.size) @canvas.events.mouse_release.connect def on_mouse_release(event): print(event.pos) transform = scatter.transforms.get_transform('canvas', 'visual') print(transform.map(event.pos)) return event app.run()
Hi! I realize this is not the entirely correct place to ask, but seeing as glumpy is the sister project of vispy and since the glumpy chatroom is not very active at the moment, I try anyways:
Right now I am learning about data buffering on the GPU. In the program above (image to the left) I try to
As you can see (image to the right), Python is not reading back what I expected. I am obviously quite the amature, and there is probably something conceptually wrong with my approach here. Does anyone see the problem?
I am trying to create a 2d plot with multiple y axes. I use the scene module. I am able to plot multiple lines on one view but do not understand how to link them to different y axes. I link the axis to the view but do not get how the scene.LinePlot is connected to the axis.
I am also able to plot two views on top of each other, each one with its own y axis. This was a smart solution until I realised that the mouse only affects the top view and when I want to scroll to the right I only change the x axis of that view. So I would need to keep the views in sync which I don't know how to realise as well.
So my question is if this is possible at all (for a mechanical engineer), how to do it or whether there might be an example I have missed that could guide me.
I'm using the AxisWidget and Markers visual to create a scatterplot widget. I'm able to set the domains to the min/max of the data correctly, but I'm not sure how to stretch the axis so that the end of the axis aligns with the end of the data. I've tried using self.axis_x.stretch and using the pos keyword in the AxisWidget init, not really seeing the results. Seems like AxisWidget uses the screen transform over the pos keyword anyway, if I'm understanding it correctly.
Is there some trick to getting the axis to align with the data extents?
self.scatter = scene.visuals.Markers(parent=self.view.scene) self.scatter.set_data(self.displayed_points, edge_color=clrs, face_color=clrs, symbol='o', size=3) self.axis_x = scene.AxisWidget(orientation='bottom', domain=(0, self.x.max() - self.x.min())) self.view.add(self.axis_x) self.axis_z = scene.AxisWidget(orientation='right', domain=(self.z.min(), self.z.max())) self.view.add(self.axis_z)
.transform = STTransform(...)to scale the widget.
sizekeyword argument to the AxisWidget that I think specifies how large it is supposed to be.
from vispy import app, scene import numpy as np class Canvas(scene.SceneCanvas): def __init__(self): scene.SceneCanvas.__init__(self, keys='interactive', show=True) self.size = 1600, 1200 self.unfreeze() self.grid = self.central_widget.add_grid(margin = 10) self.grid.spacing = 0 self.view = self.grid.add_view(row=1, col=1, border_color='white', bgcolor = 'black') self.view2 = self.grid.add_view(row=1, col=1, border_color='white', bgcolor = None) self.view.camera = 'panzoom' self.view2.camera = 'panzoom' self.yaxis = scene.AxisWidget(orientation='left') self.yaxis.width_max = 80 self.grid.add_widget(self.yaxis, row=1, col=0) self.yaxis2 = scene.AxisWidget(orientation='right') self.yaxis2.width_max = 80 self.grid.add_widget(self.yaxis2, row=1, col=2) self.xaxis = scene.AxisWidget(orientation='bottom') self.xaxis.height_max = 80 self.grid.add_widget(self.xaxis, row=2, col=1) self.xaxis2 = scene.AxisWidget(orientation='top') self.xaxis2.height_max = 80 self.grid.add_widget(self.xaxis2, row=0, col=1) self.xaxis2.link_view(self.view2) self.yaxis2.link_view(self.view2) self.xaxis.link_view(self.view) self.yaxis.link_view(self.view) self.freeze() canvas = Canvas() data = np.array([[0.0, 1.0, 2.0], [0.0, 1.5, 0.75]]).transpose() scene.LinePlot(data, parent = canvas.view.scene, color = 'r') data = np.array([[0.0, 1.5, 3.0], [0.0, 1.5, 3.75]]).transpose() scene.LinePlot(data, parent = canvas.view.scene, color = 'y') canvas.view.camera.set_range() data = np.array([[0.0, 1.0, 2.0], [1.0, 0.5, 1.75]]).transpose() scene.LinePlot(data, parent = canvas.view2.scene, color = 'b') canvas.view2.camera.set_range() if __name__ == '__main__': import sys if sys.flags.interactive != 1: app.run()
@chhb:tchncs.de This is a difficult one. I don't think this is possible. The AxisWidget has its
link_view method which ties itself to the view. Every time the view changes (via the camera) the axis is updated. However, there might be some hack-y stuff you could do by modifying
your_axis_widget.transform = STTransform(...). I'm looking at the AxisWidget
_view_changed method and notice all it is doing is transforming the axis end points to new coordinates using the newly changed view transform (and every transform between the view and the widget). I'm not sure what
some_axis_widget.transform is set to by default in this Widget, but if you customized it you might be able to get this to work...
but it definitely isn't supported out of the box.
@djhoese: That is what I feared. 😆 I will try to understand the transform stuff and see if I find a solution.
Thank you very much for looking at my code and for your answer.