MATLAB: scatter plot from where each point has its own color [duplicate] - matlab

This question already has answers here:
3D scatter plot with 4D data
(2 answers)
Closed 6 years ago.
Suppose I have a situation as follows:
clc; clear;
n = 1001;
m = 1000;
X = linspace(0,1,n);
Y = linspace(0,1,n);
randcolor = rand(m,3);
colorcode = randi(m,m,m);
For i = 1, ..., n and j = 1, ...,n, I would like to plot the points (X(i),Y(j))'s where the RBG color for (X(i),Y(j)) is randcolor(colorcode(i,j),:). I tried to do this the silly way: first declare
figure; hold on;
then do 2 nested loops, n steps each, and use plot to plot a single point n x n times:
for i = 1:n
for j = 1:n
plot(X(i),Y(j),'Marker','o',...
'MarkerEdgeColor',randcolor(colorcode(i,j),:),...
'MarkerFaceColor',randcolor(colorcode(i,j),:));
end
end
This technically worked but it was slow and MATLAB ate up all of my memory when n was increased. What's a better way to do this please?
p.s. In my actual problem, colorcode isn't actually randomly assigned. Rather, it's assigned based on some divergence criterion for a filled Julia set.

You want to use scatter instead of plot which allows you to specify the size and color of each point individually.
colors = rand(numel(X), 3);
S = scatter(X, Y, 100, colors);

Related

ploting a function under condition with Matlab [duplicate]

This question already has an answer here:
Multiple colors in the same line
(1 answer)
Closed 4 years ago.
I am looking for a solution to this problem:
consider a function f (x) = 2x + 1, with x belonging to [0, 1000]. Draw the representative curve of f as a function of x, so that if ||f (x)|| <3 the representative curve of f is in red color and else represent the curve of f in blue color.
Help me because I am a new user of Matlab software
The code below should do the trick:
% Obtain an array with the desired values
y = myfunc(x);
% Get a list of indices to refer to values of y
% meeting your criteria (there are alternative ways
% to do it
indInAbs = find((abs(y)<3));
indOutAbs = find((abs(y)>=3));
% Create two arrays with y-values
% within the desired range
yInAbs = y(indInAbs);
xInAbs = x(indInAbs);
% Create two arrays with y-values
% outside the desired range
yOutAbs = y(indOutAbs);
xOutAbs = x(indOutAbs);
% Plot the values
figure(1);
hold on;
plot( xInAbs, yInAbs, 'r')
plot( xOutAbs, yOutAbs, 'b')
legend('in abs', 'out abs', 'location', 'best')
There are alternative ways to do it which could be more efficient and elegant. However, this is a quick and dirty solution.
Your threshold cannot be too low, otherwise it has not enough data to plot (if threshold=3) or cannot see the blue part. Here I use 500 such that you can see.
function plotSeparate
clc
close all
k=0
threshold=500
for x=1:0.5:1000
k=k+1
y=f(x)
if abs(y)<threshold
t(k,:)=[x,y];
else
s(k,:)=[x,y];
end
end
plot(s(:,1),s(:,2),'-r',t(:,1),t(:,2),'-b')
end
function y=f(x)
y=2*x+1;
end

Ploting a wave with different colors in the same figure [duplicate]

This question already has an answer here:
Plotting piecewise function
(1 answer)
Closed 5 years ago.
How can I plot a wave (represented by 1 x N matrix) with different colors in matlab. The range for a specific color can be provided manually.
See the diagram below for the expected output.
Here is a simple option:
x = linspace(-4*pi,4*pi,10000); % some data
y = -sin(x); % some data
N = 4;
py = reshape(y,[],N);
px = reshape(x,[],N);
plot(px,py,'LineWidth',2)
Where y is your vector, and N is the number of pieces you want to distinguish. Note that you have to make sure that y is dividable by N with no remainder.
If you want to set the colors, you can do this with set command:
p = plot(px,py,'LineWidth',2)
cmap = parula(N); % a set of N colors in RGB matrix
set(p,{'color'},mat2cell(cmap,ones(N,1),3))
and you get:
That figure looks like a sine function, so let's just assume that it is for this example. While I don't have MATLAB in front of me right now, what I would probably do is, in an m-file script:
clear all; clc;
functionToPlot = [sin(0 : (pi/2) : (8*pi))]; %This spacing will look very sharp and pointy, so I'd recommend using >>linspace like shown in other answers.
yAxisVector = [-1 : 1 : 1];
for n = 1 : length(functionToPlot)
if rem(functionToPlot(1,n),2) <= pi
plot(functionToPlot(1,n),yAxisVector,'r')
hold on
elseif rem(functionToPlot(1,n),4) <= pi
plot(functionToPlot(1,n),yAxisVector,'g')
hold on
elseif rem(functionToPlot(1,n),6) <= pi
plot(functionToPlot(1,n),yAxisVector,'y')
hold on
elseif rem(functionToPlot(1,n),8) <= pi
plot(functionToPlot(1,n),yAxisVector,'c')
hold on
end
end
This code should give you the function that you pictured in your question. Have you tested a code yet? What code did you test? This link shows an alternative method using RGB values, if you prefer that. Good luck with your project!

how to plot each profile with a distance from the other in a 2D plot?

I want to plot something like this http://www.nature.com/nprot/journal/v9/n6/fig_tab/nprot.2014.090_F7.html or like this one http://file.scirp.org/Html/11-2200285/ff6819f9-5db9-4121-852d-a8d5c302a5a4.jpg I have a 2D matrix.
I tried to plot it like this but did not work
figure;
hold on
for i = 1:size(X,1)
plot(X(i,:)+10)
end
Since you do not specify what exactly does not work, I am having some difficulties to answer your question directly (I do not have enough reputation for a comment).
The following code results in an image like the ones you link. Maybe you forgot to multiply the y-shift with the iteration number i.
N = 200;
x = 1:N;
M = 5;
X = sin(kron(x,ones(M,1)));
figure; hold all;
for i=1:N
plot(X(i,:)+i*5);
end

matlab plotting a family of functions

Generate a plot showing the graphs of
y=(2*a+1)*exp(-x)-(a+1)*exp(2*x)
in the range x ∈ <-2, 4> for all integer values of a between -3 and 3
I know how to make typical plot for 2 values and set a range on the axes, but how to draw the graph dependent on the parameter a?
To elaborate on Ben Voigt's comment: A more advanced technique would be to replace the for-loop with a call to bsxfun to generate a matrix of evaluations of M(i,j) = f(x(i),a(j)) and call plot with this matrix. Matlab will then use the columns of the matrix and plot each column with individual colors.
%%// Create a function handle of your function
f = #(x,a) (2*a+1)*exp(-x)-(a+1)*exp(2*x);
%%// Plot the data
x = linspace(-2, 4);
as = -3:3;
plot(x, bsxfun(f,x(:),as));
%%// Add a legend
legendTexts = arrayfun(#(a) sprintf('a == %d', a), as, 'uni', 0);
legend(legendTexts, 'Location', 'best');
You could also create the evaluation matrix using ndgrid, which explicitly returns all combinations of the values of x and as. Here you have to pay closer attention on properly vectorizing the code. (We were lucky that the bsxfun approach worked without having to change the original f.)
f = #(x,a) (2*a+1).*exp(-x)-(a+1).*exp(2*x); %// Note the added dots.
[X,As] = ndgrid(x,as);
plot(x, f(X,As))
However for starters, you should get familiar with loops.
You can do it using a simple for loop as follows. You basically loop through each value of a and plot the corresponding y function.
clear
clc
close all
x = -2:4;
%// Define a
a = -3:3;
%// Counter for legend
p = 1;
LegendText = cell(1,numel(a));
figure;
hold on %// Important to keep all the lines on the same plot.
for k = a
CurrColor = rand(1,3);
y= (2*k+1).*exp(-x)-(k+1).*exp(2.*x);
plot(x,y,'Color',CurrColor);
%// Text for legend
LegendText{p} = sprintf('a equals %d',k);
p = p+1;
end
legend(LegendText,'Location','best')
Which gives something like this:
You can customize the graph as you like. Hope that helps get you started!

How to fit a curve by a series of segmented lines in Matlab?

I have a simple loglog curve as above. Is there some function in Matlab which can fit this curve by segmented lines and show the starting and end points of these line segments ? I have checked the curve fitting toolbox in matlab. They seems to do curve fitting by either one line or some functions. I do not want to curve fitting by one line only.
If there is no direct function, any alternative to achieve the same goal is fine with me. My goal is to fit the curve by segmented lines and get locations of the end points of these segments .
First of all, your problem is not called curve fitting. Curve fitting is when you have data, and you find the best function that describes it, in some sense. You, on the other hand, want to create a piecewise linear approximation of your function.
I suggest the following strategy:
Split manually into sections. The section size should depend on the derivative, large derivative -> small section
Sample the function at the nodes between the sections
Find a linear interpolation that passes through the points mentioned above.
Here is an example of a code that does that. You can see that the red line (interpolation) is very close to the original function, despite the small amount of sections. This happens due to the adaptive section size.
function fitLogLog()
x = 2:1000;
y = log(log(x));
%# Find section sizes, by using an inverse of the approximation of the derivative
numOfSections = 20;
indexes = round(linspace(1,numel(y),numOfSections));
derivativeApprox = diff(y(indexes));
inverseDerivative = 1./derivativeApprox;
weightOfSection = inverseDerivative/sum(inverseDerivative);
totalRange = max(x(:))-min(x(:));
sectionSize = weightOfSection.* totalRange;
%# The relevant nodes
xNodes = x(1) + [ 0 cumsum(sectionSize)];
yNodes = log(log(xNodes));
figure;plot(x,y);
hold on;
plot (xNodes,yNodes,'r');
scatter (xNodes,yNodes,'r');
legend('log(log(x))','adaptive linear interpolation');
end
Andrey's adaptive solution provides a more accurate overall fit. If what you want is segments of a fixed length, however, then here is something that should work, using a method that also returns a complete set of all the fitted values. Could be vectorized if speed is needed.
Nsamp = 1000; %number of data samples on x-axis
x = [1:Nsamp]; %this is your x-axis
Nlines = 5; %number of lines to fit
fx = exp(-10*x/Nsamp); %generate something like your current data, f(x)
gx = NaN(size(fx)); %this will hold your fitted lines, g(x)
joins = round(linspace(1, Nsamp, Nlines+1)); %define equally spaced breaks along the x-axis
dx = diff(x(joins)); %x-change
df = diff(fx(joins)); %f(x)-change
m = df./dx; %gradient for each section
for i = 1:Nlines
x1 = joins(i); %start point
x2 = joins(i+1); %end point
gx(x1:x2) = fx(x1) + m(i)*(0:dx(i)); %compute line segment
end
subplot(2,1,1)
h(1,:) = plot(x, fx, 'b', x, gx, 'k', joins, gx(joins), 'ro');
title('Normal Plot')
subplot(2,1,2)
h(2,:) = loglog(x, fx, 'b', x, gx, 'k', joins, gx(joins), 'ro');
title('Log Log Plot')
for ip = 1:2
subplot(2,1,ip)
set(h(ip,:), 'LineWidth', 2)
legend('Data', 'Piecewise Linear', 'Location', 'NorthEastOutside')
legend boxoff
end
This is not an exact answer to this question, but since I arrived here based on a search, I'd like to answer the related question of how to create (not fit) a piecewise linear function that is intended to represent the mean (or median, or some other other function) of interval data in a scatter plot.
First, a related but more sophisticated alternative using regression, which apparently has some MATLAB code listed on the wikipedia page, is Multivariate adaptive regression splines.
The solution here is to just calculate the mean on overlapping intervals to get points
function [x, y] = intervalAggregate(Xdata, Ydata, aggFun, intStep, intOverlap)
% intOverlap in [0, 1); 0 for no overlap of intervals, etc.
% intStep this is the size of the interval being aggregated.
minX = min(Xdata);
maxX = max(Xdata);
minY = min(Ydata);
maxY = max(Ydata);
intInc = intOverlap*intStep; %How far we advance each iteraction.
if intOverlap <= 0
intInc = intStep;
end
nInt = ceil((maxX-minX)/intInc); %Number of aggregations
parfor i = 1:nInt
xStart = minX + (i-1)*intInc;
xEnd = xStart + intStep;
intervalIndices = find((Xdata >= xStart) & (Xdata <= xEnd));
x(i) = aggFun(Xdata(intervalIndices));
y(i) = aggFun(Ydata(intervalIndices));
end
For instance, to calculate the mean over some paired X and Y data I had handy with intervals of length 0.1 having roughly 1/3 overlap with each other (see scatter image):
[x,y] = intervalAggregate(Xdat, Ydat, #mean, 0.1, 0.333)
x =
Columns 1 through 8
0.0552 0.0868 0.1170 0.1475 0.1844 0.2173 0.2498 0.2834
Columns 9 through 15
0.3182 0.3561 0.3875 0.4178 0.4494 0.4671 0.4822
y =
Columns 1 through 8
0.9992 0.9983 0.9971 0.9955 0.9927 0.9905 0.9876 0.9846
Columns 9 through 15
0.9803 0.9750 0.9707 0.9653 0.9598 0.9560 0.9537
We see that as x increases, y tends to decrease slightly. From there, it is easy enough to draw line segments and/or perform some other kind of smoothing.
(Note that I did not attempt to vectorize this solution; a much faster version could be assumed if Xdata is sorted.)