【Matlab】多维数据可视化方法之雷达图和气泡图

今天浏览了Matlab官网,看了一下官网提供的Matlab的绘图工具箱,因为很多之前没有注意到,部分虽然自己可以实现,但是功能不够完善,因此,今天做一下工具箱的总结,以用来记录自己的学习过程,详情请移步MathWorks绘图专区入口

目录

1. 雷达图

2. 多维数据可视化之气泡图

2.1 加载数据

2.2 3D气泡图

2.3 可点击图例

2.4 七维数据的3D可视化效果图

2.5 五维数据的2D可视化效果图


1. 雷达图

雷达图,又称为蜘蛛图,MathWorks中有位大佬提供了具体的画法,这里给出其实例:

%% Example Script %%%
% Clear workspace
close all;
clearvars;
clc;

% Point properties
num_of_points = 6;
row_of_points = 4;

% Random data
P = rand(row_of_points, num_of_points);

% Scale points by a factor
P(:, 2) = P(:, 2) * 2;
P(:, 3) = P(:, 3) * 3;
P(:, 4) = P(:, 4) * 4;
P(:, 5) = P(:, 5) * 5;

% Make random values negative
P(1:3, 3) = P(1:3, 3) * -1;
P(:, 5) = P(:, 5) * -1;

% Create generic labels
P_labels = cell(num_of_points, 1);

for ii = 1:num_of_points
P_labels{ii} = sprintf('Label %i', ii);
end

% Figure properties
figure('units', 'normalized', 'outerposition', [0 0.05 1 0.95]);

% Axes properties
axes_interval = 2;
axes_precision = 1;

% Spider plot
spider_plot(P, P_labels, axes_interval, axes_precision,...
'Marker', 'o',...
'LineStyle', '-',...
'LineWidth', 2,...
'MarkerSize', 5);

% Title properties
title('Sample Spider Plot',...
'Fontweight', 'bold',...
'FontSize', 12);

% Legend properties
legend('show', 'Location', 'southoutside');

笔者喜欢一步到位,下面是雷达图实现的源码,后期可能更新有所不同,不过只要知道大概意思就行,大家可以在次基础上改:

function spider_plot(P, P_labels, axes_interval, axes_precision, varargin)
% Create a spider web or radar plot with an axes specified for each column
%
% spider_plot(P, P_labels, axes_interval, axes_precision) creates a spider
% web plot using the points specified in the array P. The column of P
% contains the data points and the rows of P contain the multiple sets of
% data points. Each point must be accompanied by a label specified in the
% cell P_labels. The number of intervals that separate the axes is
% specified by axes_interval. The number of decimal precision points is
% specified by axes_precision.
% 
% P - [vector | matrix]
% P_labels - [cell of string]
% axes_interval - [integer]
% axes_precision - [integer]
%
% spider_plot(P, P_labels, axes_interval, axes_precision, line_spec) works
% the same as the function above. Additional line properties can be added
% in the same format as the default "plot" function in MATLAB.
%
% line_spec - [character vector]
%
% %%%%%%%%%%%%%%%%%%% Example of a Generic Spider Plot %%%%%%%%%%%%%%%%%%%
% % Clear workspace
% close all;
% clearvars;
% clc;
% 
% % Point properties
% num_of_points = 6;
% row_of_points = 4;
%
% % Random data
% P = rand(row_of_points, num_of_points);
%
% % Scale points by a factor
% P(:, 2) = P(:, 2) * 2;
% P(:, 3) = P(:, 3) * 3;
% P(:, 4) = P(:, 4) * 4;
% P(:, 5) = P(:, 5) * 5;
%
% % Make random values negative
% P(1:3, 3) = P(1:3, 3) * -1;
% P(:, 5) = P(:, 5) * -1;
% 
% % Create generic labels
% P_labels = cell(num_of_points, 1);
% 
% for ii = 1:num_of_points
%     P_labels{ii} = sprintf('Label %i', ii);
% end
% 
% % Figure properties
% figure('units', 'normalized', 'outerposition', [0 0.05 1 0.95]);
% 
% % Axes properties
% axes_interval = 2;
% axes_precision = 1;
% 
% % Spider plot
% spider_plot(P, P_labels, axes_interval, axes_precision,...
%     'Marker', 'o',...
%     'LineStyle', '-',...
%     'LineWidth', 2,...
%     'MarkerSize', 5);
% 
% % Title properties
% title('Sample Spider Plot',...
%     'Fontweight', 'bold',...
%     'FontSize', 12);
% 
% % Legend properties
% legend('show', 'Location', 'southoutside');
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%% Point Properties %%%
% Number of points
[row_of_points, num_of_points] = size(P);

%%% Error Check %%%
% Check if axes properties are an integer
if floor(axes_interval) ~= axes_interval || floor(axes_precision) ~= axes_precision
    error('Error: Please enter in an integer for the axes properties.');
end

% Check if axes properties are positive
if axes_interval < 1 || axes_precision < 1
    error('Error: Please enter value greater than one for the axes properties.');
end

% Check if the labels are the same number as the number of points
if length(P_labels) ~= num_of_points
    error('Error: Please make sure the number of labels is the same as the number of points.');
end

% Pre-allocation
max_values = zeros(1, num_of_points);
min_values = zeros(1, num_of_points);
axis_increment = zeros(1, num_of_points);

% Normalized axis increment
normalized_axis_increment = 1/axes_interval;

% Iterate through number of points
for ii = 1:num_of_points
    % Group of points
    group_points = P(:, ii);
    
    % Max and min value of each group
    max_values(ii) = max(group_points);
    min_values(ii) = min(group_points);
    range = max_values(ii) - min_values(ii);
    
    % Axis increment
    axis_increment(ii) = range/axes_interval;
    
    % Normalize points to range from [0, 1]
    P(:, ii) = (P(:, ii)-min(group_points))/range;
    
    % Shift points by one axis increment
    P(:, ii) = P(:, ii) + normalized_axis_increment;
end

%%% Polar Axes %%%
% Polar increments
polar_increments = 2*pi/num_of_points;

% Normalized  max limit of axes
axes_limit = 1;

% Shift axes limit by one axis increment
axes_limit = axes_limit + normalized_axis_increment;

% Polar points
radius = [0; axes_limit];
theta = 0:polar_increments:2*pi;

% Convert polar to cartesian coordinates
[x_axes, y_axes] = pol2cart(theta, radius);

% Plot polar axes
grey = [1, 1, 1] * 0.5;
h = line(x_axes, y_axes,...
    'LineWidth', 1,...
    'Color', grey);

% Iterate through all the line handles
for ii = 1:length(h)
    % Remove polar axes from legend
    h(ii).Annotation.LegendInformation.IconDisplayStyle = 'off';
end

%%% Polar Isocurves %%%
% Shifted axes interval
shifted_axes_interval = axes_interval+1;

% Incremental radius
radius = (0:axes_limit/shifted_axes_interval:axes_limit)';

% Convert polar to cartesian coordinates
[x_isocurves, y_isocurves] = pol2cart(theta, radius);

% Plot polar isocurves
hold on;
h = plot(x_isocurves', y_isocurves',...
    'LineWidth', 1,...
    'Color', grey);

% Iterate through all the plot handles
for ii = 1:length(h)
    % Remove polar isocurves from legend
    h(ii).Annotation.LegendInformation.IconDisplayStyle = 'off';
end

%%% Figure Properties %%%
colors = [0, 0.4470, 0.7410;...
    0.8500, 0.3250, 0.0980;...
    0.9290, 0.6940, 0.1250;...
    0.4940, 0.1840, 0.5560;...
    0.4660, 0.6740, 0.1880;...
    0.3010, 0.7450, 0.9330;...
    0.6350, 0.0780, 0.1840];

% Repeat colors is necessary
repeat_colors = fix(row_of_points/size(colors, 1))+1;
colors = repmat(colors, repeat_colors, 1);

%%% Data Points %%%
% Iterate through all the rows
for ii = 1:row_of_points
    % Convert polar to cartesian coordinates
    [x_points, y_points] = pol2cart(theta(1:end-1), P(ii, :));
    
    % Make points circular
    x_circular = [x_points, x_points(1)];
    y_circular = [y_points, y_points(1)];
    
    % Plot data points
    plot(x_circular, y_circular,...
        'Color', colors(ii, :),...
        'MarkerFaceColor', colors(ii, :),...
        varargin{:});
end

%%% Axis Properties %%%
% Figure background
fig = gcf;
fig.Color = 'white';

% Iterate through all the number of points
for hh = 1:num_of_points
    % Shifted min value
    shifted_min_value = min_values(hh)-axis_increment(hh);
    
    % Axis label for each row
    row_axis_labels = (shifted_min_value:axis_increment(hh):max_values(hh))';
    
    % Iterate through all the isocurve radius
    for ii = 2:length(radius)
        % Display axis text for each isocurve
        text(x_isocurves(ii, hh), y_isocurves(ii, hh), sprintf(sprintf('%%.%if', axes_precision), row_axis_labels(ii)),...
            'Units', 'Data',...
            'Color', 'k',...
            'FontSize', 10,...
            'HorizontalAlignment', 'center',...
            'VerticalAlignment', 'middle');
    end
end

% Label points
x_label = x_isocurves(end, :);
y_label = y_isocurves(end, :);

% Shift axis label
shift_pos = 0.07;

% Iterate through each label
for ii = 1:num_of_points
    % Angle of point in radians
    theta_point = theta(ii);
    
    % Find out which quadrant the point is in
    if theta_point == 0
        quadrant = 0;
    elseif theta_point == pi/2
        quadrant = 1.5;
    elseif theta_point == pi
        quadrant = 2.5;
    elseif theta_point == 3*pi/2
        quadrant = 3.5;
    elseif theta_point == 2*pi
        quadrant = 0;
    elseif theta_point > 0 && theta_point < pi/2
        quadrant = 1;
    elseif theta_point > pi/2 && theta_point < pi
        quadrant = 2;
    elseif theta_point > pi && theta_point < 3*pi/2
        quadrant = 3;
    elseif theta_point > 3*pi/2 && theta_point < 2*pi
        quadrant = 4;
    end
    
    % Adjust text alignment information depending on quadrant
    switch quadrant
        case 0
            horz_align = 'left';
            vert_align = 'middle';
            x_pos = shift_pos;
            y_pos = 0;
        case 1
            horz_align = 'left';
            vert_align = 'bottom';
            x_pos = shift_pos;
            y_pos = shift_pos;
        case 1.5
            horz_align = 'center';
            vert_align = 'bottom';
            x_pos = 0;
            y_pos = shift_pos;
        case 2
            horz_align = 'right';
            vert_align = 'bottom';
            x_pos = -shift_pos;
            y_pos = shift_pos;
        case 2.5
            horz_align = 'right';
            vert_align = 'middle';
            x_pos = -shift_pos;
            y_pos = 0;
        case 3
            horz_align = 'right';
            vert_align = 'top';
            x_pos = -shift_pos;
            y_pos = -shift_pos;
        case 3.5
            horz_align = 'center';
            vert_align = 'top';
            x_pos = 0;
            y_pos = -shift_pos;
        case 4
            horz_align = 'left';
            vert_align = 'top';
            x_pos = shift_pos;
            y_pos = -shift_pos;
    end
    
    % Display text label
    text(x_label(ii)+x_pos, y_label(ii)+y_pos, P_labels{ii},...
        'Units', 'Data',...
        'HorizontalAlignment', horz_align,...
        'VerticalAlignment', vert_align,...
        'EdgeColor', 'k',...
        'BackgroundColor', 'w');
end

% Axis limits
axis square;
axis([-axes_limit, axes_limit, -axes_limit, axes_limit]);
axis off;
end

2. 多维数据可视化之气泡图

真的是很棒,之前虽然笔者也曾写过五维的数据可视化气泡图,相比大佬,自叹望尘莫及:Bubbleplot visualization of multi-dimensional data。该工具箱可以创建2维和三维散点图,最多可以利用颜色、形状、大小以及标注文本可视化七个维度的数据信息。绘制气泡图的工具箱源码如下:

function [lh, th] = bubbleplot(x, y, z, siz, col, shape, varargin)
% BUBBLEPLOT produces a scatter plot that enables the visualization of upto 
% 6-dimensional data. The dimensions used for displaying data include the 
% X, Y and Z coordinates, the marker size, color and shape. 
%
% USAGE: 
% BUBBLEPLOT(x, y, z, siz, col, shape)
%    draws a 3D bubble plot. See input parameter description below.
%
% BUBBLEPLOT(x, y, [], siz, col, shape)
%    draws a 2D bubble plot. 
%
% BUBBLEPLOT(..., textarray)
%    enables you to pass in a cell array of strings to annotate each point
%    on the plot. By default the strings are displayed as text labels as well
%    as stored in the UserData property of the line objects
%
% BUBBLEPLOT(..., textarray, 'ShowText', false)
%    will not display the text on screen, but will store it in the user
%    data property. This can be useful when creating a custom data tip.
%
% [hLine, hText] = BUBBLEPLOT(...)
%    returns a vector of line handles to the points in the plot and 
%    (if appropriate) a vector of handles to the text objects on the
%    screen.
%
% INPUT PARAMETERS:
% The inputs should be vectors of the same length, with the following
% requirements:
%  Input     Required     Default-Value         Type
% x, y, z      Yes             N/A          Numerical (Continuous or discrete)
%   siz         No              8           Numerical (Continuous or discrete)
%   col         No           col = z        Numerical or Categorical*
%  shape        No             'o'          Categorical* (upto 13 unique discrete values)
% 
% NOTES:
% * "Categorical" variables can either be numeric with discrete values or
%   non-numeric data types that support a "UNIQUE" method. Examples of this
%   can be a cell array of strings, a nominal array or ordinal array.
%
% * The siz variable is normalized to a marker size range of 3 to 20. To
%   specify a custom size range use the optional parameter
%   'markerSizeLimits'. Example: BUBBLEPLOT(..., 'MarkerSizeLimits', [5 32])
%
% * The shape variable can also be a character that represents a marker
%   shape to be used for all points
%
% * If col is a categorical variable, ensure it is integer-valued so that
%   it is handled correctly. If it is not integer valued, BUBBLEPLOT will
%   check to see if the number of unique values is less than 10% of the
%   length of the vector and use that to determine if the variable is
%   categorical. The colors used to depict categorical data are evenly
%   spaced (1 color level per unique category/label). However if col is
%   not categorical, its values are simply scaled to different values in
%   the colormap
%
% * The default font size used to display the text labels is 8 pt with a
%   left alignment. Use the input arguments 'FontSize' and 'Alignment' to
%   control these properties.
%   Example: BUBBLEPLOT(..., 'FontSize', 6, 'Alignment', 'center')
%
% * You can specify a custom colormap using the Colormap argument. The
%   parameter can be a string (eg. 'cool'), a function handle (eg. @jet) or 
%   an N-by-3 matrix of color RGB levels.
%   Example: BUBBLEPLOT(..., 'ColorMap', cmap)

% Copyright 2009-2014 The MathWorks, Inc.

%% Parse input params and defaults

% Check number of input arguments
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

2.1 加载数据

加载随机样本数据:

load carsmall
Origin = cellstr(Origin);

2.2 3D气泡图

  • X: Acceleration (continuous)
  • Y: Horsepower (continuous)
  • Z: MPG (continuous)
  • Size: Weight (continuous)
  • Color: Model_Year (discrete, ordinal)
  • Shape: Origin
clf
bubbleplot(Acceleration, Horsepower, MPG, Weight, Model_Year, Origin);
grid on
xlabel('Acceleration');ylabel('Horsepower');zlabel('MPG');

2.3 可点击图例

可点击图例可以让你能够隐藏或者强调某一组数据,需要用到 clickableLegend 工具箱的源码如下:

function varargout = clickableLegend(varargin)
% clickableLegend  Interactive legend for toggling or highlighting graphics
%
% clickableLegend is a wrapper around the LEGEND function that provides
% interactive display toggling or highlighting of lines or patches in a MATLAB
% plot. It enables you to,
% * Toggle (hide/show) a graphics object (or group) by clicking on an
%   associated text label in the legend
% * Highlight and identify a graphics object (or group) by clicking it. 
%
% Its usage is the same as the <a href="matlab: help legend">LEGEND</a> function with additional
% optional parameters. For further information please see the LEGEND documentation.
%
% ADDITIONAL ARGUMENTS specific to clickableLegend:
% These are passed in as parameter-value pairs
%
% * groups: A vector specifying the group membership for every line object.
%   The grouping parameter lets you have a group of lines represented and
%   controlled by one entry in the legend. This can be useful if you would
%   like to highlight or hide a group of lines by clicking on one legend entry.
%   CONSIDERATIONS:
%   # The number of unique entries in the group vector must match the
%     number of strings in the legend
%   # When passing a vector of line/patch handles as the first input
%     argument, the vector should contain all lines/patches whose group
%     membership is included in the group vector. ie. the length of the
%     vector of handles must match that of the length of the group vector.
% 
% * displayedLines: A vector of indices corresponding to the lines or groups that
%   should be displayed initially. This option is useful if there are too
%   many lines in the figure and you are only interested in looking at a
%   few at first.
%   Example: clickableLegend(..., 'displayedLines', [4 5 6])
%
% * plotOptions: A cell array of parameter value pairs that define
%   properties of the graphics objects in the legend. This can be useful,
%   for example, to ensure consistent marker sizes within the legend. 
% 
% Notes: 
% 1. If you save the figure and re-load it, the toggling functionality
% is not automatically re-enabled. To restore it, simply call clickableLegend
% with no arguments.
%
% 2. To prevent the axis from automatically scaling every time a line is
% turned on and off, issue the command: axis manual
%
% Example 1:
% z = peaks(100);
% plot(z(:,26:5:50))
% grid on;
% axis manual;
% clickableLegend({'Line1','Line2','Line3','Line4','Line5'}, 'Location', 'NorthWest');
%
% Example 2:
% f = plot([1:10;1:2:20]','x'); hold on;
% g = plot(sin([1:10;1:2:20]'),'r-');
% h = plot(11:20,rand(5,10)*5,'b:');
% clickableLegend([f;g;h], {'Line1','Line2','Line3'},...
%   'groups', [1 1 2 2 3 3 3 3 3], 'displayedLines', [2 3]);
%
% hgsave(gcf, 'testfig.fig');
% hgload testfig.fig
% clickableLegend
%
% See also legend, clickableLegend_examples

% Copyright 2009-2014 MathWorks, Inc.

% Extract any arguments for clickableLegend
[dispinds, groupmem, plotOptions, varargin] = ...
    extractOptionalArgs(varargin{:});

% Process group memberships
[groups, plotObj, varargin] = processGroups(groupmem, varargin{:});

% Create legend
[varargout{1:nargout(@legend)}] = legend(varargin{:});

% Extract what is needed for the rest of the function and fix varargout
[leghan, objhan, plothan] = varargout{1:3}; 
% objhan: strings
% plothan: graphics objects
varargout = varargout(1:nargout);

if isempty(groupmem) % Default group membership
    groupmem = 1:length(plothan);
    plotObj = plothan;
    groups = groupmem;
end

if ~isempty(dispinds) % DisplayedLines parameter was specified
    hidden = true(1, length(plothan));
    dispinds(dispinds>length(plothan)) = [];
    hidden(dispinds) = false;
end

% Set the callbacks & plot options
for i = 1:length(plothan)
    set(objhan(i), 'HitTest', 'on', 'ButtonDownFcn',...
        @(varargin)togglevisibility(objhan(i),plotObj(groupmem==groups(i))),...
        'UserData', true);
    if ~isempty(dispinds) && hidden(i)
        togglevisibility(objhan(i), plotObj(groupmem==groups(i)));
    end
    set(plotObj(groupmem==groups(i)), 'HitTest', 'on', 'ButtonDownFcn', ...
        @(varargin)highlightObject(objhan(i),plothan(i),...
                   plotObj(groupmem==groups(i)),plotOptions),...
        'UserData', false);
    if ~isempty(plotOptions)
        set(plothan(i), plotOptions{:}); 
    end
end


function togglevisibility(hObject, obj)
if get(hObject, 'UserData') % It is on, turn it off
    set(hObject, 'UserData', false);
    set(obj,'HitTest','off','Visible','off','handlevisibility','off');
else
    set(hObject, 'UserData', true);
    set(obj, 'HitTest','on','visible','on','handlevisibility','on');
end

function highlightObject(lTextObj, lMarkerObj, plotObj, plotOptions)
lw = get(plotObj,'LineWidth');
if ~iscell(lw), lw = {lw}; end;
ms = get(plotObj,'MarkerSize');
if ~iscell(ms), ms = {ms}; end;

if ~get(plotObj(1), 'UserData') % It is not selected, highlight it
    %set(hObject, 'FontWeight', 'bold');
    set(lTextObj, 'EdgeColor', 'k');
    set(plotObj, {'LineWidth', 'MarkerSize'}, [cellfun(@(x)x+2, lw, 'Uniformoutput', false) cellfun(@(x)x+2, ms, 'uniformoutput', false)]);
    set(plotObj, 'UserData', true);
else
    %set(hObject, 'FontWeight', 'normal');
    set(lTextObj, 'EdgeColor', 'none');
    set(plotObj, {'LineWidth', 'MarkerSize'}, [cellfun(@(x)x-2, lw, 'Uniformoutput', false) cellfun(@(x)x-2, ms, 'uniformoutput', false)]);
    set(plotObj, 'UserData', false);
end
if ~isempty(plotOptions)
    set(lMarkerObj, plotOptions{:});
end

function [dispinds, groupmem, plotOpt, varargin] = extractOptionalArgs(varargin)
% Extract the displayedlines and/or groups arguments if specified

ind = find(strcmpi(varargin,'DisplayedLines'));
if ~isempty(ind)
    assert(ind<nargin, 'The DisplayedLines parameter value must be specified');
    dispinds = varargin{ind+1};
    varargin(ind:ind+1) = [];
else
    dispinds = [];
end

ind = find(strcmpi(varargin,'groups'));
if ~isempty(ind)
    assert(ind < nargin, 'The groups parameter value must be specified');
    groupmem = varargin{ind+1};
    varargin(ind:ind+1) = [];
else
    groupmem = [];
end

ind = find(strcmpi(varargin,'plotoptions'));
if ~isempty(ind)
    assert(ind < nargin, 'The plotOptions parameter value must be specified');
    plotOpt = varargin{ind+1};
    varargin(ind:ind+1) = [];
else
    plotOpt = {};
end

function [groups, obj, varargin] = processGroups(groupmem, varargin)
if isempty(groupmem)
    groups = []; obj = [];
    return;
end
if iscellstr(groupmem)
    groupmem = categorical(groupmem);
end
groups = unique(groupmem);
firstmem = zeros(size(groups));
if nargin > 1 && ishandle(varargin{1}(1))
    if strcmpi(get(varargin{1}(1),'Type'),'axes')
        hAxes = varargin{1}(1);
        obj = flipud([findobj(hAxes,'Type','line');findobj(hAxes,'Type','patch')]);
    else % It's a line/patch
        obj = varargin{1};
        [~,firstmem] = ismember(groups, groupmem);
        %for i = 1:length(groups)
        %    firstmem(i) = find(groupmem==groups(i),1);
        %end
        varargin{1} = obj(firstmem);
    end
else
    hAxes = gca;
    obj = flipud([findobj(hAxes,'Type','line');findobj(hAxes,'Type','patch')]);
end

 实例代码如下:

clf
h = bubbleplot(Acceleration, Horsepower, MPG, Weight, Model_Year, Origin);
grid on
xlabel('Acceleration');ylabel('Horsepower');zlabel('MPG');

clickableLegend(h, unique(Origin), 'groups', Origin, 'plotOptions', ...
    {'MarkerSize', 8, 'MarkerFaceColor', 'c'});

2.4 七维数据的3D可视化效果图

  • X: Acceleration (continuous)
  • Y: Horsepower (continuous)
  • Z: MPG (continuous)
  • Size: Weight (continuous)
  • Color: Model_Year (discrete, ordinal)
  • Shape: Cylinders
  • Text: Origin
clf
bubbleplot(Acceleration, Horsepower, MPG, Weight, Model_Year, Cylinders,...
            Origin, 'fontSize',6);
grid on
xlabel('Acceleration');ylabel('Horsepower');zlabel('MPG');

2.5 五维数据的2D可视化效果图

  • X: Horsepower (continuous)
  • Y: MPG (continuous)
  • Size: Acceleration (continuous)
  • Color: Displacement (continuous)
  • Shape: Origin
  • Text: Manufacturer
clf
h = bubbleplot(Horsepower, MPG, [], Acceleration, Displacement, Origin,...
    Mfg, 'fontSize', 6);
xlabel('Horsepower');ylabel('MPG');
grid on;
clickableLegend(h, unique(Origin), 'groups', Origin, 'plotOptions', ...
    {'MarkerSize', 8, 'MarkerFaceColor', 'c'});

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页