Как скрыть нулевые значения в графике bar3 в MATLAB
У меня есть двухмерная гистограмма (график 3D - несколько гистограмм, скопированных бок о бок), которые я создал с помощью команды plot bar3. Однако все нулевые значения отображаются как плоские квадраты в плоскости x-y. Есть ли способ предотвратить отображение MATLAB значений? Я уже пытался заменить все нули на NaNs, но ничего не изменил в сюжете. Здесь код, который я экспериментировал с:
x1=normrnd(50,15,100,1); %generate random data to test code
x2=normrnd(40,13,100,1);
x3=normrnd(65,12,100,1);
low=min([x1;x2;x3]);
high=max([x1;x2;x3]);
y=linspace(low,high,(high-low)/4); %establish consistent bins for histogram
z1=hist(x1,y);
z2=hist(x2,y);
z3=hist(x3,y);
z=[z1;z2;z3]';
bar3(z)
Как вы можете видеть, на графике имеется немало нулевых значений. Закрытие фигуры и повторное построение после замены нулей NaNs ничего не меняют:
close
z(z==0)=NaN;
bar3(z)
Ответы
Ответ 1
Одним из решений является изменение графических объектов, созданных bar3
. Во-первых, вам нужно вернуть дескрипторы из bar3
:
h = bar3(z);
В вашем случае h
будет 3-элементным вектором дескрипторов, по одному для каждого набора цветных полосок. Следующий код должен затем сделать бункеры с невидимыми отсчетами:
for i = 1:numel(h)
index = logical(kron(z(:, i) == 0, ones(6, 1)));
zData = get(h(i), 'ZData');
zData(index, :) = nan;
set(h(i), 'ZData', zData);
end
И вот иллюстрация (с обязательными свободными кругами):
![введите описание изображения здесь]()
Как это работает...
Если ваш вектор подсчета bin равен N-by-1
, то bar3
будет выстроить прямоугольные патчи 6*N
(то есть 6 граней кубоида для каждого бункера). Таким образом, свойство 'ZData'
для каждого набора объектов патча в h
будет (6*N)-by-4
, так как для каждой прямоугольной грани есть 4 угла. Таким образом, каждый кластер из 6 строк свойства 'ZData'
представляет собой набор z-координат для 6 граней одного бина.
Вышеприведенный код сначала создает логический вектор, в котором каждый из них имеет значение 0, а затем реплицирует каждый элемент этого вектора 6 раз, используя kron
. Это становится индексом для строк свойства 'ZData'
, и этот индекс используется для установки z-координат в nan
для патчи пустых бункеров. Это приведет к тому, что патчи не будут отображаться.
EDIT:
Здесь немного измененная версия кода, которая делает ее более общей, выбирая высоту столбца из свойства 'ZData'
построенного графика баров, поэтому все, что необходимо для работы, это дескрипторы, возвращенные из bar3
. Я также завернул код в функцию (без ошибок и проверки ввода):
function remove_empty_bars(hBars)
for iSeries = 1:numel(hBars)
zData = get(hBars(iSeries), 'ZData'); % Get the z data
index = logical(kron(zData(2:6:end, 2) == 0, ones(6, 1))); % Find empty bars
zData(index, :) = nan; % Set the z data for empty bars to nan
set(hBars(iSeries), 'ZData', zData); % Update the graphics objects
end
end
Ответ 2
Вот пример, показывающий, как скрыть бары с нулевыми значениями. Начнем с нормального BAR3:
x = 1:7;
Y = jet(numel(x));
h = bar3(x,Y,'detached');
xlabel x; ylabel y; zlabel z; box on;
![before]()
Обратите внимание, что переменная h
содержит массив surface
обрабатывает (3 в этом случае по одному для каждой "группы" Группы соответствуют столбцам матрицы Y
, каждая из которых представлена другим цветом).
И теперь код, чтобы скрыть нулевые значения:
for i=1:numel(h)
%# get the ZData matrix of the current group
Z = get(h(i), 'ZData');
%# row-indices of Z matrix. Columns correspond to each rectangular bar
rowsInd = reshape(1:size(Z,1), 6,[]);
%# find bars with zero height
barsIdx = all([Z(2:6:end,2:3) Z(3:6:end,2:3)]==0, 2);
%# replace their values with NaN for those bars
Z(rowsInd(:,barsIdx),:) = NaN;
%# update the ZData
set(h(i), 'ZData',Z)
end
![after]()
Объяснение:
Для каждой группы баров создается графический объект surface
(с дескриптором, хранящимся в h(i)
). Эта матрица Z-координат ZData
представлена в виде матрицы 6*N-by-4
(то же самое для матриц XData
, YData
и CData
), где N - количество прямоугольных баров в каждой группе или 7 в пример выше.
Таким образом, каждый прямоугольник представлен 6x4 матрицами (по одному для каждой из координат X/Y/Z). Например, координаты одного такого прямоугольника будут выглядеть так:
>> xx = get(h(3),'XData'); yy = get(h(3),'YData'); zz = get(h(3),'ZData');
>> xx(1:6,:)
ans =
NaN 2.6 3.4 NaN
2.6 2.6 3.4 3.4
2.6 2.6 3.4 3.4
NaN 2.6 3.4 NaN
NaN 2.6 3.4 NaN
NaN NaN NaN NaN
>> yy(1:6,:)
ans =
NaN 0.6 0.6 NaN
0.6 0.6 0.6 0.6
1.4 1.4 1.4 1.4
NaN 1.4 1.4 NaN
NaN 0.6 0.6 NaN
NaN NaN NaN NaN
>> zz(1:6,:)
ans =
NaN 0 0 NaN
0 1 1 0
0 1 1 0
NaN 0 0 NaN
NaN 0 0 NaN
NaN NaN NaN NaN
Второй столбец каждого прослеживает точки вдоль левой стороны, третий столбец прослеживает точки вдоль правой стороны, а когда эти два связаны, будут рисовать 4 грани прямоугольника:
>> surface(xx(1:6,2:3), yy(1:6,2:3), zz(1:6,2:3), cc(1:6,2:3))
>> view(3)
![rectangle_surface]()
Первый и последний столбцы будут рисовать две оставшиеся грани, закрывая стороны прямоугольника.
Все такие матрицы объединены как одна высокая матрица, а прямоугольники все рисуются с использованием одного поверхностного объекта. Это достигается с помощью значений NaN
для разделения разных частей, как внутри точек одного и того же прямоугольника, так и между разностными прямоугольниками.
Итак, что делает вышеприведенный код, это искать прямоугольники, где Z-высота равна нулю, и заменить все свои значения на NaN
значения, которые эффективно сообщают MATLAB не рисовать поверхности, образованные этими точками.
Ответ 3
Моя проблема была не в нулевых значениях, а в значениях NaN (которые преобразуются в нулевые значения внутри bar3).
Я хотел сохранить элементы с нулевыми значениями, но не элементами со значением nan.
Я немного скорректировал код, и он отлично работал:
for i = 1:numel(h)
index = logical(kron(isnan(z(:,i)),ones(6,1)));
zData = get(h(i),'ZData');
zData(index,:) = nan;
set(h(i),'ZData',zData);
end
Спасибо!