Comments (11)
The reason I'm using the regular canvas is that the program I built using SceneCanvas and visuals was judged too slow to load and what I have so far using app.Canvas and gloo shaders is way faster. I have not managed to display a visual in a regular canvas. When I add my visual and then call
<TextVisual>.draw()
in myon_draw
function, I get the following error :[...] in _prepare_draw n_pix = (self._font_size / 72.) * transforms.dpi # logical pix TypeError: unsupported operand type(s) for *: 'float' and 'NoneType'
I also tried using scene.visuals.Text but putting the canvas as parent doesn't work as it require a scene (view.scene)
I use visuals a lot in my vispy.app.Canvas
.
For them to work, you need to set the transform of the visual, with:
visual.transforms.configure()
Here is a sample program that works using vispy visuals in the vispy.app.Canvas
:
from PySide6.QtWidgets import *
from PySide6.QtCore import *
from PySide6.QtGui import *
import vispy.app
import vispy.color
import vispy.visuals
class Canvas(vispy.app.Canvas):
def __init__(self):
super().__init__(size = (600,600), parent=None)
self.context.set_clear_color(vispy.color.Color("#ffffff"))
self.text_visual = vispy.visuals.TextVisual("1a 1b", pos=(self.size[0]/2, self.size[1]/2))
# This is the important line here
self.text_visual.transforms.configure(canvas=self)
def on_draw(self, event):
vispy.gloo.clear()
self.text_visual.draw()
def on_resize(self, event):
# This will keep the text visual position and size when resizing the canvas
self.text_visual.transforms.configure(canvas=self)
if __name__ == "__main__":
app = QApplication([])
win = QMainWindow()
canvas = Canvas()
win.setCentralWidget(canvas.native)
win.show()
QApplication.instance().exec()
from vispy.
I guess my first question is: why are you doing this? Is there a reason you can't use the TextVisual
? That should work with the regular Canvas (I think, at least off the top of my head). But also is there a reason you're using the regular Canvas instead of the SceneCanvas?
from vispy.
The reason I'm using the regular canvas is that the program I built using SceneCanvas and visuals was judged too slow to load and what I have so far using app.Canvas and gloo shaders is way faster.
I have not managed to display a visual in a regular canvas. When I add my visual and then call <TextVisual>.draw()
in my on_draw
function, I get the following error :
[...] in _prepare_draw
n_pix = (self._font_size / 72.) * transforms.dpi # logical pix
TypeError: unsupported operand type(s) for *: 'float' and 'NoneType'
I also tried using scene.visuals.Text but putting the canvas as parent doesn't work as it require a scene (view.scene)
from vispy.
Ok. Correct me if I'm wrong, but I don't recall an issue from you on performance issues. So if we've had this discussion before let me know.
How many Visuals were you using in your old SceneCanvas implementation? What was slow about it? Have you tested the exact same equivalent code in your new implementation (same number of GL Programs)? What is different between what your shader code is doing and VisPy's Visuals are doing?
As for the TextVisual, yeah there is a chance that Visual requires a SceneCanvas to figure out the dpi of the system. We should really make that optional though.
from vispy.
What is slow about my previous imlementation is the original setup of the scene, when placing between 64 and 256 signals lasting 20 minutes to an hour sampled at 1024Hz. I also had a grid, a title, a time axis and a view with labels acting a s a y axis. Once set however, the navigation (camera movement) was fast.
from vispy.
Ok and you've tested your current shader/gloo implementation with that many Programs and that much data? If the creation of the Scene was the main problem I'm curious what the main bottleneck was. Are you saying you had 64 to 256 different Visuals for each signal? Usually users complain about the performance from having that many Visuals and that includes the drawing and interaction time. That drawing time is mainly a product of the number of GL programs involved, but if drawing time is not your issue then I'd be curious to see an old version of your code even if you end up going with this gloo version.
I should state explicitly that I don't recommend doing what you're doing unless you are extremely desperate. What typically happens is people have slow drawing so they right stuff with their own custom complex shader code, things work, and then they need more complex features like cameras or clickable objects ("picking" is the term vispy uses) and then they end up having to reimplement what vispy already has. So that's why I'm surprised that your drawing performance was fine and would like to know more.
As for debugging your existing gloo text code, I'm not sure I can help much more than suggesting the obvious of comparing with the TextVisual in vispy. You could copy/paste the TextVisual and then hardcode the dpi (or make a pull request to allow for it as a keyword argument) so you can just reuse what vispy has.
from vispy.
I'm testing my current gloo implementation with an hour long 64 channels signal sampled at 1024Hz with one shader program per channel. I have no performance issues at all.
When I load the same data in my scene implementation, I have a 30 seconds long loading time before I can see and do anything, then having a slow navigation. It features one visual per channel.
If you're curious, here's a chunk of my code handling the channels' shaders :
# Shaders
vertex = """
uniform mat4 projection;
attribute vec2 position;
void main()
{
gl_Position = projection * vec4(position, 0.0, 1.0);
} """
fragment = """
uniform vec3 color;
void main()
{
gl_FragColor = vec4(color, 1);
} """
# Signals
# Time selection
startTime_index = bisect_left(self.time_vector, self.horizontal_scope[0])
endTime_index = bisect_left(self.time_vector, self.horizontal_scope[1])
selected_time_indexes = np.arange(startTime_index, endTime_index, dtype=np.uint32)
# Signals
self.signals_shaders_list = []
self.signals_status_list = []
for i in range(self.channels_number):
shader = gloo.Program(vertex, fragment)
# Position
pos = np.stack([self.time_vector[selected_time_indexes], self.data[i, selected_time_indexes] * self.gain_factor - i * self.spacing * self.spacing_factor], axis=1)
shader['position'] = pos
self.signals_shaders_list.append(shader)
# Status and color
status = False
shader['color'] = (0, 0, 0)
self.signals_status_list.append(status)
# Projection
projection = util.transforms.ortho(self.horizontal_scope[0], self.horizontal_scope[1], self.vertical_scope[0], self.vertical_scope[1], 0, 1)
for shader in self.signals_shaders_list:
shader['projection'] = projection
I want to note that I tried to make the shader as simple/light as possible.
I will now retry to use the visual, following your advice.
from vispy.
I have a 30 seconds long loading time before I can see and do anything, then having a slow navigation.
"navigation" as in interaction? I thought you said the visualization/interaction was fine?
Correct me if I'm wrong, but if you had one visual per signal/line and in your gloo code you have one GL Program (one Visual also uses on GL Program) where you've concatenated all the lines together into segments, you can do that same thing in the LineVisual using the connect
kwarg.
Nope...nevermind, I misread your code. You are making a GL Program for each channel. I would expect the SceneCanvas creation to take a while, but the drawing I would expect to be about the same. Interesting.
from vispy.
Apologies for my late response, I was on an unexpected sick leave (they rarely are)
I made progress ! I manage to display legible text but I still have issues with the sizing.
It seems like the font_size
parameter only affects the width (1 on left and 0.1 on right). Also, resizing the canvas resizes the text.
Hmm, maybe I could add a transform, and update it in the on_resize
function.
I made a child class of TextVisual
with adding the parent canvas as an attribute to be able to get the dpi and px_scale in the _prepare_draw
function.
class TextVisual_ductTaped(TextVisual):
# Init
def __init__(self, canvas, text=None, color='black', bold=False, italic=False, face='OpenSans', font_size=12, pos=[0, 0, 0], rotation=0., anchor_x='center', anchor_y='center', method='cpu', font_manager=None, depth_test=False):
super().__init__(text, color, bold, italic, face, font_size, pos, rotation, anchor_x, anchor_y, method, font_manager, depth_test)
self.unfreeze()
self.canvas = canvas
self.freeze()
# _prepare_draw override
def _prepare_draw(self, view):
# attributes / uniforms are not available until program is built
if len(self.text) == 0:
return False
if self._vertices is None:
text = self.text
if isinstance(text, str):
text = [text]
n_char = sum(len(t) for t in text)
# we delay creating vertices because it requires a context,
# which may or may not exist when the object is initialized
self._vertices = np.concatenate([_text_to_vbo(t, self._font, self._anchors[0], self._anchors[1], self._font._lowres_size) for t in text])
self._vertices = VertexBuffer(self._vertices)
idx = (np.array([0, 1, 2, 0, 2, 3], np.uint32) +
np.arange(0, 4*n_char, 4, dtype=np.uint32)[:, np.newaxis])
self._index_buffer = IndexBuffer(idx.ravel())
self.shared_program.bind(self._vertices)
# This is necessary to reset the GL drawing state after generating
# SDF textures. A better way would be to enable the state to be
# pushed/popped by the context.
self._configure_gl_state()
if self._pos_changed:
# now we promote pos to the proper shape (attribute)
text = self.text
if not isinstance(text, str):
repeats = [4 * len(t) for t in text]
text = ''.join(text)
else:
repeats = [4 * len(text)]
n_text = len(repeats)
pos = self.pos
# Rotation
_rot = self._rotation
if isinstance(_rot, (int, float)):
_rot = np.full((pos.shape[0],), self._rotation)
_rot = np.asarray(_rot)
if _rot.shape[0] < n_text:
_rep = [1] * (len(_rot) - 1) + [n_text - len(_rot) + 1]
_rot = np.repeat(_rot, _rep, axis=0)
_rot = np.repeat(_rot[:n_text], repeats, axis=0)
self.shared_program['a_rotation'] = _rot.astype(np.float32)
# Position
if pos.shape[0] < n_text:
_rep = [1] * (len(pos) - 1) + [n_text - len(pos) + 1]
pos = np.repeat(pos, _rep, axis=0)
pos = np.repeat(pos[:n_text], repeats, axis=0)
assert pos.shape[0] == self._vertices.size == len(_rot)
self.shared_program['a_pos'] = pos
self._pos_changed = False
if self._color_changed:
# now we promote color to the proper shape (varying)
text = self.text
if not isinstance(text, str):
repeats = [4 * len(t) for t in text]
text = ''.join(text)
else:
repeats = [4 * len(text)]
n_text = len(repeats)
color = self.color.rgba
if color.shape[0] < n_text:
color = np.repeat(color, [1]*(len(color)-1) + [n_text-len(color)+1], axis=0)
color = np.repeat(color[:n_text], repeats, axis=0)
assert color.shape[0] == self._vertices.size
self._color_vbo = VertexBuffer(color)
self.shared_program.vert['color'] = self._color_vbo
self._color_changed = False
#transforms = self.transforms
#tr = transforms.get_transform('document', 'render')
#px_scale = (tr.map((1, 0)) - tr.map((0, 1)))[:2]
n_pix = (self._font_size / 72.) * self.canvas.dpi # logical pix
self._text_scale.scale = self.canvas._px_scale * n_pix
self.shared_program.vert['text_scale'] = self._text_scale
self.shared_program['u_npix'] = n_pix
self.shared_program['u_kernel'] = self._font._kernel
self.shared_program['u_color'] = self._color.rgba
self.shared_program['u_font_atlas'] = self._font._atlas
self.shared_program['u_font_atlas_shape'] = self._font._atlas.shape[:2]
from vispy.
Nice hack! And yeah I would guess you need to work with these bits of the code:
vispy/vispy/visuals/text/text.py
Lines 593 to 610 in 83d029b
from vispy.
Wow, it does work wonderfully, thanks a lot !
I just modified the on_resize
function to update the position when resizing
def on_resize(self, event):
# This will keep the text visual position and size when resizing the canvas
self.text_visual.pos = (self.size[0] / 2, self.size[1] / 2)
self.text_visual.transforms.configure(canvas=self)
Thank you two for the help and I hope this will help other users in the future !
from vispy.
Related Issues (20)
- How to render canvas with original pixel values? HOT 13
- The case where the scan lines are parallel to the sides of the rectangle HOT 1
- Cannot find Quartz library on MacOS Sonoma HOT 18
- Issue with Image Clipping in Multiple Viewboxes HOT 3
- how can i disable the canvas border HOT 2
- No setter for some properties of Arrow or Line after instantiation HOT 3
- Question regarding datoviz, backends, gtk HOT 5
- destructive behaviour when lines overlap HOT 1
- Errorous behavior in Vispy.Visuals.Markers.set_data HOT 2
- grid solver constraint not working HOT 4
- Running vispy inside docker and not being able to access OpenGL drivers HOT 1
- SurfacePlotVisual.set_data cause vertex shader to perform unnecessary build HOT 3
- Looking for additional maintainers HOT 12
- vispy flickering on Windows with real time data HOT 12
- How to use a canvas decorator inside a custom class HOT 2
- How to change shortcut for camera Interaction in vispy HOT 2
- VisPy does not work properly if QtWebEngineWidgets is imported HOT 4
- Outdated Vispy version with Debian 12 package HOT 2
- Having problems with TextVisuals and InstancedMesh HOT 9
- Memory usage keep increasing HOT 13
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from vispy.