plot magnitude data at location (x,y,z)

I can't figure out how to plot magnitudes of a variable at different (x,y,z) locations. In effect, I need to plot a 4D plot, (x,y,z,value). I thought I'd be able to do a 3D plot and set the 4D as color scale or something like that, but I can't figure how to do that.
Perhaps I'm over thinking this....but, I'd appreciate any help.
Thanks!
Jorge

 Accepted Answer

@Jorge
Try this —
LD = load('data')
LD = struct with fields:
data: [201x4 double]
x = LD.data(:,1);
y = LD.data(:,2);
z = LD.data(:,3);
c = LD.data(:,4);
figure
stem3(x, y, z)
hold on
scatter3(x, y, z, 100, c, 'filled')
hold off
CL = clim;
colormap(turbo)
xlabel('X')
ylabel('Y')
zlabel('Z')
view(130,30)
Zfcn = scatteredInterpolant(x, y, z, 'natural','none'); % Create Surface Matrix
Warning: Duplicate data points have been detected and removed - corresponding values have been averaged.
Cfcn = scatteredInterpolant(x, y, c, 'natural','none'); % Create Colour MAtrix
Warning: Duplicate data points have been detected and removed - corresponding values have been averaged.
N = numel(x);
xv = linspace(min(x), max(x), N);
yv = linspace(min(y), max(y), N);
[Xm,Ym] = ndgrid(xv, yv);
Zm = Zfcn(Xm, Ym);
Cm = Cfcn(Xm, Ym);
figure
surfc(Xm, Ym, Zm, Cm, 'EdgeColor','interp')
clim(CL)
colormap(turbo)
xlabel('X')
ylabel('Y')
zlabel('Z')
view(130,30)
The only change from my previous answer was using your data. Some parts do not interpolate well and leave gaps, however that appears to be inhereint in your data, at least as far as scatteredInterpolant interprets them.
.

13 Comments

excellent, thank you!
As always, my pleasure!
btw, I was in the process of responding to your first proposed solution when you responded again using the my sample data. Thank you!
As always, my pleasure!
When I checked and saw that you had posted a comment, I wanted to see what you wrote. At that point I saw the file and then adapted it to my existing code.
Can you try it with the whole data? I think the duplicate values are affecting the result. I think the
Zfcn = scatteredInterpolant(x, y, z,'natural','none'); % Create Surface Matrix
should be
Zfcn = scatteredInterpolant(x, y, z,val,'natural','none'); % Create Surface Matrix
?
attached is the full data...
Thanks again.
I only unaccepted the previous answer in case accepting it "close" this question and you'd never see my new (continuation) issue. thanks
The scatteredInterpolant function replaces the mean of the duplicated values with the duplicate values and deletes the others. Note that ‘data’ appears as a structure loading it into a avariable, and simply a matrix otherwsie. I don’t know what ‘val’ is, since ‘data’ is a matrix and not a table, so I assume the fourth column is the fourth dimension that is to be used to assign the colours.
In this instance, with the duplicated values, it takes the mean of each duplicate and plots it as the mean of the values. Here, there are four distinct ‘layers’, and each layer must be rencered separately.
This is what I get with the new ‘data.mat’ file —
load('data')
whos( '-file','data')
Name Size Bytes Class Attributes data 560x4 17920 double
LD = load('data')
LD = struct with fields:
data: [560x4 double]
x = LD.data(:,1);
y = LD.data(:,2);
z = LD.data(:,3);
c = LD.data(:,4);
figure
stem3(x, y, z)
hold on
scatter3(x, y, z, 100, c, 'filled')
hold off
CL = clim;
colormap(turbo)
xlabel('X')
ylabel('Y')
zlabel('Z')
view(-45,30)
[Uz,ixs,ixv] = unique(z);
L = accumarray(ixv, (1:numel(ixv)).', [], @(v) {[x(v) y(v) z(v) c(v)]})
L = 5x1 cell array
{112x4 double} {112x4 double} {112x4 double} {112x4 double} {112x4 double}
figure
hold on
for k = 1:numel(L)
x = L{k}(:,1);
y = L{k}(:,2);
z = L{k}(:,3);
c = L{k}(:,4);
Zfcn = scatteredInterpolant(x, y, z, 'natural','none'); % Create Surface Matrix
Cfcn = scatteredInterpolant(x, y, c, 'natural','none'); % Create Colour MAtrix
N = numel(x);
xv = linspace(min(x), max(x), N);
yv = linspace(min(y), max(y), N);
[Xm,Ym] = ndgrid(xv, yv);
Zm = Zfcn(Xm, Ym);
Cm = Cfcn(Xm, Ym);
surf(Xm, Ym, Zm, Cm, 'EdgeColor','interp')
clim(CL)
colormap(turbo)
end
hold off
xlabel('X')
ylabel('Y')
zlabel('Z')
view(-45,30)
grid on
figure
hold on
for k = 1:numel(L)
x = L{k}(:,1);
y = L{k}(:,2);
z = L{k}(:,3);
c = L{k}(:,4);
Zfcn = scatteredInterpolant(x, y, z, 'natural','none'); % Create Surface Matrix
Cfcn = scatteredInterpolant(x, y, c, 'natural','none'); % Create Colour MAtrix
N = numel(x);
xv = linspace(min(x), max(x), N);
yv = linspace(min(y), max(y), N);
[Xm,Ym] = ndgrid(xv, yv);
Zm = Zfcn(Xm, Ym);
Cm = Cfcn(Xm, Ym);
surf(Xm, Ym, Zm, Cm, 'EdgeColor','interp')
clim(CL)
colormap(turbo)
end
hold off
xlabel('X')
ylabel('Y')
zlabel('Z')
view(-45,30)
grid on
daspect(gca, [2.5 1 5])
I doubt that a volumetric version of this is possible, since that is not how the data are arranged. Plotting four distinct layers is likely the best possible outcome. It is possible to ‘squash’ it a bit in the z-direction, however that does not appear to accomplish much. Experiment with the daspect call to change the aspect ratios of the axes. (Assigning them as [1 1 1] is the same as axis('equal').)
EDIT — (23 Aug 2024 at 12:01)
Changed explicit loop to accumarray call to produce ‘L’.
.
this is great, and i agree that the unsquished version is probably the most informative version. Thank you.
however, i still don't really understand how you are getting these plots. the collected data is arranged into matrix and is all unique. the first three columns are x, y ,z coordinates, and the last column has the measurement value at each fof those coordinates. there are no duplicate rows; each row is a new coordinate and measurement.
for example, row 1 has the 3D position in space as located by the first three columns of the matrix, (x,y,z), respectively, and the magnetic field strength measured at that location is stored in the fourth column. the scatter plot is showing this correctly, but I'm not sure if the surf plot is converying the same info- because i dont really understand how it is set up. I'm gonna try to follow how/why you did what you did. Thank you!
Star Strider
Star Strider on 23 Aug 2024
Edited: Star Strider on 23 Aug 2024
I don’t understand what the problem is. After looking at the scatter3 plot, it was obvious that there are five discrete layers in the data, so I used accumarray to separate the data into each ‘L’ layer:
[Uz,ixs,ixv] = unique(z);
L = accumarray(ixv, (1:numel(ixv)).', [], @(v) {[x(v) y(v) z(v) c(v)]})
with ‘Lv’ being a logical vector, and then did the same interpolation and surf plot with each ‘L’ matrix and then plotted them together using hold. That’s all there is to it.
EDIT — (23 Aug 2024 at 12:03)
Updated text to include the accumarray call.
if you have the time to explain it to me, let me try to break it down so you can understand what I don't understand. If you want to move on, that's fine too, no worries.
1) why do you need to do unique z, when every row in the matrix is 'unique"?
2) wht is this exactly doing:
Zfcn = scatteredInterpolant(x, y, z, 'natural','none');
why do we need to interpolate the z values when I have them --they are fixed coordinates?
3) In my mind, I figured all we had to do was somehow create a 3d grid or mesh, and then map the value on column for to the respective location in the grid.
For example, if I had only a 2D data (x,y, value).
I could use meshgrid to create the cartesian grid, and then I would have to figure out how to map each value v to its respectdive (x,y) coordinate. Perhaps that is the crux of the thing....I don't understand how what you did does that (in this case in 3D, but I don't understand it for the 2D case either).
I'm going to continue playing with what you did above until I figure it out.
thank you.
The values may be ‘unique’ in some sense, however the matrix itself is scattered. You can see that by displaying it. That is the first thing I did, because if it was truly gridded, I would have only needed to use the reshape function to create matrices from the various vectors, once I got them separated by rows according to the ‘z’ values. (That would also have required the unique funciton in order to determine the rows at which ‘z’ changed value.)
The unique call is used to provide a vector ‘ixv’ that returns the positions of every row corresponding to specific values of ‘z’ (since it defines the layers), and sorts them (although the sorting is not specifically necessary and can be suppressed by using the 'stable' argument to unique). My code then uses that vector to separate out the corresponding values of the original matrix into five equal-size cell arrays corresponding to each specific ‘z’ value, using accumarray to do this. (The accumarray function is more efficient than the loop I used originally, so I replaced it.) The cell arrays do not have to be the same size, however they are in these data.
It is necessary to interpolate the ‘z’ values in order to create the surfaces. The scattteredInterpolant function creates the interpolation function ‘Zfcn’ that then uses the ‘Xm’ and ‘Ym’ matrices created from the ‘xv’ and ‘yv’ vectors to interpolate the surface that then exists as ‘Zm’ (the surface values) and ‘Cm’ (the surface colours). Interpolating to a finer grid (the result of the ndgrid call) produces more detail.
If you only have a 2D data, you cannot create a surface from it, since it lacks the third dimension. The data already have to exist in 3D in order to create a surface plot. With 2D data, you can createa line plot and then interpolate it as a line in 2D in order to add more data points and perhaps smooth it a bit (using 'pchip', 'spline' or 'makima' interpolation methods), however that is all you can do.
See the documentation for the various functions for details.
thanks for taking the time to explain!
As always, my pleasure!
The purpose of MATLAB answers is to provide solutions, as well as education in various contexts.

Sign in to comment.

More Answers (1)

Here is one way where you use colors to indicate the magnitude;
% random data
x = [0:pi/50:10*pi nan]; % nan is added to remove connection between first and last data point
y = sin(x);
z = cos(x);
m = x; % magnitude you want as colors, i set it to x cause it looks nice :D
colormap(winter)
patch(x,y,z,m,'Facecolor','none','EdgeColor','interp')
colorbar
view(3)

2 Comments

Thank you for you input. That does give me something I can use, but I'm left wondering if there is yet a better way to display the data. Here's a sample of data I collected in the lab. The data has the coordinates of the x,y,z fixture, and the values measured. The format is [x,y,z,value]. if you think of a better, please let me know. I appreciate the help. Thank you.
Here is similar scatter3 way with your code:
load('data.mat')
x = data(:,1);
y = data(:,2);
z = data(:,3);
m = data(:,4);
scatter3(x,y,z,100,m,'filled')
colorbar
view(-15,10)

Sign in to comment.

Categories

Products

Release

R2023b

Asked:

on 22 Aug 2024

Commented:

on 23 Aug 2024

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!