Отображение нового изображения внутри существующих осей без удаления цветовой шкалы

Я работаю над графическим интерфейсом, который инициализируется путем создания нескольких axes вместе с невидимым colorbar для каждого (это делается для того, чтобы оси сохраняли свои предопределенные Position) 1. Дескрипторы всех осей и цветовых полос сохранены.

Взаимодействие с пользовательским интерфейсом может привести к тому, что изображения будут нанесены на одну из осей. Мне бы хотелось, чтобы в любой момент времени отображалась только цветная полоса активных осей, соответствующим образом Visible свойство всех цветовых полос.

У меня проблема с этим подходом, потому что я использую imagesc обновить мои оси, и это удалит любую цветовую панель, связанную с осями, делая сохраненные маркеры недействительными.

Мой вопрос: как я могу использовать imagesc или же image обновить оси, связанные с цветовой шкалой, без удаления цветовой полосы?

Вот как воспроизвести эту проблему:

dbclear in newplot %// Needed for the code to be properly re-runnable
%// Create an example figure containing a colorbar:
figure(); imagesc(imread('cameraman.tif')); colorbar;
%// "Refreshing" the displayed image:
uiwait(msgbox('The image will now be refreshed. A breakpoint will be set in newplot.m'));
dbstop in newplot at 124 %// The line responsible for deleting the colorbar in R2015A/B
imagesc(imread('cameraman.tif'));

Линия, на которой точка останова в newplot.m установлено читает:

cla(ax, 'reset', hsave);

Что является (не) удивительно недокументированным способом cla (с 3 параметрами), который сохраняет объекты, чьи ручки находятся в hsave,


Некоторые идеи, которые я предполагал, предполагая, что удаление цветовой панели неизбежно (я буду реализовывать в случае, если "нормальное" решение не будет найдено):

  1. Связывание DeleteFcn на цветовую панель, которая сохраняет свои данные в некоторых struct, Создание новой цветовой панели после imagesc закончил, затем перебирая поля struct и присвоение всех свойств новому объекту цветовой панели.
  2. Проверяйте "время от времени", что все цветовые полосы существуют, используя либо findall(hFig,'type','colorbar') или убедитесь, что каждая из осей имеет действительный ColorbarPeerHandle согласно приложению ниже. Воссоздайте CB, если он недействителен.
  3. Удалите все цветные полосы, когда активны разные оси, и создайте только тот CB, который я хотел бы показать.

Приложение - Ассоциация ColorBar/Axes:

  • Дескриптор к цветовой панели, связанной с определенными осями hAx можно получить (в hg2) используя:

    hCb = getappdata(hAx,'ColorbarPeerHandle');
    
  • Ручка к axes связанный с объектом colorbar hCb можно получить, используя 2:

    hAx = hCb.Axes;
    

1 ответ

Решение

Мне удалось придумать пару решений:

  1. safeUpdateImage1 - На основании обхода cla(...) через создание нового Image объект внутри осей после использования hold, Это хорошо для случаев, когда Image не обязательно существует в осях.
  2. safeUpdateImage2 - Следуя предложению Микколы, основываясь на обновлении существующего Image объект. Это хорошо для случаев, когда уже есть ColorBar и Image связаны с осями.

Вот демонстрация обоих решений наряду с исходной проблемой:

function [] = Problem
dbclear in newplot %// Needed for the code to be properly re-runnable
%// Create an example figure containing a colorbar:
Img = imread('cameraman.tif');
figure(); imagesc(Img); hAx = gca; colorbar;
%// Refreshing the displayed image (comment/uncomment as needed):
switch questdlg('Please select an image update method:','Update method selection',...
                'Broken','Safe1','Safe2','Safe1')
  case 'Broken'
    brokenUpdateImage(hAx,255-Img);
  case 'Safe1'
    safeUpdateImage1(hAx,255-Img);
  case 'Safe2'
  safeUpdateImage2(hAx,255-Img);  
end
end

function brokenUpdateImage(hAx,newImg)
uiwait(msgbox('The image will now be refreshed. A breakpoint will be set in NEWPLOT'));
dbstop in newplot at 124 %// The line responsible for deleting the colorbar in R2015A/B
imagesc(newImg,'Parent',hAx);
end

% For cases when the only desired child is an Image and the axes contents are unknown
function safeUpdateImage1(hAx,newImg,imgType,imgUpdateFcn)
if nargin < 4 || isempty(imgUpdateFcn)
  imgUpdateFcn = @imagesc;
end
if nargin < 3 || isempty(imgType)
  imgType = 'Image';  
end
if strcmp(hAx.NextPlot,'replace') %// Equivalent to checking "ishold == false"
  hAx.NextPlot = 'add'; %// Equivalent to "hold on"
  %// hCurrImgs = get(hAx,'Children'); %// Deletes all types of Children
  hCurrImgs = findall(hAx,'type','Image'); %// Deletes only graphical objects of type 
                                           %// "matlab.graphics.primitive.Image"
  for ind1=1:numel(hCurrImgs)
    delete(hCurrImgs(ind1));
  end
  imgUpdateFcn(newImg,'Parent',hAx);
  if strcmpi(imgType,'Image')
    axis(hAx,'tight','ij');    
%// 'tight' - XLimMode, YLimMode, and ZLimMode change to 'auto'. The limits automatic- 
%//           ally update to incorporate new data added to the axes. To keep the limits
%//           from changing when using hold on, use axis tight manual.
%// 'ij'  —   Reverse direction. For axes with a 2-D view, the y-axis is vertical with
%//           values increasing from top to bottom.    
  end
end
end

%// When it's known that the axes contains at least one Image:
function safeUpdateImage2(hAx,newImg,~,~)
%// <Input checking code>
hCurrImgs = findall(hAx,'type','Image');
%// <Optional code to decide which Image child to update>
hCurrImgs(1).CData = newImg; %// In this example, only update the "topmost" child
end
Другие вопросы по тегам