Plotting transparent lines in MATLAB - matlab

I'm trying to create a plot in MATLAB of ERP data. At present, the below code plots a waveform for 26 participant for channel 1, with mean amplitude on Y axis and time on X. I want to change the plot such that the waveforms are all light grey, but become darker where there are a lot of waves on top of one another.
times = Condition1.time;
channel = [1];
% the difference (for every participant, every channel, and every timepoint)
diff = (grandaverages.Condition1.individual) - (grandaverages.Condition2.individual);
channeldiffwaves = squeeze( mean( diff(:,channels,:), 2 ) );
% make the space to put the figure on
figure; hold on;
% list of participants to plot
plotparticipantIdx = [1:26];
% go through each participant
for participantIdx = plotparticipantIdx
ptpdiffwave = channeldiffwaves( participantIdx, : );
plot( times, ptpdiffwave )
end
% make a x-axis at zero
plot( times, zeros( size(times) ), 'k' )
How can I make all lines light gray and darkening where lines overlap?

You can use the RGB-alpha quadruplet:
plot(x, y, 'Color', [0 0 0 0.3]);
The first three entries are your standard RGB-triplet, i.e. 0 0 0 for black, then change the alpha (=transparency) between 0 (invisible) and 1 (completely visible).
As a side-note, this isn't even documented in the Chart line appearance and behavior part of MATLAB's documentation.
I can't quite figure out when this syntax was introduced; on my R2007b it doesn't work, but from 2017 onwards this solution starts popping up on the internet, thus I presume this was introduced with the overhaul of the graphic's engine in R2016b.

Related

How to make previous inputs progressively fade out in a Matlab plot when I add new inputs

Let's say I have this very simple loop
for i=1:10
[xO, yO, xA, yA, xB, yB, xC, yC] = DoSomething(i);
line([xO,xA,xB,xC],[yO,yA,yB,yC]);
pause(0.1);
end
The coordinates that I am plotting correspond to the joints of a multibody system, and I am simulating their positions over time (please see a sample of the plot here):
Since some of the links move in a periodic way, it gets confusing to keep track visually of the movement. For this reason, now comes the question: how can I plot the lines in a way that, when a new line is plotted, the previous lines are faded progressively? In other words, so that I have a gradient from the most recently plotted data (most opaque) to the oldest data (increasingly transparent until it completely fades out).
This way when a new line is drawn in the same position as very old data, I will notice that it is a new one.
You can do this by modifying the 4th Color attribute of past lines.
Here's a demo resulting gif, where I faded out 10% of the transparency each frame, so only the most recent 10 lines are visible.
Here is the code, see my comments for details:
% Set up some demo values for plotting around a circle
a = 0:0.1:2*pi; n = numel(a);
[x,y] = pol2cart( a, ones(1,n) );
% Initialise the figure, set up axes etc
f = figure(1); clf; xlim([-1,1]); ylim([-1,1]);
% Array of graphics objects to store the lines. Could use a cell array.
lines = gobjects( 1, n );
% "Buffer" size, number of historic lines to keep, and governs the
% corresponding fade increments.
nFade = 10;
% Main plotting loop
for ii = 1:n
% Plot the line
lines(ii) = line( [0,x(ii)], [0,y(ii)] );
% Loop over past lines.
% Note that we only need to go back as far as ii-nFade, earlier lines
% will already by transparent with this method!
for ip = max(1,ii-nFade):ii
% Set the 4th Color attribute value (the alpha) as a percentage
% from the current index. Could do this various ways.
lines(ip).Color(4) = max( 0, 1 - (ii-ip)/nFade );
end
% Delay for animation
pause(0.1);
end
You may want to do some plot/memory management if you've got many lines. You can delete transparent lines by adding something like
if lines(ii).Color(4) < 0.01
delete(lines(ii));
end
Within the loop. This way your figure won't have loads of transparent remnants.
Notes:
I generated the actual gif using imwrite in case that's of interest too.
Apparently the 4th Color value 'feature' has been depreciated in R2018b (not sure it was ever officially documented).
Got enough upvotes to motivate making a slightly more fun demo...
Solution for Matlab 2018a or later (or earlier, later than 2012a at least)
Since the fourth color parameter as alpha value is no longer supported in Matlab 2018a (and apparently was never supposed to as Cris Luengo pointed out), here a solution that works in Matlab 2018a using the patchline function from the file exchange (credits to Brett Shoelson).
% init the figure
figure(); axes();
hold on; xlim([-1 0.5]); ylim([0 1]);
% set fraction of alpha value to take
alpha_fraction = 0.7;
n_iterations = 200;
% looping variable to prevent deleting and calling already deleted lines
% i.e. to keep track of which lines are already deleted
delete_from = 1;
for i=1:n_iterations
% your x, y data
[x, y] = doSomething(i);
% create line with transparency using patchline
p(i) = patchline(x,y, 'linewidth', 1, 'edgecolor', 'k');
% set alpha of line to fraction of previous alpha value
% only do when first line is already plotted
if i > 1
% loop over all the previous created lines up till this iteration
% when it still exists (delete from that index)
for j = delete_from:i-1
% Update the alpha to be a fraction of the previous alpha value
p(j).EdgeAlpha = p(j).EdgeAlpha*alpha_fraction;
% delete barely visible lines
if p(j).EdgeAlpha < 0.01 && delete_from > j
delete(p(j));
% exclude deleted line from loop, so edgealpha is not
% called again
delete_from = j;
end
end
end
% pause and behold your mechanism
pause(0.1);
end
I included the deletion of barely visible lines, as suggested by #Wolfie (my own, perhaps less elegant implementation)
And here a demonstration of a quick release mechanism:
I'm adding a 2nd answer to clearly separate two completely different approaches. My 1st answer uses the undocumented (and as of 2018b, depreciated) transparency option for lines.
This answer offers a different approach for line drawing which has no compatibility issues (these two 'features' could be implemented independently):
Create a fixed n lines and update their position, rather than creating a growing number of lines.
Recolour the lines, fading to white, rather than changing transparency.
Here is the code, see comments for details:
% "Buffer" size, number of historic lines to keep, and governs the
% corresponding fade increments.
nFade = 100;
% Set up some demo values for plotting around a circle
dt = 0.05; a = 0:dt:2*pi+(dt*nFade); n = numel(a); b = a.*4;
[x1,y1] = pol2cart( a, ones(1,n) ); [x2,y2] = pol2cart( b, 0.4*ones(1,n) );
x = [zeros(1,n); x1; x1+x2]; y = [zeros(1,n); y1; y1+y2];
% Initialise the figure, set up axes etc
f = figure(1); clf; xlim([-1.5,1.5]); ylim([-1.5,1.5]);
% Draw all of the lines, initially not showing because NaN vs NaN
lines = arrayfun( #(x)line(NaN,NaN), 1:nFade, 'uni', 0 );
% Set up shorthand for recolouring all the lines
recolour = #(lines) arrayfun( #(x) set( lines{x},'Color',ones(1,3)*(x/nFade) ), 1:nFade );
for ii = 1:n
% Shift the lines around so newest is at the start
lines = [ lines(end), lines(1:end-1) ];
% Overwrite x/y data for oldest line to be newest line
set( lines{1}, 'XData', x(:,ii), 'YData', y(:,ii) );
% Update all colours
recolour( lines );
% Pause for animation
pause(0.01);
end
Result:

Plotting a phase portrait with multiple colors with MATLAB

I want to add something to make my phase portrait more understandable. Nevertheless, I can't find anything (I found this
https://se.mathworks.com/help/matlab/ref/colorspec.html
https://se.mathworks.com/matlabcentral/fileexchange/11611-linear-2d-plot-with-rainbow-color
https://se.mathworks.com/help/symbolic/mupad_ref/linecolortype.html
) but it is not what I need.
I would really like to see the color of the line of the phase portrait changing depending of if it is at the beginning or at the end of the simulation.
I found this idea which seems great :
I don't understand at all what he has done (the code is I suppose written here:
https://blogs.mathworks.com/pick/2008/08/15/colors-for-your-multi-line-plots/ )
but It would be great if I can plot a one line function which color varies depending of the time. If moreover, like on the picture, I can have have a scale on the right: it would be awesome.
So for now, I have that :
data = readtable('test.txt');
figure('Name','Phase' , 'units','normalized','outerposition',[(8/100) (0.3- 16/100) 0.5 0.7]);
hold on
plot(data{:,2},data{:,3}, 'k.', 'LineWidth',1.5 );
plot(data{:,4},data{:,5}, 'r.', 'LineWidth',1.5 );
xL = xlim;
yL = ylim;
line([0 0], yL); %x-axis
line(xL, [0 0]); %y-axis
title(['Phase portrait'])
xlabel('f')
ylabel('f '' ')
hold off
I read the values of the function in a .txt file, and then I plot the 2nd/3rd columns and 4/5th columns. The first column is the time evoluting.
Do you have any idea :)?
Thank you!
There are several ways to go about this to be honest.
However it makes a bit easier if you let us know what your time data is.
Do you plot your time data on the x (or y) axis or is it a different additional data set. Should it be an additional data set then you can consider it like z-data, plotted on the Z-axis or/and as a color.
Below is an example of what you can do by making a 3D plot but displaying it in 2D, this allows you to add the colorbar without too many problems.
x=0:5;
y=0:5;
z=rand(1,6); %random data to simulate your time
xx=[x' x']; %this allows you to plot the data using surf in 3d
yy=[y' y']; %same as for xx
z1=zeros(size(xx)); % we don't need z-data so we're making it a matrix of zeros
zc=[z' z']; %input here your time data values, if x/y then you can just use those instead of z
hs=surf(xx,yy,z1,zc,'EdgeColor','interp') %// color binded to "z" values, choose interp for interpolated/gradual color changes, flat makes it sudden
colormap('hsv') %choose your colormap or make it yourself
view(2) %// view(0,90)
hcb=colorbar; %add a colorbar
I found this, thanks to another user on stackoverflaw.
data = readtable('4ressorspendule.txt');
n = numel(data.Var1);
c = size(data,2);
figure('Name','Phase' , 'units','normalized','outerposition',[(8/100) (0.3 - 16/100) 0.5 0.7]);
for i=1:n
hold on
plot(data{i,2},data{i,3},'.','Color',[1 (1-i/n) 0] ,'MarkerSize',4);
plot(data{i,4},data{i,5},'.','Color',[0 (i/n) (1-i/n)],'MarkerSize',4);
end
xL = xlim;
yL = ylim;
line([0 0], yL); %x-axis
line(xL, [0 0]); %y-axis
title(['Phase portrait'])
xlabel('f')
ylabel('f '' ')
hold off

How to detect peaks on gray background with Matlab FastPeakFind?

I am testing the validity of the FileExchange project FindPeaksFast with different linewidths and backgrounds.
Test 1 is successful and the tool detects all peaks from 1px to 10 px.
However, Test 2 fails when testing to find peaks on the frame of an object plot i.e. an object (plot) on gray background.
The tool works well on white background.
Code
close all; clear all; clc;
f = figure;
hax = axes(f);
% Comment this out for Test 2
%zeroFigureDecorations(hax);
af = figure('Name', 'Do Not Touch');
x = rand(1,100);
y = rand(1,100);
linewidth=1;
plot(hax, x,y, 'LineWidth', linewidth);
I = getframe(hax);
I = I.cdata;
% https://se.mathworks.com/matlabcentral/fileexchange/37388-fast-2d-peak-finder
p=FastPeakFind(I);
% Input: 344x435x3 uint8
hold(hax, 'on');
plot(hax, p(1:2:end),p(2:2:end),'r+')
hold(hax, 'off');
function zeroFigureDecorations(ax)
axis(ax, 'tight');
set(ax, 'yTickLabel', []);
set(ax, 'xTickLabel', []);
set(ax, 'Ticklength', [0 0]); % http://stackoverflow.com/a/15529630/54964
colormap(ax, 1-gray(1024));
box(ax, 'off');
axis(ax, 'off');
end
Outputs in the following, and Fig. 1 shows that the function can detect something on lines when the background is white but not on correct locations.
Linewidth Output
10 166x1 double
1 844x1 double
Table: full axis decoration in Test 1
Linewidth Output
10 []
1 []
Table: no axis decorations, after zeroFigureDecorations(hax) in Test 2
Fig. 1 line as input (See Bla's answer) and its output,
Fig. 2 Output is wrong in Section 2,
Fig. 3 One more example that you cannot apply to function to simple curves,
Fig. 4 Section 3 Output is wrong, since not known how to apply the function on spectrograms
2 Test with bla's example data
f0 = figure;
hax0 = axes(f0);
d=uint16(conv2(reshape(single( 2^14*(rand(1,128*128)>0.9995) ),[128 128]) ,fspecial('gaussian', 10,2),'same')+2^4*rand(128));
imagesc(d, 'Parent', hax0);
I = getframe(hax0);
I = I.cdata;
p=FastPeakFind(I);
hold(hax0, 'on');
plot(hax0, p(1:2:end),p(2:2:end),'r+')
hold(hax0, 'off');
Output is wrong in Fig. 2
3 Testing with spectrograms
f3 = figure;
hax3 = axes(f3);
N = 1024*10;
n = 0:N-1;
w0 = 2*pi/5;
x = sin(w0*n)+10*sin(2*w0*n);
s = spectrogram(x);
spectrogram(x,'yaxis')
p=FastPeakFind(s);
hold on;
plot(p(1:2:end),p(2:2:end),'r+')
Matlab: 2016b
OS: Debian 8.5
You are not using the function correctly.
your code is this (verbatim):
f = figure;
hax = axes(f);
af = figure('Name', 'Do Not Touch');
x = rand(1,100);
y = rand(1,100);
linewidth=1;
plot(hax, x,y, 'LineWidth', linewidth);
I = getframe(hax);
I = I.cdata;
The matrix I is not a matrix that contain peaks like the function is intended to have. This is how it looks like:
imagesc(I);
Even if all you had were single pixels, that is not what the function is supposed to have, as it is said that the peaks point spread function needs to be larger than some # of pixels, and that they are assumed to be sparse. The function has a demonstration on a sample image that works fine.
Also , it's completely unclear what you even mean by peaks here.
EDIT:
Here's an example of how to use the function. First let's select random positions where we "create" the peaks:
I=rand(200)>0.9995;
This makes a binary matrix with only the points larger than 0.9995 selected (or having value 1). At each step you can imagesc(I) to see how I looks.
In real life, a camera will have some intensity in these points so we write:
I=I*100;
This is important as the peak by dentition needs to be a maximum value in its neighborhood. In real life, peaks are mostly not single pixels, they have some "width" or spread (this is also what the function says it deals with):
I=conv2(I,fspecial('gaussian',10,2),'same');
here, this spread is done by a "point-spread function" of a guassian of some width.
Lets add some 30% noise (note that after the last step the maximum value of the peaks is no longer 100, because it is spread to other pixels as well):
I=I+0.3*max(I(:))*rand(size(I));
Let's find peaks
p=FastPeakFind(I);
See how it did:
subplot(1,2,1);imagesc(I);
subplot(1,2,2);imagesc(I); hold on
plot(p(1:2:end),p(2:2:end),'r+')
In the function code, the example is doing what I wrote here in a single line. Note that there is an edg parameter, as this will not work on peaks on the edges of the image. This cab be solved by padding the image with zeros I think...

How to subplot + imagesc with a Position in Matlab?

Situation: change Position of a single subplot with imagesc
%% Matlab recommends this structure if axes(); in loop
a1 = subplot(1,2,1);
a2 = subplot(1,2,2);
while 1    
plot(a1, rand(3))    
plot(a2, rand(3))    
drawnow
end
%% Test code
unitsPerInches=[0 0 15 15];
figure('Units', 'inches');
a1 = subplot(1,2,1);
a2 = subplot(1,2,2);
while 1    
set(a1, 'Position', unitsPerInches); % TODO how to affect a1's Position here only?
imagesc(a1, rand(3))    
imagesc(a2, rand(3))    
drawnow
end
Open
What is imagesc corresponding structure to plot(a1,rand(3))?
How to change Position of figure inside the loop?
Forward in Q1 - almost done
%% Extension to imagesc
figure
a1=subplot(1,2,1);
a2=subplot(1,2,2);
for counter=1:2;
imagesc(a1,rand(3))
imagesc(a2,rand(3))
drawnow
end
Fig. 1 Output of Docs example, Fig. 2 Output of Imagesc, Fig. 3 about Q2 where Position affects both subplots
Q1 is almost done; I have just forgotten how to get corresponding plot in imagesc; x-values should be put there but pseudocode imagesc(a1,XDATA,rand(3)) is unsuccessfuly.
Backward in Q2
Code
%% Extension to imagesc
unitsPerInches=[0 0 15 15];
figure
a1=subplot(1,2,1);
a2=subplot(1,2,2);
for counter=1:2;
set(a1, 'Position', unitsPerInches); % TODO how to affect a1's Position here only?
imagesc(a1,rand(3))
imagesc(a1,rand(3))
drawnow
end
Output: position affects both images in Fig. 3.
I think I have misunderstood the meaning of Position here because so strange output.
Testing EBH's proposal for Q2
The implicit assignments cause problems when having two figures where subplots
unitsPerInches=[0 0 15 15];
aFig=figure();
a1=subplot(1,2,1);
a2=subplot(1,2,2);
bFig=figure();
b1=subplot(1,2,1);
b2=subplot(1,2,2);
for counter=1:2;
if counter==1
set(a1, 'Position', unitsPerInches); % affect only position of a1
end
subplot(1,2,counter);
imagesc(rand(3));
drawnow
subplot(1,2,counter);
imagesc(rand(3));
drawnow
end
Output: second figure of subplots fails.
System: Linux Ubuntu 16.04 64 bit
Linux kernel 4.6
Matlab: 2016a
Related threads: Matlab7 'bug' when using "subplot" + "imagesc"?
I'm not 100% sure what you're asking, but I think it's about combining multiple imagesc statements while in a loop. I'd do something more direct -- use gca and put the subplot inside the loop. Quite often, if you want to programmatically address multiple images, it makes sense to put them in some sort of structure other than creating lots of differently named variables. Note also that while 1 is probably not really what you want -- it will hammer your graphics device drivers -- and that pause can take an argument to act as a wait function, for some fraction of a second if required.
testImages{1}=double(imread('coins.png'));
testImages{2}=double(imread('cameraman.tif'));
h=figure;
set(h,'color','w'); %This handle refers to the background window
for ix=1:2
subplot(1,2,ix);
imagesc(testImages{ix});
axis equal;
colormap gray;
%Change, for example, axis position
curPoss=get(gca,'Position'); %gca stands for 'get current axis'
set(gca,'Position',curPoss+1e-2*ix^2); %Move one image up a bit
end
Does that help?
If you want to jump between figures, make an array of them, and use it within a loop:
unitsPerInches = [0.1 0.1 0.15 0.15];
figs = [figure(1) figure(2)];
for f = 1:numel(figs)
figure(figs(f));
for counter = 1:2;
subplot(1,2,counter);
imagesc(rand(3));
drawnow
end
figs(f).Children(1).Position = unitsPerInches;
figs(f).Children(2).Position = unitsPerInches+0.3;
end
Your original values for unitsPerInches was wrong, since the 'Position' property of an axes takes values between 0 to 1 by default. You can change this using the 'Units' property, like:
figs(f).Children(1).Units = 'inches';
The output from this example is two figures that looks like this:
Where there is a small axes on the down-left and a big one on the top-right.
So, back to your original questions:
What is imagesc corresponding structure to plot(a1,rand(3))?
Instead of passing the axes to imagesc, set the focus on the relevant figure, and subplot with:
figure(h)
subplot(x,y,c)
imagesc(data)
where h is a handle to the relevant figure, c is the place of the subplot within h where you want to plot the image (a number between 1 to x*y), and after these two line you call imagesc.
How to change 'Position' of figure inside the loop?
In this question it is not clear if you want to change the 'Position' of the figure or the axes, they have different units and meaning, but both are accessible in the same way:
h.Position = [left bottom width height]; % for the position of the figure
h.Children(c).Position = [left bottom width height]; % for the position of the axes
where h is as before, but c may be numbered differently, so subplot(x,y,c) may not refer to the same axes as h.Children(c). However, you can always use gca to get the current axes handle:
ax = gca;
ax.Position = [left bottom width height];
Hope it's all clear now, and if there are further questions, let me know ;)

Separating axes from plot area in MATLAB

I find that data points that lie on or near the axes are difficult to see. The obvious fix, of course, is to simply change the plot area using axis([xmin xmax ymin ymax]), but this is not preferable in all cases; for example, if the x axis is time, then moving the minimum x value to -1 to show activity at 0 does not make sense.
Instead, I was hoping to simply move the x and y axes away from the plot area, like I have done here:
left: MATLAB generated, right: desired (image editing software)
Is there a way to automatically do this in MATLAB? I thought there might be a way to do it by using the outerposition axes property (i.e., set it to [0 0 0.9 0.9] and drawing new axes where they originally were?), but I didn't get anywhere with that strategy.
The answers here already show you most of the way - here is the last step to separate the x and y axle as per the example you put together.
f = figure ( 'color', 'white' );
% create the axes and set some properties
ax = axes ( 'parent', f, 'box', 'off', 'nextplot', 'add', 'XMinorTick', 'on', 'YMinorTick', 'on' );
% plot some data
plot ( ax, 0:10, [0:10].^2, 'rx-' )
% modify the x and y limits to below the data (by a small amount)
ax.XLim(1) = ax.XLim(1)-(ax.XTick(2)-ax.XTick(1))/4;
ax.YLim(1) = ax.YLim(1)-(ax.YTick(2)-ax.YTick(1))/4;
% Set the tick direction
ax.TickDir = 'out';
% draw the plot to generate the undocumented vertex data var
drawnow()
%% R2015a
% X, Y and Z row of the start and end of the individual axle.
ax.XRuler.Axle.VertexData(1,1) = 0;
ax.YRuler.Axle.VertexData(2,1) = 0;
%% R2015b
% extract the x axis vertext data
% X, Y and Z row of the start and end of the individual axle.
vd = get(ax.XAxis.Axle,'VertexData');
% reset the zero value
vd(1,1) = 0;
% Update the vertex data
set(ax.XAxis.Axle,'VertexData',vd);
% repeat for Y (set 2nd row)
vd = get(ax.YAxis.Axle,'VertexData');
vd(2,1) = 0;
set(ax.YAxis.Axle,'VertexData',vd);
Edit: The vertex is something that Matlab recreates whenever the axes/figure changes size or if you zoom or pan for example.
You can try to counteract this (remember you are using undocumented features here) by adding a listener to attempt to capture this. We can use the MarkedClean event which is called quite a lot of times.
addlistener ( ax, 'MarkedClean', #(obj,event)resetVertex(ax) );
Where you resetVertex function is something like: (R2015b shown only)
Edit 2 added the code to turn off the minor ticks below 0.
function resetVertex ( ax )
% extract the x axis vertext data
% X, Y and Z row of the start and end of the individual axle.
ax.XAxis.Axle.VertexData(1,1) = 0;
% repeat for Y (set 2nd row)
ax.YAxis.Axle.VertexData(2,1) = 0;
% You can modify the minor Tick values by modifying the vertex data
% for them, e.g. remove any minor ticks below 0
ax.XAxis.MinorTickChild.VertexData(:,ax.XAxis.MinorTickChild.VertexData(1,:)<0) = [];
ax.YAxis.MinorTickChild.VertexData(:,ax.YAxis.MinorTickChild.VertexData(2,:)<0) = [];
end
Note: this uses undocumented features -> so may only work in certain versions of Matlab (I have added the code for r2015a & r2015b) and Matlab may recreate the vertex data depending on what you do with the plots..
Here is a simple way for achieving that:
% some data:
x = 1:100;
f=#(x) 5.*x;
y=f(x)+rand(1,length(x))*50;
close all
% plotting:
f1 = figure('Color','white');
ax = axes;
plot(ax,x,y,'o');
% 'clean' the data area a little bit:
box off
ax.TickDir = 'out';
% pushing the axis a bit forward:
lims = axis;
pos = ax.Position;
axis([lims(1)-ax.XTick(2)/5 lims(2)+0.1 lims(3)-ax.YTick(2)/5 lims(4)+0.1])
% Create lines
firstXtick = 0.013; %this value need to be adjusted only once per figure
firstYtick = 0.023; %this value need to be adjusted only once per figure
lx = annotation(f1,'line',[pos(1) pos(1)+firstXtick],...
[pos(2) pos(2)],'Color',[1 1 1],'LineWidth',1);
ly = annotation(f1,'line',[pos(1) pos(1)],...
[pos(2) pos(2)+firstYtick],'Color',[1 1 1],'LineWidth',1);
Which yields this figure:
The only thing to adjust here, once per type of figure, is firstXtick and firstYtick values, that have to be fine tuned to the specific axis. After setting them to the correct value the figure can be resized with no problem. Zoom and pan require a little fixes.
You can start your axes from less than zero and then remove the less than zero ticks from your plot. e.g.
plot(0:3:30,0:3:30); %Some random data for plotting
h = gca;
axis([-1 30 -1 30]); %Setting the axis from less than zero
box off; %Removing box
h.TickDir = 'out'; %Setting Direction of ticks to outwards
h.XTickLabel(1)= {' '}; %Removing the first tick of X-axis
h.YTickLabel(1)= {' '}; %Removing the first tick of Y-axis
With this code, you'll get this result:
This may have a drawback, sometimes, that zero ticks may also get removed (as you can see in above figure). This is because the plot had set the first ticks of axes equal to zero. This can be avoided using if condition. So, the code can be modified as below:
plot(0:3:30,0:3:30);
h = gca;
axis([-1 30 -1 30]);
box off;
h.TickDir = 'out';
if str2num(cell2mat(h.XTickLabel(1))) <0
h.XTickLabel(1)= {' '};
end
if str2num(cell2mat(h.YTickLabel(1))) <0
h.YTickLabel(1)= {' '};
end
The above code will yield the following result:-
Also note that, for your case, since your axes ticks are very less, -1 may not be much suitable for the starting value of axes and you may need to use -0.1 instead i.e. axis([-0.1 30 -0.1 30]);
With a slight modification of #matlabgui's answer you can track the (major) tick limits:
ax = gca();
% Set the tick direction
ax.TickDir = 'out';
% Make sure this stays when saving, zooming, etc
addlistener ( ax, 'MarkedClean', #(obj,event) change_ticks(ax) );
% Draw the plot to generate the undocumented vertex data variable
% and call callback for the first time
drawnow();
The callback
function change_ticks( ax )
% Modify ruler
ax.XRuler.Axle.VertexData(1,1) = ax.XTick(1);
ax.XRuler.Axle.VertexData(1,2) = ax.XTick(end);
ax.YRuler.Axle.VertexData(2,1) = ax.YTick(1);
ax.YRuler.Axle.VertexData(2,2) = ax.YTick(end);
end
I haven't test extensively but seems to work for custom ticks too. This nicely cuts the rulers not only on zero but beyond the fist and last tick. This was tested in Matlab 2019a on Windows and ax.XRuler.Axle.VertexData works just fine. Note this is only for major ticks!