Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Marker size unit proportionnal to the axis values

Tags:

matlab

I have an X Y Z dataset. X and Y are the 2D coordinates and Z is the intensity.

I plot the data using the scatter function:

markerSize=100;
scatter(x,y,markerSize,z,'s','fill');

I use the options 's' and 'fill' to get filled squares.

My problem is the markerSize value corresponds to the area of the marker, and its unit is points (1/72 of one inch).

The marker size is constant, even if I resize the figure plot. So that the gap between the data points increases when I increase the figure size.

What I would like is a constant marker size which is a constant of the axis unit. For instance, the marker size should be 5x5 (5 in X axis and 5 in Y axis).

Thanks for your help.

like image 563
Dav Avatar asked Feb 14 '23 08:02

Dav


2 Answers

You want to make the size of markers proportional to the figure size.

The size of markers is controlled by SizeData parameter of the scattergroup object. The size of figure is stored in Position parameter of the figure object. The difficult part is to interactively resize the marker when the figure size is changed. So you need to use ResizeFcn callback and call setmarkersize function that you define.

function [ ] = setmarkersize( src, evnt )

    % # get position of the figure (pos = [x, y, width, height]) 
    pos = get(src, 'Position'); 
    % # get the scattergroup object 
    h = get(get(src,'children'),'children'); 
    % # resize the marker
    relativesize = 0.5;
    set(h,'SizeData', pos(3)*relativesize); 

end
================================================
% # attach the callback to figure 
f = figure('ResizeFcn', @setmarkersize); 
h = scatter(x,y,markerSize,z,'s','fill');
like image 75
ysakamoto Avatar answered Feb 15 '23 21:02

ysakamoto


You will have to set the marker size manually according to the actual figure size on screen. Using axes property Position you can convert data units to relative figure units. In the next step this size can be converted to the absolute size in points on screen. With that information you can set the marker size accordingly. In the following code snippet I've set the x/y axis limits and width/height of the axis to identical values, because the square marker area can only be calculated reasonably if the marker width is equal to the marker height.

Set marker size relative to data units

% test data
x = [25*rand(1,10) 2.5];
y = [25*rand(1,10) 2.5];
z = [rand(1,10) 0.5];

% relative marker size in squared normalized figure units
marker_rel = 5;

%% Set relative marker size (approximately)
scatter(x,y,100,z,'s','fill');

% Set identical x/y limits and set axes height=widht, so that markers
% really represent squares in data units
xlim([0 25]);
ylim([0 25]);
set(gca, 'Units', 'Points');
axpos_pt = get(gca, 'Position');
axpos_pt = [axpos_pt(1) axpos_pt(2) min(axpos(3:4)) min(axpos(3:4))];
set(gca, 'Position', axpos_pt);

grid on;
grid minor;

% Set marker size relative to data units
markerSize = (marker_rel * axpos_pt(3) / diff(xlim))^2;
set(get(gca, 'children'), 'sizedata', markerSize);

As it turns out, the displayed marker size is slightly smaller than expected. Obviously, there's some bounding box of unknown (at least to me) size, see here.

An alternative approach is to plot rectangles "manually" as shown in the following code snippet (same test data is used). When the figure is resized, the rectangles are resized as well without any special callback function being needed.

Draw rectangles manually

%% Use rectangles (exact)
figure;
axes;
cmp = colormap;
z_range = max(z) - min(z);
line_style = 'none'; % set to '-' to make the edges visible
for k = 1:length(x)
    x_pos = x(k) - marker_rel/2;
    y_pos = y(k) - marker_rel/2;
    w = marker_rel;
    h = marker_rel;
    color = cmp( round(((z(k) - min(z))/z_range)*(length(cmp) - 1)) + 1, : );
        rectangle('Position', [x_pos y_pos w h], 'FaceColor', color,...
          'LineStyle', line_style);
end
grid on;
grid minor;

The above code produces the desired marker size:

Demonstration of rectangles with desired size and color grading

In general, these are no squares. They can (and will) only be squares if xlim = ylim and absolute height of axis = absolute width of axis. I have shown in my first code snippet how to achieve this.

like image 33
Deve Avatar answered Feb 15 '23 22:02

Deve