2

on this question I received an answer on how to dynamically update the tick labels of plots using a callback function.

Now, as of MATLAB 2014b the matlab people decided to change things that have been complicated already, to make them even more complicated (apparently, no offense, I might be mistaken).

Problem: I use callbacks almost in every plot to update tick labels. This is because often

  • these are scatter plots, using a grid of indices, which need to be mapped to the actual data
  • or the data is in an inconvenient unit, so that when updating the labels there is a unit conversion
  • it's big data and adaption/conversion of the entire data set is out of question
  • the pan/zoom utilities are being used and without updating one looses proper labeling

Now, having all my code broken I tried to fix what got broken, but... I cannot get it working. Please help me out. Below is an attempt of a fix of Amro's example.

The example is fully working in MATLAB < 2014b. From 2014b tick properties do not trigger events as I understand. Neither XTick nor XLim trigger something when changed. So the approach of Yair's FEX utility is to use MarkedClean but I can get it to work. Then I adapted the callback and added the event listener for MarkedClean of hRuler myself. It gets the ticks and it gets the axis, and it sets the axis.*TickLabel, but anyways - it d-o-e-s n-o-t w-o-r-k. Thanks. Code below.

function example_manual_ticks
    %% // some 3d plot
    hFig = figure;
    sphere
    view(3), grid on, box on
    xlabel x, ylabel y, zlabel z
    %% // create a hidden copy of the axis
    hax1 = gca;
    hax2 = copyobj(hax1, hFig);
    set(hax2, 'Visible','off', 'Color','none', 'HitTest','off', ...
        'XLimMode','manual', 'YLimMode','manual', 'ZLimMode','manual')
    delete(get(hax2, 'Children'))
    uistack(hax2, 'bottom')
    %// sync axes on 3d rotation
    hlink = linkprop([hax1,hax2], {'CameraPosition','CameraUpVector'});
    setappdata(hax1, 'my_axes_linkprop', hlink);
    rotate3d on
    %// respnd to changes in ZTick axis property
    %// only MATLAB < 2014b
    %//ev = addlistener(hax2, 'ZLim', 'PostSet',@(o,e) onZTickChange(o,e,hax1));
    %// FEX tool from Yair...but I do not get it to work
    %// there is not example for how the callback should look like
    %//ticklabelformat(gca,'z',@onZTickChange)
    %// Self made ... 
    hRuler = get(hax2,'ZRuler');
    addlistener(hRuler,'MarkedClean',@(X,event) onZTickChange(X,event,hax2));

    set(hax2,'ZTickLabelMode','manual')
    %% // animation
    el = 90 .* sin(linspace(0,2*pi,10) + asin(1/3));
    for n=1:numel(el)
        view(-37.5, el(n))
        drawnow
    end
end

function onZTickChange(~,eventDataUpdate,ax)
    %// NEW - Get ticks directly
    zticks_labels = num2str(eventDataUpdate.Source.Tick(:), '%.2f ($)'); 
    %// update ticks
    set(eventDataUpdate.Source, 'TickLabel',zticks_labels) 
    %// DOES NOT UPDATE THE LABELS SOMEHOW
    set(ax,'ZTickLabel',zticks_labels)
    %// ALSO DOES NOT UPDATE THE LABELS SOMEHOW
    drawnow
    %// ALSO HAS NO EFFECT
end
Community
  • 1
  • 1
embert
  • 7,336
  • 10
  • 49
  • 78

1 Answers1

3

Matt's solutions works quite okay

It can be used like so:

set(zoom(gcf),'ActionPostCallback',callbackfun);
set(pan(gcf),'ActionPostCallback',callbackfun);
set(rotate3d(gcf),'ActionPostCallback',callbackfun);
set(gcf,'ResizeFcn',callbackfun);
callbackfun(false,false);

with everything whats need saved in an anonymous function (MATLAB saves the entire current scope anyway as I understand). For instance

callbackfun = @(s,e) set(gca,'XTickLabel',myformatfun(get(gca,'XTick')))

The arguments to the anonymous function are just discarded. The line

callbackfun(false,false);

is for the initial setup.

And actually in the mean time I better got to know how to use the mesh function. I never understood, that the first arguments can be given as the scaling vectors just like with plot.

Complete Example with Subfunction
Note, that the sprintf('%.4f ($)|', zticks_) method for turning numeric arrays to string arrays apparently does not work in 2014b anymore. The callback setup could be put in a separate function of course.

function example_manual_ticks
    %% // some 3d plot
    figure;
    sphere
    view(3), grid on, box on
    xlabel x, ylabel y, zlabel z, rotate3d on
    %% // create a hidden copy of the axis
    hAx = gca;
    set(hAx,'ZTickLabelMode','manual')
    %% // set callback
    callbackfun = @(s,e) onZTickChange(hAx);
    set(zoom(gcf),'ActionPostCallback',callbackfun);
    set(pan(gcf),'ActionPostCallback',callbackfun);
    set(rotate3d(gcf),'ActionPostCallback',callbackfun);
    set(gcf,'ResizeFcn',callbackfun);
    callbackfun(false,false);
    %% // animation
    el = 90 .* sin(linspace(0,2*pi,10) + asin(1/3));
    for n=1:numel(el)
        view(-37.5, el(n))
        drawnow
    end
end

function onZTickChange(ax)
    %// get z ticks
    zticks_ = get(ax,'ZTick'); 
    %// format to tick label strings
    if verLessThan('Matlab', '8.4')
        %// MATLAB < 2014b
        zticks_labels = sprintf('%.4f ($)|', zticks_);
    else
        %// MATLAB >= 2014b
        zticks_labels = strtrim(cellstr(num2str(zticks_(:), '%.4f ($)'))');
    end
    %// set z tick labels
    set(ax,'ZTickLabel',zticks_labels)
end
Community
  • 1
  • 1
embert
  • 7,336
  • 10
  • 49
  • 78