2013-07-11 2 views
5

Эта проблема относится только к unix matlabs, пользователи Windows не смогут ее воспроизвести.Поместите стек данных на этикетку над меткой оси и обновите этикетку осей после того, как было произведено изменение положения осей

У меня возникают проблемы при создании данных, в которых находятся надписи на оси y. На следующем рисунке показан вопрос:

Issue Example

Как вы можете видеть, всплывающие подсказки, созданные близко к ylabel получат дно к тексту ylabel, в то время как эффект желания наоборот: DataTip быть на верхняя ось метки.

Я сгенерировал участок со следующим (не очень минимальным) кодом, который доступен ниже. Вы можете удалить строки, прокомментированные с помощью % may be removed, или даже просто поставить datatip на -78 вместо цикла, чтобы получить более быстрый скрипт тестирования, но я оставляю этот код, если кто-то однажды захочет создать пользовательские данные (в этом случае , рассмотреть наблюдение также http://undocumentedmatlab.com/blog/controlling-plot-data-tips/):

gradientStep = 1e-1; 

x=-100:gradientStep:100; xSize=numel(x); 
y=x.^3-x.^2; 

figH=figure(42); 
lineH=plot(x,y); 

ylabel('YLabel (YUnits)','FontSize',16) 
xlabel('XLabel (XUnits)','FontSize',16) 

dcH=datacursormode(figH); 

nTips = 20; % May change the loop for a datatip at x=-78. 

for pos = round(linspace(2,xSize,nTips)) 
    datatipH=dcH.createDatatip(lineH,... 
    struct('Position',[x(pos) y(pos)])); 

    orientation = 'top-left'; 

    if pos>1 
    tipText{1} = 'The grandient here is: '; 
    tipText{2} = ['\Deltax:',sprintf('%d',x(pos)-x(pos-1)),' XUnits']; 
    tipText{3} = ['\Deltay:',sprintf('%d',y(pos)-y(pos-1)),' YUnits']; 
    else 
    tipText = 'Cannot calculate gradient here.'; 
    end 

    bkgColor = [1 1 .5]; % May be removed. 
    fontSize = 12; % May be removed. 

    set(datatipH,'StringFcn',(@(~,~) tipText),'Orientation',... 
    orientation,'backGroundColor',bkgColor,'FontSize',... 
    fontSize,'Draggable','on');   % Only set text and orientation needed.  
    datatipTextBoxH=get(datatipH,'TextBoxHandle'); % May be removed. 

    uistack(datatipH,'top'); % Unfortunately makes no effect, since the ylabel handles is not at the axes children list 

    datatipTextBoxH=get(datatipH,'TextBoxHandle'); 
    set(datatipTextBoxH,'HorizontalAlignment','left',... 
    'VerticalAlignment','top','Margin',0.02,'Interpreter',... 
    'tex','FontName','Courier','FontSize',fontSize); % May be removed. 

end 
uistack(get(gca,'YLabel'),'bottom') % Also makes no effect, for the same reason. 

Я пробовал:

  • uistack все DataTips вверх,
  • uistack этикетки вниз (оба из них не работают, потому что в ylabel ручки не находится в осях, которыми управляют дети).

Update: После внедрения решения @horchler», новая проблема появилась: при масштабировании и панорамирование оси, метка оси также будет двигаться. Я нашел небольшое исправление для этого, я изменил следующие аспекты:

  • Установите значение datatip z в значение 1, чтобы оно всегда было выше, чем ось ylabel z.
  • Повторное создание ярлыка после этого происходит перемещение панорамирования или масштабирования. Для этого я внедрил функцию localAxisUpdate, получив старые свойства ярлыка, заменив ее на новую, и они сбросят все настраиваемые свойства, но положение ylabel. Для этого я использовал этот reference

Результирующий код выглядит следующим образом:

function test 
    gradientStep = 1e-1; 

    x=-100:gradientStep:100; xSize=numel(x); 
    y=x.^3-x.^2; 

    figH=figure(42); 
    lineH=plot(x,y); 

    ylabel('YLabel (YUnits)','FontSize',16) 
    xlabel('XLabel (XUnits)','FontSize',16) 

    dcH=datacursormode(figH); 

    %nTips = 20; 

    %for pos = round(linspace(2,xSize,nTips)) 
    pos = find(x>-78,1); 
    datatipH=dcH.createDatatip(lineH,... 
     struct('Position',[x(pos) y(pos) 1])); 

    orientation = 'top-left'; 

    if pos>1 
     tipText{1} = 'The grandient here is: '; 
     tipText{2} = ['\Deltax:',sprintf('%d',x(pos)-x(pos-1)),' XUnits']; 
     tipText{3} = ['\Deltay:',sprintf('%d',y(pos)-y(pos-1)),' YUnits']; 
    else 
     tipText = 'Cannot calculate gradient here.'; 
    end 

    bkgColor = [1 1 .5]; % Light Yellow 
    fontSize = 12; 

    set(datatipH,'StringFcn',(@(~,~) tipText),'Orientation',... 
     orientation,'backGroundColor',bkgColor,'FontSize',... 
     fontSize,'Draggable','on'); 
    datatipTextBoxH=get(datatipH,'TextBoxHandle'); 

    datatipTextBoxH=get(datatipH,'TextBoxHandle'); 
    set(datatipTextBoxH,'HorizontalAlignment','left',... 
     'VerticalAlignment','top','Margin',0.02,'Interpreter',... 
    %end 

    % Set changes due to zoom and pan to also use adaptativeDateTicks:   
    set(zoom(figH),'ActionPostCallback',... 
    @(~,~) localAxisUpdate(gca)); 
    set(pan(figH),'ActionPostCallback',... 
    @(~,~) localAxisUpdate(gca)); 

end 

function localAxisUpdate(aH)  
    % Fix axis label on top of datatip: 
    ylh = get(aH,'YLabel'); 
    % Get original YLabel properties 
    ylstruct = get(ylh); 
    % Get settable fields: 
    yfieldnames=fieldnames(rmfield(set(ylh),'Position'))'; 
    % Remove old label: 
    delete(ylh) 
    % Create new one: 
    ylh = ylabel(aH,'Dummy'); 
    % Send it bottom: 
    ylpos = get(ylh,'Position'); 
    set(ylh, 'Position', [ylpos(1:2) 0]); 
    % Reset new ylabel to old values: 
    for field=yfieldnames 
    field = field{1}; 
    set(ylh,field,ylstruct.(field)); 
    end 
end 

Такой подход создает нежелательный эффект, который является ylabel будет двигаться по фигуре, пока кнопка мыши не будет отпущена. Как удалить этот нежелательный эффект?

Я думаю, что решение может быть более или менее таким, как это было сделано в undocummented matlab solution for updating axes ticks, но теперь мне нужен слушатель для свойства postet ylabel. Кто-нибудь знает, как это сделать? Если вы пользователь Windows, вы также можете попытаться помочь, все, что мне нужно, это сбросить положение ylabel после изменения (панорамирование, масштабирование или что-то еще) на рисунке.

+2

fyi, исходный код работает без изменений в R2013a (WinXP): http://i.stack.imgur.com/I9MCS.png – Amro

+0

Я также использую Matlab R2013a, но на MacOS 10.8.4. Добавлен запрос, чтобы проверить, действительно ли это проблема, связанная с платформой. – Werner

ответ

2

Обходной путь, который использует как linkaxes, так и полезен при масштабировании/панорамировании нескольких участков и видимости участков.

  1. создать оси (hax_1) с функцией, чтобы быть нарисовано, без DataTips
  2. создать оси (hax_2) с функцией быть нанесено И всплывающие подсказки, но без осей этикетки
  3. набора hax_2 видимость на «выключен» (это построит datatips выше метки первых осей)
  4. связывает 2 оси со звеньями ([hax_1 hax_2], 'xy'); (Масштабирование и панорамирование на одной из осей будет изменять на лету второй оси)

Это дает с первым кодом (не отредактированный один):

gradientStep = 1e-1; 
x=-100:gradientStep:100; xSize=numel(x); 
y=x.^3-x.^2; 
figH=figure(42); 
plot(x,y); 
ylabel('YLabel (YUnits)','FontSize',16) 
xlabel('XLabel (XUnits)','FontSize',16) 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
% modification starts 

hax_1 = gca; 
hax_2 = axes('Position', get(hax_1,'Position')); 
lineH = plot(x,y); 
linkaxes([hax_1 hax_2],'xy'); 
set(hax_2,'Visible', 'off'); 

% modification ends 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

dcH=datacursormode(figH); 
nTips = 20; % May change the loop for a datatip at x=-78. 
for pos = round(linspace(2,xSize,nTips)) 
    datatipH=dcH.createDatatip(lineH,struct('Position',[x(pos) y(pos)])); 
    orientation = 'top-left'; 
    if pos>1 
    tipText{1} = 'The grandient here is: '; 
    tipText{2} = ['\Deltax:',sprintf('%d',x(pos)-x(pos-1)),' XUnits']; 
    tipText{3} = ['\Deltay:',sprintf('%d',y(pos)-y(pos-1)),' YUnits']; 
    else 
    tipText = 'Cannot calculate gradient here.'; 
    end 
    bkgColor = [1 1 .5]; % May be removed. 
    fontSize = 12; % May be removed. 
    set(datatipH,'StringFcn',(@(~,~) tipText),'Orientation',orientation,'backGroundColor',bkgColor,'FontSize',fontSize,'Draggable','on'); % Only set text and orientation needed.  
    datatipTextBoxH=get(datatipH,'TextBoxHandle'); 
    set(datatipTextBoxH,'HorizontalAlignment','left','VerticalAlignment','top','Margin',0.02,'Interpreter','tex','FontName','Courier','FontSize',fontSize); % May be removed. 
end 

Я на OSX 10.8.4, R2012b, и имел ту же проблему, что и ваша. Здесь предлагаемое решение отображает данные, расположенные над метками оси, и позволяет масштабировать/панорамировать, не используя недокументированные функции Matlab.

+0

Это волшебство! – Werner

+0

Очень хорошая работа. Фактическое «использование» для «linkaxes». Итак, подсказки данных помещаются в невидимую ось, которая связана с основной, выровненной с ней? Я бы хотел, чтобы дети невидимой оси наследовали невидимость. Вероятно, есть и другие ошибки, которые можно было бы обработать с помощью этой методики - хотя это может быть немного дорогостоящим с точки зрения дополнительной обработки/обратных вызовов, которые, вероятно, потребуются - как бы часто это не было проблемой для многих сюжетов. – horchler

+1

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

5

Как насчет явной установки z-позиции y-метки через ее ручку?Если бы это после цикла, кажется, работает в R2012b:

ylh = get(gca,'Ylabel') 
ylpos = get(ylh,'Position'); 
set(ylh,'Position',[ylpos(1:2) 0]); 

Если я регулирую г-позицию я могу получить у метки всплывала и даже чередование между Datatips. Я не совсем уверен, что это ошибка или функция, но иногда есть обходные пути для решения проблем, связанных с настройкой элемента элемента, чтобы заставить Matlab пересчитать и перерисовать фигуру.

+1

Отлично! Спасибо, что мне нужно. Не мог подумать, что ответ будет таким простым! На данный момент я не стану закрывать вопрос, на всякий случай кто-то хочет улучшить ответ для будущих «поколений». – Werner

+1

Рад, что он работает на вас. Я был обеспокоен тем, что вы можете использовать версию Matlab с некоторой ошибкой, которая помешала бы ей работать. Существует множество ошибок, требующих лишь слегка подгонки позиции элементов, чтобы заставить Matlab повторно отобразить все. Оставляя его открытым до тех пор, пока щедрость не закончится или пока всякий раз, когда вам нравится, хорошо. – horchler

+0

Вы не знаете, как я счастлив, это беспокоило меня так долго. Вы могли бы добавить следующую фразу к своему ответу (я не знал об этом), это очень полезно: «Существует множество ошибок, которые требуют лишь слегка подстройки позиции элементов, чтобы заставить Matlab повторно отобразить все». – Werner

Смежные вопросы