Matlab; Круговая диаграмма с 2+ / сплит легенды R2017b - PullRequest
0 голосов
/ 08 января 2019

Я создаю круговую диаграмму и в идеале хочу, чтобы легенда отображалась горизонтально вверху и / или внизу. Тем не менее, почти во всех случаях это невозможно, так как легенда исчезает с фигуры. Поэтому в идеале я хотел бы разделить легенду на две (или более) под легенды и разместить их по отдельности. Я знаю, что это не встроенная функция в MATLAB (я использую R2017b), но я не уверен, что это что-то, что можно заставить работать? Я видел, как нескольким людям удавалось делать подобные вещи с линейными графиками, но я не смог адаптировать их для работы с круговыми диаграммами.

Пример кода:

% Set up a figure and make it a reasonable size/location.
figure( 1 )
set( gcf, 'Position', [ 350, 150, 750, 750 ] )

% Create a list of items for the food menu (example only).
Menu = { "Egg and Bacon", "Egg, Sausage and becon", "Egg and Spam", ...
         "Egg, bacon and Spam", "Egg, bacon, sausage and Spam",     ...
         "Spam, bacon, sausage and Spam", "Nothing"                    };

% Estimate the demand for said food items (example only).
Orders = randi( 150, 1, length( Menu ) );

% Make a pie chart showing what ratio the food was ordered.
Pie_Plot = pie( Orders );

% Create two ranges to grab the first and second half of the pie chart's 
% patches.
Range_1 =                  1 : 2 : ceil( length( Pie_Plot ) / 2 );
Range_2 = Range_1( end ) + 2 : 2 : length( Pie_Plot );

% In an ideal world this would be the first of two legends that would 
% display at the same time.
Ideal_Leg_Pt1 = legend( Pie_Plot( Range_1 ), ...
        Menu( round( Range_1 / 2 ) ), 'orientation', 'horizontal', ...
        'location', 'southoutside'                                    );

% A pause because the method doesn't work so without it, this legend 
% won't appear.                         
pause

% The second half of the ideal legend(s) solution; noting that when this 
% is created, the original
% legend is replaced.
Ideal_Leg_Pt2 = legend( Pie_Plot( Range_2 ), ...
        Menu( round( Range_2 / 2) ), 'orientation', 'horizontal', ...
        'location', 'northoutside'                                   );

% Pause for the same reasons as before.
pause

% This is what I'm currently stuck with; a legend that doesn't fit (I'm 
% aware I could make it vertical for example but this looks messy in my 
% eyes and I'm trying to avoid it unless there really is no way to make 
% the ideal method work).
Current_Leg = legend( Menu, 'orientation', 'horizontal', ...
        'location', 'northoutside'                          );

EDIT

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

В вышеупомянутом примере он работает, рисуя некоторые части, создавая новую ось, затем рисуя остальные; но вы не можете сделать это с круговой диаграммой. Я могу приблизиться к решению проблемы, но в итоге получаю две круговые диаграммы, которые не накладываются идеально. Это суть того, почему я не верю, что это дублирующая проблема; круговые диаграммы кажутся по своей сути отличными от обычных графиков, и поэтому многие решения, которые работают для обычных линейных графиков, похоже, не работают для круговых диаграмм (однако, я свободно допускаю, что могу просто пропустить простую модификацию, которая заставит их всех работать! ).

Код для указанного примера (помещен прямо под Ideal_Leg_Pt1 в моем OP, со всем остальным после удаления):

ax2 = axes('Position',get(gca,'Position'),...
           'Visible','off','Color','none');

Second_Pie = pie( Orders );

Ideal_Leg_Pt2 = legend( Second_Pie( Range_2 ), ...
        Menu( round( Range_2 / 2) ), 'orientation', 'horizontal', ...
        'location', 'northoutside' );

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Вы сказали, что у вас есть версия Matlab до 2018a (2017b), поэтому вы не можете применить @ ответ Сардара . Вот способ сделать это без свойства NumColumns:

Мы начнем с первой части вашего кода (в версии, совместимой с моим 2017a), где вы создадите круговую диаграмму и разместите первую половину легенды:

figure(1);
set(gcf,'Position',[350,150,750,750])
% Create a list of items for the food menu (example only).
Menu = {'Egg and Bacon', 'Egg, Sausage and becon', 'Egg and Spam', ...
         'Egg, bacon and Spam', 'Egg, bacon, sausage and Spam',     ...
         'Spam, bacon, sausage and Spam', 'Nothing'};
% Estimate the demand for said food items (example only).
Orders = randi(150,1,length(Menu));
% Make a pie chart showing what ratio the food was ordered.
Pie_Plot = pie(Orders);
% Create two ranges to grab the first and second half of the pie chart's 
% patches.
Range_1 = 1:2:ceil(length(Pie_Plot)/2);
Range_2 = Range_1(end)+2:2:length(Pie_Plot);

% In an ideal world this would be the first of two legends that would 
% display at the same time:
Ideal_Leg_Pt1 = legend(Pie_Plot(Range_1),Menu(round(Range_1/2)),...
    'orientation', 'horizontal','EdgeColor','none');

Далее, мы установим позицию Ideal_Leg_Pt1 вручную, чтобы освободить место:

Ideal_Leg_Pt1.Position(1:3) = [0 1-Ideal_Leg_Pt1.Position(4) 1];

Теперь мы добавим скрытые оси с тем же пирогом, но на этот раз со второй частью легенды:

% the hidden axes are neded so the first legend won't be replaced:
hidden_ax = axes('Visible','off','NextPlot','add');
% we plot the same pie, only to create the objects in the legend:
Pie_Plot_2 = pie(Orders);
% The second half of the ideal legend(s) solution:
Ideal_Leg_Pt2 = legend(Pie_Plot_2(Range_2),Menu(round(Range_2/2)),...
    'orientation', 'horizontal','AutoUpdate','off',...
    'EdgeColor','none');

Обратите внимание, что мы установили свойство 'AutoUpdate' для Ideal_Leg_Pt2 в значение 'off', поэтому мы можем безопасно удалить фиктивный пирог, не удаляя элементы из легенды:

% remove the extra dummy pie:
Pie_Plot_2.delete

Теперь мы можем установить положение Ideal_Leg_Pt2 относительно положения Ideal_Leg_Pt1, чтобы они выглядели как одна легенда:

% Define a position of the second legend to fit the first one:
% make the legend equally wide
Ideal_Leg_Pt2.Position([1 3]) = Ideal_Leg_Pt1.Position([1 3]);
% attach the two parts of the leggend
Ideal_Leg_Pt2.Position(2) = Ideal_Leg_Pt1.Position(2)-Ideal_Leg_Pt2.Position(4);

Результат:

enter image description here

Обратите внимание, что при любом изменении размера фигуры потребуется изменить положение легенд, поэтому, если это проблема, вы можете установить свойство 'SizeChangedFcn' фигуры, чтобы сделать это для вас:

% updating the position of the legends upon resizing of the figure:
set(figure(1),'SizeChangedFcn',...
    ['Ideal_Leg_Pt1.Position(1:3) = [0 1-Ideal_Leg_Pt1.Position(4) 1];'...
     'Ideal_Leg_Pt2.Position([1 3]) = Ideal_Leg_Pt1.Position([1 3]);'...
     'Ideal_Leg_Pt2.Position(2) = Ideal_Leg_Pt1.Position(2)-Ideal_Leg_Pt2.Position(4);']);

или установите для этого небольшую функцию, сохраните ее в другом M-файле:

function setLgePos(Ideal_Leg_Pt1,Ideal_Leg_Pt2)
Ideal_Leg_Pt1.Position(1:3) = [0 1-Ideal_Leg_Pt1.Position(4) 1];
Ideal_Leg_Pt2.Position([1 3]) = Ideal_Leg_Pt1.Position([1 3]);
Ideal_Leg_Pt2.Position(2) = Ideal_Leg_Pt1.Position(2)-Ideal_Leg_Pt2.Position(4);
end

и вызовите его из свойства figure:

set(figure(1),'SizeChangedFcn','setLgePos(Ideal_Leg_Pt1,Ideal_Leg_Pt2)');
0 голосов
/ 08 января 2019

Для этого решения требуется ≥ R2018a

Вместо того, чтобы усложнять это, разделение горизонтальной легенды на несколько столбцов / строк может достичь вашей цели.

legend(Menu, 'location', 'northoutside', 'orientation', 'horizontal', 'NumColumns', 3);

output

...