0

Question 1: I am trying to highlight particular section from Vispy Surface Plot example in a particular colour somewhat similar to below modified image.

yellow colour highlight at centre of X-axis

Question 2: Similarly I would like to add an image data as overlay texture to the Vispy surface plot

enter image description here

Can SurfacePlotVisual be used for this? I am unable to find any examples of the SurfacePlotVisual on the internet.

Can anyone please direct me to the efficient way of getting it done using vispy. Thanks

Update 1: Adding Sample code for testing

import sys
import numpy as np

from vispy import app, scene, color
from vispy.util.filter import gaussian_filter
from vispy.visuals.filters import TextureFilter
from vispy.io import imread, load_data_file, read_mesh


canvas = scene.SceneCanvas(keys='interactive', bgcolor='w')
view = canvas.central_widget.add_view()
view.camera = scene.TurntableCamera(up='z', fov=60)

# Simple surface plot example
# x, y values are not specified, so assumed to be 0:50
z = np.random.normal(size=(250, 250), scale=200)
z[100, 100] += 50000
print(z.shape)
z = gaussian_filter(z, (10, 10))


p1 = scene.visuals.SurfacePlot(z=z)  # , color=(0.3, 0.3, 1, 1))
p1.transform = scene.transforms.MatrixTransform()
p1.transform.scale([1 / 249., 1 / 249., 1 / 249.])
p1.transform.translate([-0.5, -0.5, 0])

#verts = p1._meshdata.get_vertices()
verts = p1._meshdata.get_vertices()[:, :2]

texcoords = (verts - verts.min()) / (verts.max() - verts.min())

texture = imread('spot.png')
texture = np.flip(texture, 0) // flip added to get correct position of the image
print("spot.shape:", texture.shape)
print("textcoords:", texcoords)
texture_filter = TextureFilter(texture, texcoords)
p1.attach(texture_filter)

view.add(p1)

xax = scene.Axis(pos=[[-0.5, -0.5], [0.5, -0.5]], tick_direction=(0, -1),
                 font_size=16, axis_color='k', tick_color='k', text_color='k',
                 parent=view.scene)
xax.transform = scene.STTransform(translate=(0, 0, -0.2))

yax = scene.Axis(pos=[[-0.5, -0.5], [-0.5, 0.5]], tick_direction=(-1, 0),
                 font_size=16, axis_color='k', tick_color='k', text_color='k',
                 parent=view.scene)
yax.transform = scene.STTransform(translate=(0, 0, -0.2))

# Add a 3D axis to keep us oriented
axis = scene.visuals.XYZAxis(parent=view.scene)

if __name__ == '__main__':
    canvas.show()
    if sys.flags.interactive == 0:
        app.run()


Update 2:

Have updated above code and output image for reference.

SurfacePlot output with Texture Filter Image

Surface plot output is as above... Would like to remove surface plot shade and instead would like to have same color output for the surface plot output as compared to image....

ViNOJ
  • 15
  • 5

1 Answers1

1

Answer 1

The set_data method of the SurfacePlotVisual takes an array of colors:

https://github.com/vispy/vispy/blob/df6c6be9c5aa6a67abf7e3072780264886e2be77/vispy/visuals/surface_plot.py#L132-L151

You should be able to pass whatever colors you want to that as an RGBA array (MxNx4). Note these are colors for the vertices apparently (based on the code I'm seeing) so colors will be interpolated between vertices.

Answer 2

The SurfacePlot is a subclass of the MeshVisual which is able to have a TextureFilter applied to it. I've never done it, but theoretically you should be able to follow this example to add a texture to your SurfacePlot:

https://vispy.org/gallery/scene/mesh_texture.html

The key parts are the loading of the image data from spot.png and then creating and attaching the TextureFilter.

Update 1

Here's what I get if I change the texcoords line to:

verts = p1._meshdata.get_vertices()[:, :2]

spots on surface plot

Kind of creepy. The point is that we're just making an array that maps the individual surface plot verticies (the mesh vertices) to points on the image. These coordinates need to be between 0 and 1. So we're cheating and taking the vertex coordinates of the mesh and normalizing them between 0 and 1. This may not be anything like what you want, but the point is we have texcoords with a shape of (N, 2) where N is the number of mesh vertices and an (x, y) coordinate for each.

djhoese
  • 3,567
  • 1
  • 27
  • 45
  • With Answer 1, I was able to change color of the surface plot using a set_data method. But for Answer 2 I am not sure how to create a Texture Filter? To create a Texture Filter we require texcoords. How can I get texcoords from my data – ViNOJ Nov 08 '22 at 14:13
  • The texture coordinates would be 2D array with values between 0 and 1 (if I recall recorrectly). They represent the normalized coordinates on the image that will map to your vertices in your surface plot. So if the first element of the texcoords is (0.0, 0.0) then the corner of your surface plot will be the surface of your image. I wonder if we could update vispy to provide a default for this. I'll make an issue for it. – djhoese Nov 08 '22 at 16:45
  • I've created a question for this [here](https://github.com/vispy/vispy/issues/2427). I'm not sure this default behavior is possible though. I was mistaken, the shape of the texcoords is (N, 2) where N is the number of vertices in the mesh...at least I'm pretty sure. The SurfacePlot is hiding the generation of these vertices *but* you may be able to fake it by making a texcoords that is (num_z_rows, num_z_cols, 2) then flattening (`.ravel()`) and providing that as your texcoords. I hope this makes some sense. – djhoese Nov 08 '22 at 16:56
  • Sorry I didn't get how can I get texcoords from the available data which ranges between 0 to 1. I am using a random data of (250, 250) shape for surface plot. For Texture I am using the spot png file for which the shape is (1024, 1024, 3) after imread. Still not sure how to get textcoords from this data for the Texture Filter.. – ViNOJ Nov 09 '22 at 10:06
  • I think it will come down to the conversation in the issue I linked to above. I don't work with meshes a lot so I'm not sure where to go. You could start by doing `verts = surface_plot._meshdata.get_vertices()` and then something like `texcoords = (verts - verts.min()) / (verts.max() - verts.min())`. That's just a hacky way that might give you something. If you can update your question with your version of the code so far maybe I can play with it, but try this suggestion first. – djhoese Nov 09 '22 at 19:22
  • I tried your suggestion but it is giving me error for texcoords dimension (ValueError: Last dimension should be 2 not 3). I have updated question with sample code where filter attachment part has been commented. I am using vispy examples spot.png as the texture image. – ViNOJ Nov 10 '22 at 07:31
  • Thank you @djhoese I have accepted it as answer. I have added flip to the texture data so that the image comes proper. But the color on the surface doesn't match the original texture image. How can I achieve proper texture color on the surface. – ViNOJ Nov 11 '22 at 10:56
  • How can I achieve original color from the texture image instead of surface plot shaded color. I tried playing around with color of the surface plot without any success. @djhoese – ViNOJ Nov 12 '22 at 08:21
  • Make sure the color of the SurfacePlot is set to white (1, 1, 1, 1) and then also pass `shading=None` and see how that looks for you. – djhoese Nov 12 '22 at 21:09
  • Yeah it works as required with shading=None. Thanks @djhoese – ViNOJ Nov 15 '22 at 06:48