Консалтинг водопад диаграммы Matlab - PullRequest
0 голосов
/ 14 марта 2020

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

Учитывая эти данные:

x = [5, 2, -5, 8, 2, 12];

total = [1, 0, 0 ,0 ,0, 1];

Я хочу сделать диаграмму водопада.

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

Итак, первый столбец - это 5, и это общий столбец. Второй столбец - два, и это не так (поэтому он складывается). Третий столбец минус пять, поэтому он вычитает, и так далее, и так далее, до последнего столбца, который снова будет итоговым. Ниже как будет выглядеть фигура.

1) Как получить эту цифру?

2) Как цвета увеличивать, уменьшать и суммировать разными цветами?

3) Как включить соединительные линии?

enter image description here

1 Ответ

1 голос
/ 15 марта 2020

Метод 1

Вот одно из возможных решений с использованием функции bar MATLAB.

Допущения:

  • Столбцы всего всегда первый и последний столбцы.

Основная идея c заключается в использовании свойства 'Baseline' объекта Bar, которое позволяет конкретному бару начинаться с указанного значения c. Например, bar([1,3,5], 'BaseValue', 2) производит 3 бара, которые начинаются со значения 2: первый понижается на 1 единицу, второй повышается на 1 единицу, а последний повышается на 3 единицы.

Из тестирования на R2019b, к сожалению, выяснилось, что все объекты Bar на осях должны иметь один и тот же BaseValue. Таким образом, чтобы каждый объект Bar имел свое базовое значение, каждый из них должен находиться в отдельном объекте Axes. Мы можем обойти это, накладывая несколько осей (по одному на каждый столбец) друг на друга, делая прозрачными все, кроме одного. Таким образом, все столбцы будут видны.

В любом случае, вот функция. Входные данные:

  • ax (необязательно): дескриптор существующего объекта Axes. Возможно, вы захотите сделать это, если у вас уже есть другие объекты, или если вы хотите вручную установить различные свойства осей.
  • y : вектор всех добавочных значений. Примечание : конечное значение НЕ требуется, т. Е. Чтобы воспроизвести сюжет в вопросе, используйте y=[5, 2, -5, 8, 2];

Функция выводит дескрипторы для каждого созданного объекта Bar. Вы можете захотеть, чтобы это еще больше изменило EdgeColor Bars.

function h = wfall(ax, y)

if nargin == 1
    y = ax;
    ax = gca;
end
if ~strcmp(ax.NextPlot, 'add')
    fprintf('hold on not set for current axes. Overriding.\n');
    hold(ax, 'on');
end

y = y(:); % column vector
n = length(y);
cumy = cumsum(y);

set(ax, 'XLim', [0, n+1]+0.5, 'YLim', [min(min(cumy), 0), max(max(cumy), 0)]);
% colors:
% decrease - red - code as -1
% total - black - code as 0
% increase - blue - code as 1
set(ax, 'CLim', [-1, 1], 'ColorMap', [1 0 0; 0 0 0; 0 0 1]);

% copy a bunch of axes
for i = 1:n
    ax(i+1) = copyobj(ax(1), ax(1).Parent);
end
% Make all subsequent axes invisible
% Make sure all axes will always be the same size by linking properties
set(ax(2:end), 'Color', 'none', 'XColor', 'none', 'YColor', 'none');
linkprop(ax, {'XLim', 'YLim', 'Position', 'DataAspectRatio'});

% define from/to of each bar (except 1st and last)
from = cumy(1:n-1);
to = cumy(2:n);

% color of each bar (except 1st and last)
c = double(y>0) - double(y<0);
c(1) = [];

% first total bar
h = bar(ax(1), 1, from(1), 'CData', 0, 'BaseValue', 0);
% 2nd to 2nd last bars
for i = 1:n-1
    h(end+1) = bar(ax(i+1), i+1, to(i), 'CData', c(i), 'BaseValue', from(i), 'ShowBaseLine', 'off');
end
% last total bar
h(end+1) = bar(ax(1), n+1, cumy(n), 'CData', 0);

% setting FaceColor flat makes the Bars use the CData property
set(h, 'FaceColor', 'flat') 

Выполните код следующим образом для получения следующего графика.

close all;
ax = gca;
h = wfall(ax, y(1:end-1));

enter image description here


Метод 2

Вот еще одно решение, если вы предпочитаете не размещать объекты Axes друг над другом. В этом случае мы делаем дополнительное предположение:

  • Совокупное значение никогда не бывает отрицательным (это применимо, например, к sh в моем кармане)

Проще говоря, каждый нарисованный нами столбец можно рассматривать как один цветной (синий или красный), который частично покрыт более короткой белой полосой.

function h = wfall2(ax, y)

if nargin == 1
    y = ax;
    ax = gca;
end
if ~strcmp(ax.NextPlot, 'add')
    fprintf('hold on not set for current axes. Overriding.\n');
    hold(ax, 'on');
end

y = y(:); % column vector
n = length(y);
cumy = cumsum(y);


from = cumy(1:n-1);
to = cumy(2:n);

% color values:
%  1 - blue (increase)
%  0 - white
% -1 - red (decrease)
c = double(y>0) - double(y<0);
c(1) = [];

upper = max(cumy(1:n-1), cumy(2:n));
lower = min(cumy(1:n-1), cumy(2:n));


h(1) = bar(ax, 2:n, upper, 'FaceColor', 'flat', 'CData', c);
h(2) = bar(ax, 2:n, lower, 'FaceColor', 'w');
h(3) = bar(ax, 1, cumy(1), 'FaceColor', 'k');
h(4) = bar(ax, n+1, cumy(n), 'FaceColor', 'k');

set(h, 'EdgeColor', 'none')
set(ax, 'CLim', [-1, 1], 'ColorMap', [1 0 0; 0 0 0; 0 0 1]);

Запустите функцию следующим образом:

close all;
ax = gca;
h = wfall2(ax, y(1:end-1));

Полученный график: enter image description here Результат, однако, немного уродлив по моим личным стандартам , поскольку белая полоса будет частично покрывать ось X. Однако это можно исправить, установив для нижнего YLim отрицательное значение, например set(ax, 'YLim', [-0.5 inf]) enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...