3
votes

I am looking for a robust way to 3D plot particles for which I have the 3D coordinates and radii:

 x=[0 1 1 0 0 1 1 0]';
 y=[0 0 1 1 0 0 1 1]';
 z=[0 0 0 0 1 1 1 1]';
 radius=[0.1 0.5 0.1 1 1 0.4 0.6 0.2]';

I tried using:

 scatter3(x,y,z,4/3*pi.*radius.^3,'filled')

Question: How to plot the particles in a way that guaranties the conservation of the relative size and position (and so when the window size is modified, particles see their size adjusted accordingly with the axis)?

Basically, I would like to get the following graph (which I obtained using Ovito, from a .xyz (text) file I generated (it contains [x;y;z;radius])) in MATLAB, with the possibility to adjust the size of the graph window and still get the proper axis scales with respect to the apparent size of the particles):

3D plot of the particles, the color and the size of which represent the radius. Note that the size of the particles is computed that's to the radius.

2
1) From scatter3's doc, it is also area. 2) It can be done via the figure's SizeChangedFunction. But how would you define relative size of the marks? Would it be relative to the figure's height? Width? Area? - Luis Mendo
By relative size I mean that the marker size is set accordingly with respect to the size of the window, the axis... - LeChat

2 Answers

1
votes

The fourth argument to scatter3 defines the marker area in units of square points (1 point = 1/72 inch), which is relative to the figure/screen size and therefore not related to the axes data units. If you want to define the radius of your particles relative to the positional data (such that a particle with radius 1 at the origin will span [-1 1] in the x, y, and z directions) then scatter3 isn't going to work.

One option is to plot each particle as a sphere using surf, as illustrated here. Here's how you can do this, using your sample data:

% Data and unit sphere surface coordinates:
x = [0 1 1 0 0 1 1 0].';
y = [0 0 1 1 0 0 1 1].';
z = [0 0 0 0 1 1 1 1].';
radius = [0.1 0.5 0.1 1 1 0.4 0.6 0.2].';
[xS, yS, zS] = sphere;

% Plot spheres:
for pt = 1:numel(x)
  surf(x(pt)+xS.*radius(pt), ...  % Shift and scale x data
       y(pt)+yS.*radius(pt), ...  % Shift and scale y data
       z(pt)+zS.*radius(pt), ...  % Shift and scale z data
       'EdgeColor', 'none');
  hold on;
end

% Modify figure and axes:
axis equal
set(gcf, 'Color', 'k');
set(gca, 'Color', 'k', 'Box', 'on', 'BoxStyle', 'full', ...
    'XColor', 'w', 'YColor', 'w', 'ZColor', 'w', 'GridColor', 'none');

And here's the plot this produces:

enter image description here

Notice that the surfaces are colored by default based on height. If you want to color them differently, you can modify the CData and FaceColor properties of the surfaces. For example, you can give each surface a flat color based on its radius value (which will be mapped to the current colormap) by modifying the surf call above to this:

surf(x(pt)+xS.*radius(pt), ...
     y(pt)+yS.*radius(pt), ...
     z(pt)+zS.*radius(pt), ...
     radius(pt).*ones(size(xS)), ...
     'FaceColor', 'flat', 'EdgeColor', 'none');
0
votes

Ok found it. Thanks to @gnovice also (thank you mate). In the following, the color of each particle is chosen according to its radius.

packing. Colors reflect the radius. Here is the code:

figure
[xS, yS, zS] = sphere;
cmap=parula(length(x));
radius_sort = sort(radius);
% Plot spheres:
for pt = 1:numel(x)
    cmap_ind = find(radius_sort == radius(pt));
  hs=surf(x(pt)+xS.*radius(pt), ...  % Shift and scale x data
       y(pt)+yS.*radius(pt), ...  % Shift and scale y data
       z(pt)+zS.*radius(pt), ...  % Shift and scale z data
       'EdgeColor', 'none');
       set(hs,'FaceColor',cmap(cmap_ind(1),:))
  hold on;
end

One can also add the following commands to tune the axis and figure colors:

% Modify figure and axes:
axis equal
set(gcf, 'Color', 'k');
set(gca, 'Color', 'k', 'Box', 'on', 'BoxStyle', 'full', ...
    'XColor', 'w', 'YColor', 'w', 'ZColor', 'w', 'GridColor', 'none');