No Gap Next to Axis Label in Matlab? - matlab

Matlab 2015b or Matlab 2016a.
I would like to have grid lines going across Subplot's spacing between the figures in order to evaluate better two pictures horizontally.
However, I have a small gap between the two figures at the lower right-hand-side corner because which is misaligning the figures
where the gap is because of the 10^4 at lower right-hand-side corner.
I would also like to have horizontal lines going across the spacing between the two figures, but I cannot do it before the gap problem is solved.
Code where the relative alignment is done as described in the answer here about the thread Tight subplot with colorbars and subplot's 3rd parameter in Matlab?
data=randi(513,513);
D=mat2gray(pdist(data, 'correlation'));
% Set normalized outer position (x,y,width,height)
ax1=axes('OuterPosition', [0 0.5 0.5 0.5]);
plot(D, 'Parent', ax1);
xlim([0 size(D,2)]);
set(cbar1, 'Visible', 'off')
title('Signal');
ax2=axes('OuterPosition', [0.51 0.5 0.5 0.5]);
plot(D, 'Parent', ax2);
set(ax2, 'XLim', [0, size(D,1)])
axis(ax2, 'square');
title('Corr pdist');
Output of Suever's answer
I tried unsuccessfully change two (2) in sprintf('%.2g', x) bigger and smaller
ax2 = axes('OuterPosition', [0.51 0.5 0.5 0.5]);
plot(D, 'Parent', ax2);
set(ax2, 'XLim', [0, size(D,1)])
axis(ax2, 'square');
title('Corr pdist');
cbar2 = colorbar(); % ax2 not needed here in brackets
set(ax2, 'XLim', [0 size(D,2)]);
set(cbar2, 'Visible', 'off')
grid minor;
% https://stackoverflow.com/a/35776785/54964
xticks = get(ax2, 'xtick');
labels = arrayfun(#(x)sprintf('%.2g', x), xticks, 'uniform', 0);
set(ax2, 'xticklabels', labels);
It gives
where those ticks are not XMinorTicks but simply ticks (wrongly marked in the picture).
They are zero points at some points in the x-axis. When x-axis gets larger, MATLAB automatically adds new xtick marks but without complete labels.
I think it would be better to have another symbol than zero there. How can you have some other mark than zero for incomplete labels of xticks?
How can you align the 10^4 next to the last number in the second figure?

I would get the current xtick locations, convert those to strings, and then set the xticklabels property of the axes.
xticks = get(ax2, 'xtick');
labels = arrayfun(#(x)sprintf('%.2g', x), xticks, 'uniform', 0);
set(ax2, 'xtick', xticks, 'xticklabels', labels);
If you want them to dynamically be computed as the figure changes size (and the xticks get recomputed) you can link this code to the SizeChangedFcn of the figure.
func = #(varargin)set(ax2,'xticklabels',arrayfun(#(x)sprintf('%.2g',x),get(ax2, 'xtick'),'uni',0));
set(gcf, 'SizeChangedFcn', func)

Related

Tight subplot with colorbars and subplot's 3rd parameter in Matlab?

I would like to have a tight subplot i.e. minimum spacing between figures in the subplot where
you have subplot's 3rd parameter i.e. you can decide where the picture is going to be i.e. easy to move between subplot and new_tight_subplot, and
you can use it with colorbars.
I have profiled the most popular tight subplots in FileExchange of Matlab.
None (etc most popular here Pekka's version) can pass the following code
data=randi(513,513);
ax1=subplot(2,1,1);
plot(mat2gray(pdist(data, 'correlation')));
cbar1=colorbar(ax1);
axis(ax1, 'square');
xlim([0 size(mat2gray(pdist(data, 'correlation')),2)]);
set(cbar1, 'Visible', 'off')
ax2=subplot(2,1,2);
imshow(squareform( mat2gray(pdist(data, 'correlation')), 'tomatrix') );
colormap('parula'); colorbar;
axis(ax2, 'square');
Pekka's tight_subplot requires the syntax without the third parameter.
It also fails with colorbars as in the example. I do not understand why.
Hypothesis about the 2nd problem with colorbars
I think the problem can be the fact that colorbar objects are children of the figure, not axis, and their position is defined in normalized figure units; like for annotated objects as discussed here.
However, I am unsure how to adjust the tight subplot for this.
Test output after Author's edit in tight_subplot in FileExchange 3.3.2016
Code
data = randi(513, 513);
ax1=tight_subplot(2,1,[.01 .03],[.1 .01],[.01 .01]);
plot(mat2gray(pdist(data, 'correlation')));
ax2=tight_subplot(2,1,[.01 .03],[.1 .01],[.01 .01]);
imshow(squareform( mat2gray(pdist(data, 'correlation')), 'tomatrix') );
You get
where the plot fails and there is noisy part in the second figure for some reason. Why?
Extension of Suever's answer to 2x2 figures
ax1=axes('OuterPosition', [0 0.5 0.5 0.5]);
plot(u, 'Parent', ax1);
set(ax1, 'XLim', [0, size(u,1)]);
cbar1 = colorbar(); % not needed to assign ax1
set(cbar1, 'Visible', 'off')
ax3 = axes('OuterPosition', [0 0 0.5 0.5]);
image(data, 'Parent', ax3);
D=mat2gray(pdist(pTFD, 'correlation'));
ax2 = axes('OuterPosition', [0.51 0.5 0.5 0.5]);
plot(D, 'Parent', ax2);
set(ax2, 'XLim', [0, size(D,1)])
axis(ax2, 'square');
xlim([0 size(D,2)]);
set(cbar2, 'Visible', 'off')
ax4 = axes('OuterPosition', [0.51 0 0.5 0.5]);
imshow( D_square );
axis(ax4, 'square');
where 2x2 figure system and where I think equivalent
xlim([0 size(D,2)]); is same as set(ax1, 'XLim', [0, size(D,2)]);. Right?
...
How can you use Matlab's tight subplot with colorbars and third parameter?
The third parameter of tight_subplot defines the gaps between axis objects. For the built-in subplot command, the third parameter defines which axis is set as the CurrentAxes of the Figure. This option is not available in tight_subplot because I personally did not find it useful. Typically, I use the returned axes handles to specify where to add graphics.
Existing axes objects are repositioned when you add a colorbar.
I have added a second output argument to tight_subplot which provides the output position of the axes so that you can "reset" the axes positions after adding a colorbar.
[hax, position] = tight_subplot();
% Add a colorbar which alters the positions
colorbar();
% Now reset the positions back to where they were
set(hax, {'Position'}, pos);
Rather than trying to deal with subplot and different versions on the file exchange, I would probably just manually set the positions of my axes objects to get the effect that you want. You can use normalized units so that the positions scale as the size of the parent figure changes.
Also, you can set the OuterPosition property of the axes which takes into account the room needed to properly display all text labels of the axes.
figure
data=randi(513,513);
set(0, 'defaultaxeslooseinset', [0 0 0 0])
D = mat2gray(pdist(data, 'correlation'));
square = squareform(D, 'tomatrix');
% Set normalized outer position (x,y,width,height)
ax1 = axes('OuterPosition', [0, 0.5, 1, 0.5]);
plot(D, 'Parent', ax1);
set(ax1, 'XLim', [0, size(square, 1)])
axis(ax1, 'square');
cbar1 = colorbar();
set(cbar1, 'Visible', 'off')
% Set normalized outer position (x,y,width,height)
ax2 = axes('OuterPosition', [0 0 1 0.5]);
imshow(square);
colormap('parula'); colorbar;
axis(ax2, 'square');
And if you remove the x and y ticks on the axes
set([ax1,ax2], 'xtick', [], 'ytick', []);
This can easily be adapted to any dimensions with something similar to the following
figure;
% [Rows, Columns]
axdim = [3, 3];
width = 1 ./ axdim(2);
height = 1./ axdim(1);
[x,y] = meshgrid(linspace(0,1,axdim(2)+1), ...
linspace(0,1, axdim(1)+1));
for k = 1:numel(x)
ax = axes('OuterPosition', [x(k), y(k), width, height]);
set(ax, 'xtick', [], 'ytick', []);
end

How to Have Non-Zero Symbol for Incomplete Labels of XTicks in Matlab?

I run into the problem where Matlab 2015b expands the labels of new Xticks when the x-axis gets bigger by using incomplete label, zeros, in the thread No Gap Next to Axis Label in Matlab?
The dynamic expansion of incomplete labels of xticks is not possible because there is always cases of insufficient space but only one symbol is needed to mark half between two values.
The situation is problematic with zeros because I have several calibration points and several systems where the extra zeros are errorprone.
I would like to have there another symbol.
Example code how to create those incomplete labels of xticks
labels = arrayfun(#(x)sprintf('%.2g', x), xticks, 'uniform', 0);
ax2 = axes('OuterPosition', [0.51 0.5 0.5 0.5]); % anything here
xticks = get(ax2, 'xtick'); % https://stackoverflow.com/a/35776785/54964
set(ax2, 'xticklabels', labels); % here the point!
Without those incomplete labels of xticks but broader labelling which is worser
labels = arrayfun(#(x)sprintf('%.2g', x), xticks, 'uniform', 0);
ax2 = axes('OuterPosition', [0.51 0.5 0.5 0.5]);
xticks = get(ax2, 'xtick'); % https://stackoverflow.com/a/35776785/54964
set(ax2, 'xtick', xticks, 'xticklabels', labels);
Output of Suever's answer
Beautiful Small window in the original size with scientific numbering because of callback(); at the end of the code following
Medium window
Code
hFig=figure;
data=randi(513,513);
D=mat2gray(pdist(data, 'correlation'));
ax2 = axes('OuterPosition', [0.51 0.5 0.5 0.5]);
plot(D, 'Parent', ax2);
axis(ax2, 'square');
title('Corr pdist');
cbar2 = colorbar();
set(ax2, 'XLim', [0 size(D,2)]);
set(cbar2, 'Visible', 'off')
grid minor;
labelconverter = #(x)sprintf('%.2g', x); % https://stackoverflow.com/a/35780915/54964
callback = #(varargin)set(ax2, 'xticklabels', arrayfun(labelconverter, get(ax2, 'xtick'), 'uniform', 0));
set(hFig, 'SizeChangedFcn', callback);
callback(); % necessary for small window
How can you have another symbol for the incomplete labels of xticks in Matlab?
As I said in the other question, if you want the labels to be updated automatically when you resize things, you'll want to do the following.
fig = figure;
% Set large xlimits to demonstrate the issue at hand
ax2 = axes('xlim', [0 1e9]);
% Force a draw event to have the axes determine where the
labelconverter = #(x)sprintf('%.2g', x);
callback = #(varargin)set(ax2, 'xticklabels', arrayfun(labelconverter, get(ax2, 'xtick'), 'uniform', 0));
set(fig, 'SizeChangedFcn', callback);
% Be sure to execute the callback to get new labels prior to figure resize.
callback();
As you change the size of your figure, the labels will be changed automatically and the positions will be updated.
Small Window
Medium Window
Large Window
Note: Test this code in isolation to verify that it works, then adapt the idea to your solution. It seems like you're ending up with a lot of complications because your namespace is polluted (for example your examples don't even run because labels isn't defined).

Linkaxes of Heterogenous Matrixes in Square Control of Matlab?

I am trying to have the linked control of two matrices which have different xlims and ylims by linkaxes() where there exists an inverse function between the two matrices.
The axes of the matrices (signal D / square matrix D_square) are ax2/ax4, respectively.
The dimensions of the axes are
The limits of ax2 are different than those of ax4, since linkaxes() just makes all input axes have identical limits.
A selection of Fig. ax2 (= zooming an area in the figure) should bring forward appropriate selection in Fig. ax4.
I think you should tell Matlab how to do it.
The only difference between the two datasets is that data of ax2 is the matrix D, while the data of ax4 is the matrix D_square=squareform(D, 'tomatrix') which has an inverse transform, D=squareform(D_square, 'tomatrix') so it is possible to have a control between the two figures.
Code
data=randi(513,513);
D=mat2gray(pdist(data, 'correlation'));
% Set normalized outer position (x,y,width,height)
ax2 = axes('OuterPosition', [0.51 0.5 0.5 0.5]);
plot(D, 'Parent', ax2);
axis(ax2, 'square');
title('Corr pdist');
cbar2 = colorbar();
set(ax2, 'XLim', [0 size(D,2)]);
set(cbar2, 'Visible', 'off')
grid minor;
% Force a draw event to have the axes determine where the
labelconverter = #(x)sprintf('%.2g', x); % http://stackoverflow.com/a/35780915/54964
callback = #(varargin)set(ax2, 'xticklabels', arrayfun(labelconverter, get(ax2, 'xtick'), 'uniform', 0));
set(hFig, 'SizeChangedFcn', callback);
callback(); % necessary for the original small window and its scientific numbering
%% Problem here!
D_square=squareform(D, 'tomatrix');
ax4 = axes('OuterPosition', [0.51 0 0.5 0.5]);
set(ax4, 'XLim', [0 size(D_square,2)]);
image( D_square, 'Parent', ax4 ); % TODO problem here!
set(gca,'YDir','normal');
colormap('parula'); colorbar;
axis(ax4, 'square');
title('Square Corr pdist');
linkaxes([ax2,ax4], 'x');
Output
where Fig. ax4 gets substituted because lims of ax4 are substituted by ax2, vice versa for linkaxes([ax4,ax2], 'x'); in the last line.
Some fixes in Suever's answer
Some changes
Use imagesc() in him=imagesc( D_square, 'Parent', ax4 );
initiate/let things be square by axis(ax4, 'square'); just after imagesc(); not sure why
unknown about if linkaxes([ax2,ax4], 'xy'); or just one axis linkaxes([ax2,ax4], 'x');
Code
data=randi(513,513);
D=mat2gray(pdist(data, 'correlation'));
% Figure out the xrange of your first plot
xrange = [1, numel(D)];
% Set normalized outer position (x,y,width,height)
ax2 = axes('OuterPosition', [0.51 0.5 0.5 0.5]);
plot(D, 'Parent', ax2);
axis(ax2, 'square');
title('Corr pdist');
cbar2 = colorbar();
set(ax2, 'XLim', [0 size(D,2)]);
set(cbar2, 'Visible', 'off')
grid minor;
% Force a draw event to have the axes determine where the
labelconverter = #(x)sprintf('%.2g', x); % http://stackoverflow.com/a/35780915/54964
callback = #(varargin)set(ax2, 'xticklabels', arrayfun(labelconverter, get(ax2, 'xtick'), 'uniform', 0));
set(hFig, 'SizeChangedFcn', callback);
callback(); % necessary for the original small window and its scientific numbering
D_square=squareform(D, 'tomatrix');
ax4 = axes('OuterPosition', [0.51 0 0.5 0.5]);
set(ax4, 'XLim', [0 size(D_square,2)]);
him=imagesc( D_square, 'Parent', ax4 );
axis(ax4, 'square'); % To let things be square!
set(gca,'YDir','normal');
colormap('parula'); colorbar;
title('Square Corr pdist');
% Set XData AND YData (to keep things square)
set(him, 'XData', xrange, 'YData', xrange);
linkaxes([ax2,ax4], 'xy');
where the problem is
to keep things square by set(him, 'XData', xrange, 'YData', xrange);
and to initiate/let them be square by axis(ax4, 'square'); just after imagesc(); code not working as expected having initiation of square shape too far from plotting for some reason.
I think personally that it may not be possible to have strict control (both x,y axes by linkaxes([ax2,ax4], 'xy')) between the two figures.
I think only one axis (by linkaxes([ax2,ax4], 'x') or linkaxes([ax2,ax4], 'y')) can be controlled at least because there exists an inverse function. Some empirical evidence
Output in linkaxes([ax2,ax4], 'xy'); is two empty figures.
Output in linkaxes([ax2,ax4], 'x'); is one figure with some graph and full matrix. Similar with y control.
Active control of square shape
Here active control of square shape by set(him, 'XData', xrange, 'YData', xrange);.
Outputs with keeping square in original view
where one full matrix.
Outputs without keeping square in original view
Disable set(him, 'XData', xrange, 'YData', xrange);
where Fig.ax4 is right. No
Successful Output from Suever's 2nd edit
Original view in x control by linkaxes([ax2,ax4], 'x'); and other changes about labels as described in Suever's answer
where the medium picture is also functional.
How can you tell Matlab the relation between the figures in using linkaxes()?
How can you have a linked control between the two figures in Matlab?
You're having issues because the image in your bottom axes is 513 x 513 (xlims = [0.5 513.5]) whereas the xlimits of your top axes [0 131328]. If you need them to be the same, you can simply alter the XData and YData of your image to be the same as your XLims for your top plot.
% Figure out the xrange of your first plot
xrange = [1, numel(D)];
% Set XData AND YData (to keep things square)
him = image( D_square, 'Parent', ax4 );
set(him, 'XData', xrange, 'YData', xrange);
Now when you call linkaxes (which links XLims) they should move together. You will also need to call axis(ax4, 'tight') to refit the axes to the new image data.
I have included a modified version of your code below that also keeps the xticklabels the same between the two plots.
hFig = figure();
data = randi(513,513);
D = mat2gray(pdist(data, 'correlation'));
D_square = squareform(D, 'tomatrix');
% Set normalized outer position (x,y,width,height)
ax2 = axes('OuterPosition', [0.51 0.5 0.5 0.5]);
plot(D, 'Parent', ax2);
axis(ax2, 'square');
title('Corr pdist');
cbar2 = colorbar();
set(ax2, 'XLim', [0 size(D,2)]);
set(cbar2, 'Visible', 'off')
grid minor;
% Force a draw event to have the axes determine where the
labelconverter = #(x)sprintf('%.2g', x); % http://stackoverflow.com/a/35780915/54964
callback = #(varargin)set(ax2, 'xticklabels', arrayfun(labelconverter, get(ax2, 'xtick'), 'uniform', 0));
set(hFig, 'SizeChangedFcn', callback);
callback(); % necessary for the original small window and its scientific numbering
ax4 = axes('OuterPosition', [0.51 0 0.5 0.5]);
him = imagesc( D_square, 'Parent', ax4 ); % TODO problem here!
% Set the XData and YData of the image
set(him, 'xdata', [1, size(D, 2)], 'ydata', [1, size(D,2)])
set(ax4,'YDir','normal');
colormap('parula');
colorbar;
axis(ax4, 'square');
% Fit the axes to the new XData and YData
axis(ax4, 'tight')
title('Square Corr pdist');
% Link the two together
linkaxes([ax2,ax4], 'x');
% Ensure that the labels ALSO remain the same
linkprop([ax2,ax4], 'XTickLabel')

Background Grid Lines Across Spacing of Figures in Matlab?

I would like to have vertical/horizontal grid lines across spacing of figures in Matlab 2015b.
I know that you can have a background image that can be a network of gridlines by background, something partial about it at How do I add a background image to my GUI or figure window?
However, I think gridlines without a picture would be a better choice
Example code
data=randi(513,513);
D=mat2gray(pdist(data, 'correlation'));
ax2 = axes('OuterPosition', [0.51 0.5 0.5 0.5]);
plot(D, 'Parent', ax2);
set(ax2, 'XLim', [0, size(D,1)])
axis(ax2, 'square');
title('Corr pdist');
cbar2 = colorbar();
set(ax2, 'XLim', [0 size(D,2)]);
set(cbar2, 'Visible', 'off')
grid minor;
% Force a draw event to have the axes determine where the
labelconverter = #(x)sprintf('%.2g', x); % https://stackoverflow.com/a/35780915/54964
callback = #(varargin)set(ax2, 'xticklabels', arrayfun(labelconverter, get(ax2, 'xtick'), 'uniform', 0));
set(hFig, 'SizeChangedFcn', callback);
callback(); % necessary for the original small window and its scientific numbering
D_square=squareform(D, 'tomatrix');
ax4 = axes('OuterPosition', [0.51 0 0.5 0.5]);
imshow( D_square );
colormap('parula'); colorbar;
axis(ax4, 'square');
title('Square Corr pdist');
where the system is based on relative positions, rather than subplot as described in the answer here about Tight subplot with colorbars and subplot's 3rd parameter in Matlab?
Hypothetical methods
have master figure which has grid lines; embed those two figures there as parent positions; not sure if possible
assign gridlines function to the function background
have a separate background image which has static gridlines
Function about Suever's script
function [ hFig ] = init_background_grid(thickness)
%% Background
hFig=figure;
backax = axes('Parent', hFig);
% Ensure that this is below other objects
uistack(backax, 'bottom');
% Span the whole figure
set(backax, 'Position', [0 0 1 1]);
grid(backax, 'on')
% Make it invisible except for the grid and
% ensure it isn't able to be interacted with
set(backax, 'HitTest', 'off', ...
'HandleVisibility', 'off', ...
'GridLineStyle', '-', ...
'Color', 'none', ...
'XColor', 'none', ...
'YColor', 'none')
% Determine grid spacing with x/y ticks
% Increase nLines for a finer grid
nLines = thickness; % 30 default
set(backax, 'XTick', linspace(0, 1, nLines), ...
'YTick', linspace(0, 1, nLines));
end
How can you have grid lines in the background i.e. in the spacing between figures?
I would probably just setup an axes that spans your entire figure, then turn on the grid lines, then set the color of the axes to 'none'. A full example is shown below.
fig = figure();
backax = axes('Parent', fig);
% Ensure that this is below other objects
uistack(backax, 'bottom');
% Span the whole figure
set(backax, 'Position', [0 0 1 1]);
grid(backax, 'on')
% Make it invisible except for the grid and
% ensure it isn't able to be interacted with
set(backax, 'HitTest', 'off', ...
'HandleVisibility', 'off', ...
'GridLineStyle', '-', ...
'Color', 'none', ...
'XColor', 'none', ...
'YColor', 'none')
% Determine grid spacing with x/y ticks
% Increase nLines for a finer grid
nLines = 20;
set(backax, 'XTick', linspace(0, 1, nLines), ...
'YTick', linspace(0, 1, nLines));
You can then add any plots, uicontrols, etc. on top of this and it should work just fine. It will also handle the case where you decide that you want a different figure color.

Zoomed In/Out Plots within Subplots in Matlab

I've run into a bit of a hiccup trying to plot some data in the way I want it - any advice would be greatly appreciated.
left and right are vectors of a few hundred thousand in length, obtained elsewhere.
The code below plots left, twice - the second plot lies on top of the first, roughly towards one corner.
ax1 = axes;
plot(ax1, left, 'b');
set(ax1, 'xlim', [7.075*10^4 7.5*10^4]);
set(ax1, 'ylim', [-0.02 0.02]);
ax2 = axes('Position', get(ax1,'Position'), 'XAxisLocation', 'top', 'YAxisLocation', 'right', 'Color', 'none', 'XColor', 'k', 'YColor', 'k', 'NextPlot', 'add');
plot(ax2, left, 'b');
set(ax2, 'Units', 'normalized', 'Position', [0.6 0.60 0.25 0.25]);
What I'd like to do is have the same kind of thing for right, and then display each pair of plots as a subplot, with the two subplots side by side. I've tried adapting the way I'm doing it above to use subplot, but I'm obviously doing something wrong since I keep on nuking the contents of each subplot and ending up with two empty subplots.
Also, is it possible to prevent the smaller inset plot from having a transparent background?
Consider the following example:
%# sample data
x = 1:100;
left = randn(100,1);
right = cumsum(rand(100,1)-0.5);
%# build axes positions
hBig = [subplot(121) subplot(122)]; %# create subplots
posBig = get(hBig, 'Position'); %# record their positions
delete(hBig) %# delete them
posSmall{1} = [0.275 0.63 0.16 0.24];
posSmall{2} = [0.717 0.63 0.16 0.24];
%# create axes (big/small)
hAxB(1) = axes('Position',posBig{1});
hAxB(2) = axes('Position',posBig{2});
hAxS(1) = axes('Position',posSmall{1});
hAxS(2) = axes('Position',posSmall{2});
%# plot
plot(hAxB(1), x, left, 'b');
plot(hAxB(2), x, right, 'b');
plot(hAxS(1), x, left, 'r');
plot(hAxS(2), x, right, 'r');
%# set axes properties
set(hAxB, 'XLim',[1 100], 'YLim',[-10 10]);
set(hAxS , 'Color','none', 'XAxisLocation','top', 'YAxisLocation','right');
If you want the background color of the smaller axes to be opaque, just set their colors to white:
set(hAxS , 'Color','w')
To change the background, use (for red background)
set(ax2,'color',[1 0 0])
Regarding the subplot, if you post the code that doesn't work it will help.