MATLAB Answers

Cas Cas
1

Stretch parts of axis (non uniform axis)

Asked by Cas Cas
on 19 Jan 2018
Latest activity Commented on by Kelly Kearney
on 20 Jan 2018
Hi, I'm looking to create nonuniform axes in some plots. I'm aware of setting things like xticks and XScale, etc., but these change the spacing of the ticks themselves, rather than the data points. I'm looking to do something akin to a log or semi-log plot, where the data points themselves are stretched around accordingly, but not necessarily looking for logs.
For example, say I have x and y data and say the yticks = [0 500 1000 1500 2000 2500 3000] evenly spaced. The x data is very interesting for my purposes in the sub-1000 level so I'd like to stretch this so my plot: the data between 0 and 1000 now occupies the same amount of space that 0 to 2000 used to take and the data beyond 1000 is uniformly spaced as before, it's just now higher up in the figure. So with respect to the original figure, the new figure now takes up more vertical space and part of it is 'zoomed in', in a sense. I've attached an illustration.
Before
|
3000|
|
2500|
|
2000|
|
1500|
|
1000|
|
500|
|
0|--------------------------------------------------x
What I want:
|
3000|
|
2500|
|
2000|
|
1500|
|
1000|
|
|
|
500|
|
|
|
0|--------------------------------------------------x
and the x scale is the same in both.
I've played around with logs and manipulating ticks but the logs affect the entire dataset and while the ticks can be manipulated I've only been able to place the labels nonuniformly, without attention to the data itself.
Hope that makes sense.

  0 Comments

Sign in to comment.

1 Answer

Answer by Kelly Kearney
on 19 Jan 2018

You could scale the data appropriately and then overwrite the tick labels, but assuming you only have a few scaling blocks, I often accomplish this using two (or more) stacked axes, with the same data duplicated in each but with the y-scale set to adjacent values:
ax(1) = axes('position', [0.1 0.5 0.8 0.4]);
plot(1:100, rand(100,1)*3000);
ax(2) = copyobj(ax(1), gcf);
set(ax(2), 'position', [0.1 0.1 0.8 0.4]);
set(ax(1), 'box', 'off', 'xcolor', 'none');
set(ax(2), 'box', 'off');
set(ax(1), 'ylim', [1000 3000]);
set(ax(2), 'ylim', [0 1000]);
linkaxes(ax, 'x');
You may have to manually tweak tick labels to prevent overlap, but it's pretty straightforward otherwise.

  2 Comments

I thought about this but also wasn't sure where to begin. This works great with 2D plots, can it be implemented for 3D, such that the z-scale is now the axis that is manipulated?
To be clear, I can use the strategy to manipulate the z-axis but there is that gap in the middle of the curve (it should be a single curve plotted in 3D space). Fixing the overlapping of the axes is not an issue, just that gap in the middle. Any ideas? Thanks.
Hmm, you can almost do it with some creative overlap of axes:
[x,y,z] = peaks;
h = plotgrid('size', [2 1], 'sp', -0.26);
for ii = 1:2
s(ii) = surf(h.ax(ii), x,y,z);
end
set(h.ax(1), 'zlim', [5 9], 'xcolor', 'none', 'ycolor', 'none');
set(h.ax(2), 'zlim', [-7 5]);
set(h.ax, 'color', 'none', 'xgrid', 'off', 'ygrid', 'off');
( plotgrid is one of my own functions, to create a custom grid of axes).
But there are still some odd clipping artifacts at the x-axis... not sure if there is a way around that. 3D axes are in general more difficult to hack; so much of their positioning is hidden under undocumented properties and inaccessible code.

Sign in to comment.