Bubbleplot function from file exchange: overlapping text and positioning
    4 Ansichten (letzte 30 Tage)
  
       Ältere Kommentare anzeigen
    
Hello all,
I'm having a hard time figuring out how to place well the data point text on the scatter plot ploted using this function:
I want the text to be at the limit of the marker (circles by default) but I don't figure out a way of doing so. I tried setting the axis units to a different type but nothing.
function [lh, th] = bubbleplot(x, y, z, siz, col, shape, varargin)
error(nargchk(2,10,nargin,'struct'));
% Default z
if nargin < 3
    z = [];
end
% Default size
if nargin < 4 || isempty(siz)
    siz = 8;
end
if nargin < 5 || isempty(col)
    col = z;
end
if nargin < 6 || isempty(shape)
    shape = 'o';
end
p = inputParser;
p.addOptional('Text',{},@(x)iscellstr(x)||(ischar(x)&&size(x,1)>1)||(~ischar(x)&&length(x)>1));
p.addParamValue('ShowText',true);
p.addParamValue('FontSize',8);
p.addParamValue('Alignment', 'left');
p.addParamValue('MarkerSizeLimits',[3 20]);
p.addParamValue('ColorMap',@cool);
p.parse(varargin{:});
desctext = p.Results.Text;
showText = p.Results.ShowText;
if isempty(desctext), showText = false; end
fontSize = p.Results.FontSize;
alignment = p.Results.Alignment;
colmapfun = p.Results.ColorMap;
markerSizeLimits = p.Results.MarkerSizeLimits;
%% Determine marker colors
if ischar(colmapfun)
    colmapfun = str2func(colmapfun);
elseif isnumeric(colmapfun)
    colmapfun = @(x)colmapfun(1:min(x,end),:);
end
if isempty(col)
    col = zeros(size(x));
end
[uniqueCols, gar, colInd] = unique(col);
if isinteger(col) || isa(col,'categorical') || iscell(col) || length(uniqueCols)<=.1*length(col) || all(round(col)==col) % Is col categorical
    % Generate a colormap with one level per unique entry in col
    colmap = colmapfun(length(uniqueCols));
else
    % Scale the color values to span the colormap
    colmap = colmapfun(256);
    mx = max(col);
    n = min(col);
    if mx == n, mx = n + 1; end
    colInd = (col-n)/(mx-n)*(size(colmap,1)-1)+1;
end
try
    color = colmap(round(colInd),:);
catch %#ok<CTCH>
    error('The custom colormap must have at least %d levels', max(colInd));
end
%% Determine marker shape
if ischar(shape)
    markertype = repmat(shape(1),size(x));
else
    markerseq = 'osd^><vph.*+x';
    [uniqueShapes, gar, shapeInd] = unique(shape);
    if length(uniqueShapes)>length(markerseq)
        error('BubblePlot can only support 13 unique shapes');
    end
    markertype = markerseq(shapeInd);
end
%% Determine marker size
if isscalar(siz)
    siz = repmat(siz, size(x));
    markersize = siz;
else % Map the siz variable to a markersize between a minimum and maximum
    minsize = markerSizeLimits(1);
    maxsize = markerSizeLimits(2);
    markersize = (siz - min(siz))/(max(siz)-min(siz))*(maxsize - minsize)+minsize;
end
%% Clean up data - handle NaNs
markersize(isnan(markersize)) = .01; % These will not be drawn as regular markers, just pixel points
%isnan(x) | isnan(y) | isnan(z) | isnan(col) | 
%% Plot data
% Create structure to store original data in every graphics object (for
% subsequent retrieval, eg: with data tip)
pointData = struct('x',num2cell(x),'y',num2cell(y),'siz',num2cell(siz),'col',num2cell(col),...
    'shape',num2cell(shape));
if nargin > 6 && ~isempty(desctext)
    if ~iscellstr(desctext)
        desctext = cellstr(desctext);
    end
    [pointData.text] = desctext{:};
end
if isempty(z)
    plotfun = @plot;
    %plotfun = @patch;
    %zarg = {color(1,:)};
    zarg = {};
else
    plotfun = @plot3;
    zarg = {z(1)};
    zdata = num2cell(z);
    [pointData.z] = zdata{:};
end
lh = zeros(1,length(x)); % Line Handles
lh(1) = customPlot(plotfun, pointData(1), color(1,:), markersize(1), markertype(1), x(1), y(1), zarg{:});
for i = 2:length(lh)
    if isempty(z), zarg = {}; else zarg = {z(i)}; end
    %if isempty(z), zarg = {color(i,:)}; else zarg = {z(i)}; end
    lh(i) = customPlot(@line, pointData(i), color(i,:), markersize(i), markertype(i), x(i), y(i), zarg{:});
    %lh(i) = customPlot(@patch, pointData(i), color(i,:), markersize(i), markertype(i), x(i), y(i), zarg{:});
end
if showText
    hAxes = get(lh(1),'Parent');
    offset = diff(get(hAxes,'Ylim'))*.01;
    if isempty(z)
        z = zeros(size(x));
    end
    th = text(x, y-offset, z, desctext, 'Fontsize', fontSize, 'HorizontalAlignment', alignment);
    lims = get(hAxes,{'XLim','YLim','ZLim'});
    lims = vertcat(lims{:});
    factor = fontSize.*diff(lims,[],2);
    addlistener(hAxes,{'XLim','YLim'},'PostSet',@(obj,evdata)resizeText(hAxes, th, y, factor));
    %addlistener(get(hAxes,'Parent'),'Resize',@(obj,evdata)resizeText(hAxes, th));
else
    th = [];
end
function lh = customPlot(funh, pointData, c, siz, markertype, varargin)
lh = funh(varargin{:});
set(lh, 'Marker', markertype,...
    'LineStyle', 'none', 'Color', c, ...
    'MarkerFaceColor', c, ...
    'MarkerEdgeColor', [0 0 0], 'MarkerSize', siz,...
    'UserData', struct('Point',pointData));
%     lh = patch('XData',x(i),'YData', y(i), 'ZData', z(i), 'Marker', 'o',...
%     'LineStyle', 'none', 'CData', color, 'MarkerFaceColor', c, ...
%     'MarkerEdgeColor', [0 0 0], 'MarkerSize', siz2(i), 'FaceAlpha', .4, 'EdgeAlpha', .2, ...
%     'UserData', data);
function resizeText(hAxes, hText, y, factor) %#ok<*INUSD>
lims = get(hAxes,{'XLim','YLim','ZLim'});
lims = vertcat(lims{:});
% Uncomment following to update fontsize
% newfs = min([factor(1:2)./diff(lims(1:2,:),[],2) ; 24]);
% set(hText,'FontSize',newfs);
% Update position
offset = diff(get(hAxes,'Ylim'))*.01;
p = get(hText,'Position');
p = vertcat(p{:});
outofbounds = any(bsxfun(@gt,p,lims(:,2)') | bsxfun(@lt,p,lims(:,1)'), 2);
set(hText(outofbounds),'Visible','off');
set(hText(~outofbounds),'Visible','on');
% Adjust offsets
p(:,2) = y - offset;
for i = 1:length(p)
    set(hText(i),'Position',p(i,:));
end
I have some points with the same coordinates and the text associated with these points are overlapping. 
I added a function to re-set the text position using the text handle :
function fitText(hText,mrkrSize)
            for i=1:length(hText)
                disp(hText(1).Position)
                disp(mrkrSize(1))
                [newposx, newposy, newposz]=pos(hText(i).Position, mrkrSize(i));
                set(hText(i),'Position',[newposx, newposy, newposz]);
            end
    function [a,b,c] = pos(posX0,mrkrsize)
        a = posX0(1)+mrkrsize/10;
        b = posX0(2)+mrkrsize/10;
        c = posX0(3);
Do you have any clue of doing it properly?
thanking you in advance
1 Kommentar
  darova
      
      
 am 8 Nov. 2019
				Can you show your original image and the picture your want to achieve? Maybe simple drawing?
Antworten (0)
Siehe auch
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!