I have a scatterplot in Matlab and was wondering if there was any way to the change the color of just one of the points?
you can plot the graph, after that replot the point which you want.
% plot the curve or graph
hold on
plot(x,y,'.r')
Try to hold on and then plot the point (x,y) which you want with the specified color (r) which you are interested in.
If you do not want to overlay a second plot on the first, you can plot each point individually and use handles. In that way, you can later perform arbitrary changes on each individual point.
You can find an example below.
% Generate some numbers
x = randn(10,1);
y = randn(10,1);
% Plot each point individually
figure
hold on
for idx = 1 : numel(x)
hdl(idx) = plot(x(idx),y(idx),'marker','.','color','k')
end
% change color, markerstyle, x-position, etc...
hdl(2).Color = [1 0 0]
hdl(3).Marker = 'o'
hdl(5).XData = 1
x = rand(10,1) ;
y = rand(10,1) ;
scatter(x,y) ;
[x1,y1] = getpts ;
hold on
plot(x1,y1,'Or') ;
click on the point, you want to change color, when prompted.
Related
z is 200*200 array and I have a surf plot using Matlab surf(x,y,z). I am trying to plot the surf plot so that when z<10 it will be blue and when z>10 it will be red. At the moment the surf plot is like this. Can someone please suggest a way to do this in Matlab?
One way to achieve that (there are several ways) is to use a custom colormap:
Build a colormap with only the color you want to appear in your graph, then just adjust the levels so the midpoint is for Z=10.
The first part of the code shows how to create your custom colormap and apply it:
Zt = 10 ; % threshold level for Z
z = peaks+Zt ; % dummy test data
% build a colormap with your 2 custom color
% [%Red %green %blue]
cmap = [0.79 0.22 0.81 ; % some kind of purple
0 0 1 ] ; % pure blue
surf(z) ; % plot the surface
colormap(cmap) ; % apply the custom colormap
hcb = colorbar ;
This produces a surface with your two chosen colors:
But wait! The separation is not exactly at the Z=10 level. No problem, if we adjust the boundaries of the colormap so your threshold level is bang in the middle, Matlab will take care of adjusting the coloring for us:
%% Now center the colormap boundaries around your threshold level
% get the minimum and maximum
zmax = ceil( max(max(z)) ) ;
zmin = floor( min(min(z)) ) ;
span = max( [zmax-Zt, Zt-zmin] ) ; % calculate the span each side of [Zt]
caxis([Zt-span , Zt+span]) ; % center the colormap around [Zt]
The last bit of code above allow to define an equal span around your chosen threshold level and take the content of the Z data into account. If you know in advance the limits of your data you don't need to do the calculations. On the example above I could also have simply use the last line with some hard coded values:
caxis([0 , 20]) ;
As long as the interval you specify for caxis is centered around your threshold level it will work.
Edit:
To control the labels of the colorbar, I usually set the Ticks and TickLabels after the colorbar (or axes) is created. For this you need the handle of the colorbar object.
Note that in the code above I modified the last line of the first code block. I changed colorbar, to hcb=colorbar;. This way we have the handle of the colorbar, which allow us to set any arbitrary tick and associated label.
The most straightforward way to get your result for this specific example is:
hcb.Ticks = [ 5 , 10 , 15 ] ;
hcb.TickLabels = {'<10','10','>10'} ;
However if you want a more generic solution which can work with any threshold Zt then you can use:
%% adjust colorbar labels
zl = caxis ; % get the limits of the color scale
Zstr = num2str(Zt) ; % get a string representing the threshold
hcb.Ticks = [ (Zt+zl(1))/2 , Zt , (zl(2)+Zt)/2 ] ;
hcb.TickLabels = { ['<' Zstr] , Zstr , ['>' Zstr] } ;
For your example, both options produce:
Adapted from MATLAB Answers
z = peaks+10; % sample data generated between 3.4 and 18.1
% Make colors be red above 10, and blue below 10.
redChannel = z > 10;
greenChannel = 0*z;
blueChannel = z < 10;
% Make the RGB image.
colors = double(cat(3, redChannel, greenChannel, blueChannel));
% Plot the surface with those colors.
surf(z, colors);
try this
surf(x,y,z)
map = [0.0 0.0 1.0
1.0 0.0 0.0];
colormap(map);
caxis([0 20]);
Question
When using polarhistogram(theta) to plot a dataset containing azimuths from 0-360 degrees. Is it possible to specify colours for given segments?
Example
In the plot bellow for example would it be possible to specify that all bars between 0 and 90 degrees (and thus 180-270 degrees also) are red? whilst the rest remains blue?
Reference material
I think if it exists it will be within here somewhere but I am unable to figure out which part exactly:
https://www.mathworks.com/help/matlab/ref/polaraxes-properties.html
If you use rose, you can extract the edges of the histogram and plot each bar one by one. It's a bit of a hack but it works, looks pretty and does not require Matlab 2016b.
theta = atan2(rand(1e3,1)-0.5,2*(rand(1e3,1)-0.5));
n = 25;
colours = hsv(n);
figure;
rose(theta,n); cla; % Use this to initialise polar axes
[theta,rho] = rose(theta,n); % Get the histogram edges
theta(end+1) = theta(1); % Wrap around for easy interation
rho(end+1) = rho(1);
hold on;
for j = 1:floor(length(theta)/4)
k = #(j) 4*(j-1)+1; % Change of iterator
h = polar(theta(k(j):k(j)+3),rho(k(j):k(j)+3));
set(h,'color',colours(j,:)); % Set the color
[x,y] = pol2cart(theta(k(j):k(j)+3),rho(k(j):k(j)+3));
h = patch(x,y,'');
set(h,'FaceColor',colours(j,:),'FaceAlpha',0.2);
uistack(h,'down');
end
grid on; axis equal;
title('Coloured polar histogram')
Result
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!
I have the following image derived from imagesc(some matrix whose entries correspond to those colors). The Cyan and the Yellow both mean different things. I would like to either:
Add a legend where I can fill in what each color means
Segregate parts of the X-axis to where I can type "cyan" on the x region below the cyan part, and "yellow" on the x region below the yellow part.
Either or would be fine, and which ever one is easier would be appropriate for me.
CYAN YELLOW
Do you want something like this? It's very basic haha.
clc
clear
close all
%// Dummy array
A = repmat([0 0 0 1 1 1],6,1);
imagesc(A)
hold on
%// Dummy data to add legend
scatter(0,0,1,'b','filled')
scatter(0,0,1,'r','filled')
axis off
colorbar
%// Get axis coordinates (x first and then y)
ax = axis;
%// Add text. You can easily adjust the x-offset depending on how many colors you have.
text(ax(2)/4+ax(1),ax(4)+.2,'Blue','Color','b','FontSize',20,'HorizontalAlignment','Center')
text(3*ax(2)/4+.2,ax(4)+.2,'Red','Color','r','FontSize',20,'HorizontalAlignment','Center')
%// Add legend
legend({'Blue';'Red'})
Output:
Here's another option, which happens to be matlab-hg2 friendly:
%% // Initialization
clear variables; close all force; clc;
%% // Generate some data
fakeData = magic(3)-0.5;
fakeData_horz = fakeData(:)'; %//'
fakeNames = cellstr(strcat('color',num2str((1:9)'))); %//'
fakeNameMapping = fakeNames(randperm(numel(fakeData)));
%% // Create figure
hFig = figure('Position',[680,488,758,610],'Resize','off');
%% // Top left example
cLims = [0 numel(fakeData)+1];
hSp = subplot(2,2,1);
imagesc(fakeData); axis image; set(hSp,'XTick',[],'YTick',[]);
colorbar; caxis(cLims);
[XX,YY] = meshgrid(1:size(fakeData,1),1:size(fakeData,2));
text(XX(:),YY(:),fakeNameMapping,'HorizontalAlignment','center');
%% // Bottom example
hSp = subplot(2,2,3:4);
cLims = [0 numel(fakeData)+1]; %Not required here since unchanged
imagesc(fakeData_horz); axis image; set(hSp,'XTick',[],'YTick',[]);
colorbar; caxis(cLims);
drawnow; %// This command will allow the annotations to be positioned properly
for ind1=1:numel(fakeData_horz)
newPos = [hSp.Position(1)+hSp.Position(3)/numel(fakeData_horz) * (ind1-1),...
hSp.Position(2)*1.6,... %1.6 is chosen for the demo
hSp.Position(3)/numel(fakeData_horz),...
0.05]; % 0.05 is chosen for the demo; play around with it
h= annotation('textbox',newPos,'String',fakeNameMapping{ind1},...
'LineStyle','none','HorizontalAlignment','center');
end
%% // Top right example
hSp = subplot(2,2,2);
cLims = [0 numel(fakeData)]; %// cLims is a bit different here!
imagesc(fakeData); axis image; set(hSp,'XTick',[],'YTick',[]);
caxis(hSp,cLims); colormap(hSp,parula(numel(fakeData)));
cb = colorbar; %// This time we need a handle to the colorbar
cb.Ticks = (hSp.CLim(1):hSp.CLim(2))+0.5; %// Set the tick positions
cb.TickLabels = fakeNames; %// Set the tick strings
Which results in:
Note: unless using a more intelligent text positioning computation, the figure's size should not be changed after it was plotted (in the 2nd example), because then the text no longer remains where it should be.
Edit: added another option where only the colorbar is labeled.
I am trying to make a plot with an intensity that varies over time:
[X,Y] = meshgrid(-30:.1:30);
figure;
colormap(bone);
for t = 0:0.1:2*pi
R = sqrt(X.^2 + Y.^2);
Z = cos(t)*abs(besselj(2,R));
surf(Z,'EdgeColor','None');
view(90,90);
axis([0 600 0 600 -0.5 0.5])
pause(0.1);
end
I want to look at this from the top, such that as the Z value changes, the color changes. The problem is that rather than having an absolute scale (black = -0.5, white = 0.5), the color scale is relative to the maximum and minimum values, such that the colors only change when the sign flips change. How can I set an absolute scale for the color map?
Thank you.
You have to use scaled colour mapping mode and set the limits of the scaling by using the caxis command.
Now the problem with your current code is that you call surf at each iteration of the loop, essentially destroying the current plot and generating a new plot each time. This will reset a lot of properties, including the caxis limits to auto. To overcome that, simply create your plot only once before the loop, then in the loop you only change the properties which are modified (the Z values in this case). This way everything else stays the same in the figure.
So you code becomes:
%% // Prepare and initialize the surface plot
[X,Y] = meshgrid(-30:.1:30);
R = sqrt(X.^2 + Y.^2) ; %// this doesn't need to be in the loop
Z = cos(0)*abs(besselj(2,R)) ; %// calculate initial value to create the surface
surfHandle = surf( Z , 'EdgeColor','None' ) ; %// create a first surface, and save the handle to the surface object
colormap(bone);
colorbar %// this is optional, just to make sure the colorbar does not vary
caxis([-5 5 ] ) ; %// this is what sets the color scaling to what you want
view(90,90);
axis([0 600 0 600 -0.5 0.5]) ; %// this doesn't need to be in the loop anymore
%% // Modify and update the surface plot
for t = 0:pi/100:2*pi
Z = cos(t)*abs(besselj(2,R));
set( surfHandle , 'ZData' , Z )
drawnow
pause(0.01);
end
Read coloring-mesh-and-surface-plots for more info on how surfaces can be colored.
If you just want white for values less than 0 and black for values greater than 0, you ca simply do:
surf(Z,sign(Z),'EdgeColor','None');
which uses the optional C argument to surf, telling Matlab to colour the plot depending on the values of C, not Z. sign(Z) is a matrix that has 1's where Z>0, 0's where Z=0, and -1's where Z<0.