How can I optimize this 4D contour plot?
8 次查看(过去 30 天)
显示 更早的评论
I am trying to make a 4d contour plot using an array with ua, us, g, delta data plotted in {ua, us, g} 3D space with each point having a value of delta. The 4th value of delta will correspond to a color. The data file is attached as output.txt
There seem to be numerous similar questions to this one, most with answers that suggest using a meshgrid + isosurface + patch approach. I don't think this is applicable for me as I do not have a continuous surface over the 3D space. Rather, I have discrete data that may or may not be linearly spaced in each dimension. In this example, ua locations are exponentially spaced while us and g are linearly spaced.
Here is what I have so far:
name = sprintf('output.txt');
data = readtable(name);
data_arr = table2array(data);
ua = data_arr(:,1);
us = data_arr(:,2);
g = data_arr(:,3);
delta = data_arr(:,4);
figure
h = scatter3(ua, us, g, 12, delta,'MarkerFaceColor', 'Flat','MarkerFaceAlpha',.1,'MarkerEdgeAlpha',0.05);
xlabel('{\mu}_a (mm^{-1})');
ylabel('{\mu}_s (mm^{-1})');
zlabel('g');
grid on
colormap(flipud(turbo))
c=colorbar();
c.Label.String = 'delta';
caxis([0 0.6])
which results in the attached figure. I also pair this with the CaptureFigVid function (https://www.mathworks.com/matlabcentral/fileexchange/41093-create-video-of-rotating-3d-plot) to have a nice rotating video. The idea is that with enough sheets in the ua dimension, I can replicate a continuous 3D contour map. I'd like to optimize this method to create a figure with easily visible color contour in the 3D space. Perhaps someone has some experience with this or tips I can try? Perhaps even there is a better, more sophisticated method.
So far, I've tried to play with the values of
'MarkerFaceAlpha',.1,'MarkerEdgeAlpha',0.05
to make the volume transparent.
Perhaps also I could animate alternating through slices of constant ua, like the last example here: http://web.mit.edu/8.13/matlab/MatlabTraining_IAP_2012/AGV/DemoFiles/ScriptFiles/html/Part7_SlicesIsosurfaces.html. However, it looks like the slice() function is not compatible with data in this style.
Rather than slice, I can use
xslice = 0.230849; %% for instance.
scatter3(xslice,us(ua==xslice),g(ua==xslice),ones(size(us(ua==xslice)))*50,delta(ua==xslice))
and write a for loop to step through each value of ua.
Alternatively, I've added a loop to show the slices for each unique value of ua.
unique_ua=unique(ua);
for i = 1:length(unique_ua)
ua_scatter = repmat(unique_ua(i),M,1);
scatter3(ua_scatter,us(ua==unique_ua(i)),g(ua==unique_ua(i)),ones(size(us(ua==unique_ua(i))))*50,delta(ua==unique_ua(i)))
xlim([0 0.675]);
ylim([0.75 14]);
zlim([0 0.875]);
xlabel('{\mu}_a (mm^{-1})');
ylabel('{\mu}_s (mm^{-1})');
zlabel('g');
grid on
colormap(flipud(turbo))
c=colorbar();
c.Label.String = 'delta';
caxis([0 0.6])
pause(0.01);
end
Any other ideas or tips? Thanks.
0 个评论
采纳的回答
Ran Yang
2023-4-13
It looks like you're trying to visualize volumetric data. One way to do that is with slice, but you need to first restructure your data_arr from an Nx4 array of coordinates and values to a 3D volumetric array. V is also more space efficient since you're not repeating the same coordinate information n = 55 times.
data = readtable('output.txt');
% some overhead
x = data{:, 1}; y = data{:, 2}; z = data{:, 3}; c = data{:, 4};
ux = unique(x); uy = unique(y); uz = unique(z);
% assuming you sampled each data point (x,y,z) exactly once,
% brute force convert data_arr to volumetric array, v
v = zeros(length(ux), length(uy), length(uz));
for i = 1:size(v, 1)
for j = 1:size(v, 2)
for k = 1:size(v, 3)
v(i, j, k) = c(x == ux(i) & y == uy(j) & z == uz(k));
end
end
end
% visualize
figure, slice(ux, uy, uz, v, median(ux), median(uy), median(uz));
From this point you can do whatever you need to prettify your data (such as adjusting colormap, rescaling v, etc.), and it should be compatible with other functions (such as isosurface and contourslice). If you want to visualize an evenly spaced grid, see interp3.
10 个评论
Ran Yang
2023-4-14
This whole x/z axis swapping thing is getting annoying, isn't it?
v = reshape(data_sorted{:, 4}, length(uz), length(uy), length(ux)); % swap x/z
v(v > 15) = 15; % for better visualization of output_blood_2.txt only
figure, slice(uz, uy, ux, v, median(uz), median(uy), median(ux)); % swap x/z
For future reference, that GridVectors error just means that your ux,uy,uz "rescaling" vectors (the first 3 input arguments into slice) don't agree with the dimensions of v. You should always able to see your entire volume just by omitting those 3 scaling arguments and directly calling:
figure, slice(v, ...)
If even that doesn't work, or produces resulting patterns that are different than what you expect, then you'd have a much bigger problem (such as reshape not behaving as expected or your data are not 1:1).
Side note: If you have the time, I would recommend you try to figure out what's up with the whole x/z axis swap. I don't really get why I can't just assign it the proper way (why reshape has to be done using z,y,x instead of x,y,z, nested for loop has to be done z,y,x instead of x,y,z, etc.) Maybe that could even be posted as a separate Question on its own, haha.
更多回答(0 个)
另请参阅
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!