Колчан3 стрелка цвет соответствует величине

Я хочу, чтобы цвет каждой стрелки на графике quiver3 от MATLAB соответствовал величине каждой стрелки. Есть ли способ сделать это?

Я видел несколько примеров онлайн, которые могут сделать это для 2D quiver, однако ни один из них не работает для 3D-варианта, quiver3.

У меня есть следующий график и вы хотите заменить синие стрелки цветом, соответствующим их величине.

enter image description here

Ответ 1

В старой графической системе (R2014a и ранее) это невозможно с помощью встроенного объекта quiver. Вы можете легко получить все объекты сюжета, которые используются для составления графика quiver

q = quiver(1:5, 1:5, 1:5, 1:5);
handles = findall(q, 'type', 'line');

Но все хвосты представлены одним сюжетным объектом, а головки стрелок представлены другим. Таким образом, вы не можете индивидуально изменять цвет каждой головы/хвоста.

set(handles(1), 'Color', 'r')
set(handles(2), 'Color', 'g')

введите описание изображения здесь

Однако с введением HG2 (R2014b и выше) вы можете получить доступ к двум (недокументированным) LineStrip объектам (matlab.graphics.primitive.world.LineStrip) (один представляет головы, а один представляет хвосты). Они доступны через скрытые свойства Tail и Head.

q = quiver(1, 1, 1, 1);
headLineStrip = q.Head;
tailLineStrip = q.Tail;

Затем вы можете изменить цветовые свойства этих объектов, чтобы каждая стрелка отличалась цветом.

Основная идея

Чтобы сделать это, я сначала вычислил величину всех колчанов стрелок (это работает как для quiver, так и quiver3)

mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
            reshape(q.WData, numel(q.UData), [])).^2, 2));

Затем я использую текущую цветовую карту для сопоставления каждой величины с значением RGB. Коротким стрелкам присваивается самый низкий цвет в цветовой палитре, а самой длинной стрелке присваивается самый высокий цвет в цветовой палитре. histcounts отлично подходит для присвоения каждой величины индексу, который может быть передан в ind2rgb вместе с самой цветовой палитрой. Мы должны умножить на 255, потому что нам нужен цвет RGB как 8-разрядное целое число.

% Get the current colormap
currentColormap = colormap(gca);

% Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));

% Now map this to a colormap
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);

Свойство LineStrip ColorData (при указании как truecolor) также должно иметь альфа-канал (который мы будем обозначать 255, что означает непрозрачность).

cmap(:,:,4) = 255;

В этот момент мы можем установить свойство ColorBinding в interpolated, а не object (чтобы отделить его от объекта quiver) и установить свойство ColorData как q.Head, так и q.Tail > к цветам, которые мы создали выше, давая каждой стрелке собственный цвет.

Полное решение

ПРИМЕЧАНИЕ.. Это решение работает как для quiver, так и quiver3, и код вообще не нужно адаптировать.

%// Create a quiver3 as we normally would (could also be 2D quiver)

x = 1:10;
y = 1:10;
[X,Y] = meshgrid(x, y);
Z = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
W = sqrt(X.^2 + Y.^2);

q = quiver3(X, Y, Z, U, V, W);

%// Compute the magnitude of the vectors
mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
            reshape(q.WData, numel(q.UData), [])).^2, 2));

%// Get the current colormap
currentColormap = colormap(gca);

%// Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));

%// Now map this to a colormap to get RGB
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);
cmap(:,:,4) = 255;
cmap = permute(repmat(cmap, [1 3 1]), [2 1 3]);

%// We repeat each color 3 times (using 1:3 below) because each arrow has 3 vertices
set(q.Head, ...
    'ColorBinding', 'interpolated', ...
    'ColorData', reshape(cmap(1:3,:,:), [], 4).');   %'

%// We repeat each color 2 times (using 1:2 below) because each tail has 2 vertices
set(q.Tail, ...
    'ColorBinding', 'interpolated', ...
    'ColorData', reshape(cmap(1:2,:,:), [], 4).');

введите описание изображения здесь

И применяется к объекту 2D quiver

введите описание изображения здесь

Если вы не обязательно хотите масштабировать стрелки во весь диапазон цветовой карты, вы можете использовать следующий вызов histcounts (вместо строки выше), чтобы сопоставить величины с использованием границ цвета осей.

clims = num2cell(get(gca, 'clim'));
[~, ~, ind] = histcounts(mags, linspace(clims{:}, size(currentColormap, 1)));

Ответ 2

Если вы используете версию post r2014b, вы можете использовать недокументированные функции, чтобы изменить цвет каждой строки и головы:

figure
[x,y] = meshgrid(-2:.5:2,-1:.5:1);
z = x .* exp(-x.^2 - y.^2);
[u,v,w] = surfnorm(x,y,z);
h=quiver3(x,y,z,u,v,w); 

s = size(x);
nPoints = s(1)*s(2);
% create a colour map
cmap = parula(nPoints);
% x2 because each point has 2 points, a start and an end.
cd = uint8(repmat([255 0 0 255]', 1, nPoints*2));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
  % and we need to assign a colour to the start and end of the 
  %   line.
  for jj=1:2
    count = count + 1;
    cd(1:3,count) = uint8(255*cmap(ii,:)');
  end
end
% set the colour binding method and the colour data of the tail
set(h.Tail, 'ColorBinding','interpolated', 'ColorData',cd)

% create a color matrix for the heads
cd = uint8(repmat([255 0 0 255]', 1, nPoints*3));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
  % and we need to assign a colour to the all the points 
  %   at the head of the arrow
  for jj=1:3
    count = count + 1;
    cd(1:3,count) = uint8(255*cmap(ii,:)');
  end
end
% set the colour binding method and the colour data of the head
set(h.Head, 'ColorBinding','interpolated', 'ColorData',cd)

Примечание. Я не делал ничего умного с величиной и просто менял цвет каждого колчана на основе порядка в исходной матрице, но вы должны иметь возможность получить представление о том, как использовать эту "функцию"

введите описание изображения здесь