user2752383
user2752383

Reputation: 11

MATLAB: Using scatter3 and mesh at the same time

I have a 3d plot that contains a hemisphere drawn using surf and I am trying to plot more data using scatter3. This works fine as long as the data set I pass to scatter3 contains no more than 2000 points. If there are more than 2000 points, then scatter3 does not plot anything. If I remove the call to surf, then scatter3 works and draws the data.

I have verified that hold is on. I reversed the order of the calls to surf and scatter3 but it did not have any affect. Do I need to switch from scatter3 to plot3 (similar was suggested here) or is there some limit I can change for scatter3?

I am using Matlab 2012b.

EDIT: I did some more digging and looked into the renderers being used. When I do not have the semi-transparent hemisphere displayed, the renderer is "painters" but adding the hemisphere changes the renderer to OpenGL. If I force the renderer to be "painters" (using set(gcf, 'Renderer', 'painters') then scatter3 works properly but I lose the transparency on the hemisphere. This makes sense, but I really need the transparency because part of the data plotted using scatter3 is within the hemisphere. Adding a second axes will not help because the renderer is for the entire figure, not each axes (right?)

Upvotes: 0

Views: 2404

Answers (2)

user2752383
user2752383

Reputation: 11

Unfortunately, I think the "solution" is a bug in the OpenGL renderer in Matlab. When using the OpenGL renderer, Matlab will not display any of the data passed to scatter3 if the last value in the color vector is NaN. Other values in the vector can be NaN, though. As long as the last value is non NaN, there does not appear to be a limit on the number of points supported by scatter3.

This code work calls scatter3 with 2001 random points:

myX = randi(300, 1, 2001)
myY = randi(300, 1, length(myX))
myZ = randi(300, 1, length(myX))
myColors = ones(1, length(myX))
[x,y,z] = sphere(10)

% Figure 1
figure
surf(x*50, y*50, z*50, 'FaceAlpha', 0.2, 'EdgeAlpha', 0.0, 'FaceColor', [1 0 0])
hold on
scatter3(myX, myY, myZ, 100, myColors, 'filled')

If the color vector is changed so the last value is NaN, the resulting plot does not contain any of the scatter3 data

myX = randi(300, 1, 2001)
myY = randi(300, 1, length(myX))
myZ = randi(300, 1, length(myX))
myColors = ones(1, length(myX))
[x,y,z] = sphere(10)

% Figure 1
figure
myColors = ones(1, length(myX))
myColors(1,length(myX)) = NaN;
surf(x*50, y*50, z*50, 'FaceAlpha', 0.2, 'EdgeAlpha', 0.0, 'FaceColor', [1 0 0])
hold on
scatter3(myX, myY, myZ, 100, myColors, 'filled')

It also appears that the OpenGL renderer does not support NaN as a color the same way as the painters renderer. If you run this next example line by line, you can see how the OpenGL renderer displays points that were not displayed by the painters renderer.

myX = randi(300, 1, 10)
myY = randi(300, 1, length(myX))
myZ = randi(300, 1, length(myX))
myColors = ones(1, length(myX))
[x,y,z] = sphere(10)

% Figure 1
figure
myColors(1,1:5) = NaN;
scatter3(myX, myY, myZ, 100, myColors, 'filled')
get(gcf, 'Renderer')

% Figure 2
figure
myColors(1,1:5) = NaN;
scatter3(myX, myY, myZ, 100, myColors, 'filled')
get(gcf, 'Renderer')
hold on
surf(x*50, y*50, z*50, 'FaceAlpha', 0.2, 'EdgeAlpha', 0.0, 'FaceColor', [1 0 0])
get(gcf, 'Renderer')

Rather than rewrite large parts of my program, I am just going to use a logical mark to set update the values in the X vector based on NaN values in the color vector

myX(isnan(myColors)) = NaN

The painters and OpenGL renderers appear to handle NaN as a location the same way.

Hopefully this will help someone who runs into the same issue I did.

Upvotes: 1

marsei
marsei

Reputation: 7751

You may try to use scatter3 and surf within two different axes. The second axes would have the property Visible set to off, and both axes identical limits.

Upvotes: 0

Related Questions