Place a stack of data on top of the label label and update the axis labels after changing the axis position

This problem applies only to unix layouts; Windows users will not be able to reproduce it.

I am having problems trying to create datatips that are above the y axis label. The following figure shows the problem:

Issue example

As you can see, the data created next to the label will receive the bottom of the label text , while the desire effect is the opposite: the data type must be on top of the label label .

I generated a graph with the following (not very minimal) code, which is available below. You can delete the lines commented out with % may be removed , or even just put the datatip at -78 instead of a loop to achieve faster testing of the script, but I leave this code if someone once wants them to create user data ( in this case, consider also 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. 

I tried:

  • uistack all datatips to top,
  • remove the label from the bottom (both of them do not work, because the ylabel handle is not in the handles with the axles).

Update . After introducing the @horchler solution, a new problem appeared: when scaling and panning the axes, the axis label will also move. I found a small fix for this, I changed the following aspects:

  • Set datatip z-value to 1 so that it is always above the ylabel z axis.
  • Recreating the shortcut after this moves the pan or zoom. To do this, I implemented the localAxisUpdate function, which receives the old ylabel properties, replaces it with a new one, and reset - all settable properties, but the ylabel position. For this, I used the link

The resulting code is as follows:

 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 

This approach creates an undesirable effect that the iglabel will move around the figure until the mouse button is released. How to remove this unwanted effect?

I think that the solution can be more or less, as it was done in the undocummented matlab to update the tick axes , but now I need a listener for the postet ylabel property. Does anyone know how to do this? If you are a Windows user, you can also try to help, all I need to do is reset the ylabel position after changing (pan, zoom, or something else) in the picture .

+5
source share
2 answers

A workaround that uses linkaxes is so useful when zooming / panning multiple graphs and graph visibility.

  • create axes (hax_1) with the function to be built, without data
  • create axes (hax_2) with the function to be built, and data, but without axis labels
  • set the visibility of hax_2 to "off" (this will display the labels above ).
  • bind 2 axes to linkaxes ([hax_1 hax_2], 'xy'); (zooming and panning on one of the axes will change the second axis on the fly )

This gives your first code (not edited):

 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 

I'm on OSX 10.8.4, R2012b, and had the same problem as yours. Here, the proposed solution displays data located above the axis labels and allows you to scale / pan without using the undocumented matlab functions.

+2
source

How about explicitly setting the z-position of the y-tag through its handle? If I put this after your loop, it seems to work in R2012b:

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

If I adjust the z position, I can make the y-tag pop up and even alternate between the data. I'm not quite sure if this is a bug or function, but sometimes there are workarounds to solve the problems associated with a slight change in the position of the element in order to get Matlab to recount and redraw the shape.

+5
source

Source: https://habr.com/ru/post/950001/


All Articles