Plotting several images in the same plot - matlab

I'm trying to plot small images on a larger plot... Actually its isomap algorithm, I got many points, now each point correspond to some image, I know which image is it... The porblem is how to load that image and plot on the graph?
One more thing I have to plot both image and the points, so, basically the images will overlap the points.
Certainly, the type of image given here

Something like this should get you started. You can use the low-level version of the image function to draw onto a set of axes.
% Define some random data
N = 5;
x = rand(N, 1);
y = rand(N, 1);
% Load an image
rgb = imread('ngc6543a.jpg');
% Draw a scatter plot
scatter(x, y);
axis([0 1 0 1]);
% Offsets of image from associated point
dx = 0.02;
dy = 0.02;
width = 0.1;
height = size(rgb, 1) / size(rgb, 2) * width;
for i = 1:N
image('CData', rgb,...
'XData', [x(i)-dx x(i)-(dx+width)],...
'YData', [y(i)-dy y(i)-(dy+height)]);
end

Related

Fancy Correlation Plots in MATLAB

I'm trying to find a way to generate these pretty correlation plots in MATLAB. These are generated in R using 'corrplot' function, but couldn't find any similar code in MATLAB. Any help would be appreciated.
As a quick description, this function will create a color scale of the correlation values, and create circles in each cell of the correlation matrix/plot with the associated color. The size of the circles is also an indicator of the magnitude of the correlation, with larger circles representing a stronger relationship (positive or negative). More details could be found here.
you can use plot-corrmat (or modify it, depending how articulate you are in matlab), to obtain similar visualizations of correlation matrices (top pic). Or use Correlation circles , that looks somewhat similar as well (bottom pic)...
https://github.com/elayden/plot-corrmat
I could write the below code to generate a similar graph, based on the code provided here
% Produce the input lower triangular matrix data
C = -1 + 2.*rand(12,12);
C = tril(C,-1);
C(logical(eye(size(C)))) = 1;
% Set [min,max] value of C to scale colors
clrLim = [-1,1];
% load('CorrColormap.mat') % Uncomment for custom CorrColormap
% Set the [min,max] of diameter where 1 consumes entire grid square
diamLim = [0.1, 1];
myLabel = {'ICA','Elev','Pr','Rmax','Rmin','Srad','Wspd','Tmin','Tmax','VPD','ET_o','AW'};
% Compute center of each circle
% This assumes the x and y values were not entered in imagesc()
x = 1 : 1 : size(C,2); % x edges
y = 1 : 1 : size(C,1); % y edges
[xAll, yAll] = meshgrid(x,y);
xAll(C==0)=nan; % eliminate cordinates for zero correlations
% Set color of each rectangle
% Set color scale
cmap = jet(256);
% cmap = CorrColormap; % Uncomment for CorrColormap
Cscaled = (C - clrLim(1))/range(clrLim); % always [0:1]
colIdx = discretize(Cscaled,linspace(0,1,size(cmap,1)));
% Set size of each circle
% Scale the size between [0 1]
Cscaled = (abs(C) - 0)/1;
diamSize = Cscaled * range(diamLim) + diamLim(1);
% Create figure
fh = figure();
ax = axes(fh);
hold(ax,'on')
colormap(ax,'jet');
% colormap(CorrColormap) %Uncomment for CorrColormap
tickvalues = 1:length(C);
x = zeros(size(tickvalues));
text(x, tickvalues, myLabel, 'HorizontalAlignment', 'right');
x(:) = length(C)+1;
text(tickvalues, x, myLabel, 'HorizontalAlignment', 'right','Rotation',90);
% Create circles
theta = linspace(0,2*pi,50); % the smaller, the less memory req'd.
h = arrayfun(#(i)fill(diamSize(i)/2 * cos(theta) + xAll(i), ...
diamSize(i)/2 * sin(theta) + yAll(i), cmap(colIdx(i),:),'LineStyle','none'),1:numel(xAll));
axis(ax,'equal')
axis(ax,'tight')
set(ax,'YDir','Reverse')
colorbar()
caxis(clrLim);
axis off
The exact graph is available here:
Fancy Correlation Plots in MATLAB

Gradient fill of a function inside a circular area Matlab

I'm trying to create a gradient fill inside a circular area according to a given function. I hope the plot below explains it at best
I'm not sure how to approach this, as in the simulation I'm working on the direction of the gradient changes (not always in the x direction as below, but free to be along all the defined angles), so I'm looking for a solution that will be flexible in that manner as well.
The code I have is below
clear t
N=10;
for i=0:N
t(i+1) = 0+(2*i*pi) / N;
end
F = exp(-cos(t))./(2.*pi*besseli(1,1));
figure(1)
subplot(1,3,1)
plot(t*180/pi,F,'-ob')
xlim([0 360])
xlabel('angle')
subplot(1,3,2)
hold on
plot(cos([t 2*pi]), sin([t 2*pi]),'-k','linewidth',2);
plot(cos([t 2*pi]), sin([t 2*pi]),'ob');
plot(cos(t).*F,sin(t).*F,'b','linewidth',2);
subplot(1,3,3)
hold on
plot(cos([t 2*pi]), sin([t 2*pi]),'-k','linewidth',2);
plot(cos([t 2*pi]), sin([t 2*pi]),'ob');
To fill surface, you need to use the patch command.
t = linspace(0, 2*pi, 100);
x = cos(t);
y = sin(t);
c = x; % colored following x value and current colormap
figure
patch(x,y,c)
hold on
scatter(x,y)
hold off
colorbar
Resulting graph:
Colors are defined in c per point, and are interpolated inside the shape, so I'm sure that you should have all freedom to color as you want!
For example, the rotated version:
t = linspace(0, 2*pi, 100);
x = cos(t);
y = sin(t);
c = cos(t+pi/4)
figure
patch(x,y,c)
colorbar
To understand how it is going on, just think that every point has a color, and matlab interpolate inside. So here I just rotated the intensity per point by pi /4.
For this to work you need to have a filled shape, and you may need to customize the color (c) parameter so that it matches your need. For example, if your gradient direction is encoded in a vector, you want to project all your point onto that vector to get the value along the gradient for all points.
For example:
% v controls the direction of the gradient
v = [0.1, 1];
t = linspace(0, 2*pi, 100);
F = exp(-cos(t))./(2.*pi*besseli(1,1));
% reconstructing point coordinate all around the surface
% this closes the path so with enough points so that interpolation works correctly
pts = [[t', F']; [t(end:-1:1)', ones(size(t'))*min(F)]];
% projecting all points on the vector to get the color
c = pts * (v');
clf
patch(pts(:,1),pts(:,2),c)
hold on
scatter(t, F)
hold off

Replace quiver arrowheads with images

I have a circular lattice and on the lattice sites I plot normalized arrows that remain in the same magnitude and change direction according to a simulation, the details of which don't matter.
My plots look like this
Is it possible to replace the arrow in the quiver plot by an jpg/bmp/gif/png image? or by any other command?
Ideally, it would look something like this (although not necessarily arrows)
Explanation
One way that you can do this, would be to use a surface object with a texture-map as the FaceColor.
In MATLAB, you can create a simple rectangular surface. You can set the FaceColor to be texturemap which will cause the value assigned to CData to be mapped across the surface.
Then to get transparency, you can also set the FaceAlpha value to be texturemap and set the AlphaData and those transparency values will be mapped across the extent of the surface as well.
For this to be applied to your case, you want to set the CData to the image that you want to use to replace your arrows. And you will want the AlphaData to be the same size as your image data with values of 1 where you want it to be opaque and 0 where you want it to be transparent. This will allow it to not look like the image that you have posted where you can clearly see the bounding box. Then you will need to draw one of these surfaces where each of the arrows would go and scale/position it appropriately.
Implementation
Update: A more polished version of this code (ImageQuiver) is now available on Github as well as the MATLAB File Exchange.
As a demonstration of what I'm talking about, I have created the following function which essentially does just this. It accepts the same inputs as quiver (with the image data being supplied first and an optional AlphaData parameter at the end) and creates a surface at all of the requested coordinates pointing in the requested direction, and scaled by the specified amount.
function h = quiverpic(im, X, Y, dX, dY, scale, alpha)
% im - RGB or indexed image
% X - X positions
% Y - Y positions
% dX - X direction vector
% dY - Y direction vector
% scale - Any scaling (Default = 1)
% alpha - Transparency (same size as im), if not specified = ~isnan(im)
h = hggroup();
if ~exist('scale', 'var')
% By default there is no scaling
scale = 1;
end
if ~exist('alpha', 'var')
% By default, any NaN will be transparent
alpha = ~isnan(im);
end
% Determine aspect ratio of the source image
width_to_height = size(im, 2) / size(im, 1);
for k = 1:numel(X)
% Determine angle from displacement vectors
theta = atan2(dY(k), dX(k));
% Subtract pi/2 to +y is considered "up"
theta = theta + pi/2;
% Setup surface plot boundary
[xx,yy] = meshgrid([-0.5, 0.5] * width_to_height, [0 1]);
% Scale depending on magnitude of dX and dY
this_scale = scale * sqrt(dX(k).^2 + dY(k).^2);
% Scale X and Y components prior to rotating
xx = xx .* this_scale;
yy = yy .* this_scale;
% Rotate to align with the desired direction
xdata = xx .* cos(theta) - yy .* sin(theta);
ydata = xx .* sin(theta) + yy .* cos(theta);
% Determine what is considered the "anchor" of the graphic.
% For now this is assumed to be the "bottom-middle"
xoffset = X(k) - mean(xdata(2,:));
yoffset = Y(k) - mean(ydata(2,:));
% Actually plot the surface.
surf(xdata + xoffset, ...
ydata + yoffset, zeros(2), ...
'Parent', h, ...
'FaceColor', 'texture', ...
'EdgeColor', 'none', ...
'CData', im, ...
'FaceAlpha', 'texture', ...
'AlphaData', double(alpha));
end
end
Example
I wrote a little test script to show how this can be used and to show the results.
t = linspace(0, 2*pi, 13);
dX = cos(t(1:end-1));
dY = sin(t(1:end-1));
X = (3 * dX) + 5;
Y = (3 * dY) + 5;
scale = 1;
% Load the MATLAB logo as an example image
png = fullfile(matlabroot,'/toolbox/matlab/icons/matlabicon.gif');
[im, map] = imread(png);
im = ind2rgb(im, map);
% Determine alpha channel based on upper left hand corner pixel
flatim = reshape(im, [], 3);
alpha = ~ismember(flatim, squeeze(im(1,1,:)).', 'rows');
alpha = reshape(alpha, size(im(:,:,1)));
% Plot some things prior to creating the quiverpic object
fig = figure();
hax = axes('Parent', fig);
axis(hax, 'equal');
% Plot a full circle
t = linspace(0, 2*pi, 100);
plot((cos(t) * 3) + 5, (sin(t) * 3) + 5, '-')
hold(hax, 'on')
% Plot markers at all the quiver centers
plot(X, Y, 'o', 'MarkerFaceColor', 'w')
% Plot a random image behind everything to demonstrate transparency
him = imagesc(rand(9));
uistack(him, 'bottom')
axis(hax, 'equal')
colormap(fig, 'gray')
set(hax, 'clim', [-4 4]);
% Now plot the quiverpic
h = quiverpic(im, X, Y, dX, dY, 1, alpha);
axis(hax, 'tight')
Results
Absurdity
Same image with varying vectors and scaling
Any image of any aspect ratio will work just fine

How can i render lineseries/contour/etc objects to array of pixel data?

I have an array of pixel data frames for use with VideoWriter. I want to overlay lineseries/contour objects into each frame. I don't want to make the movie by iteratively drawing each frame to a figure and capturing it with getframe, because that gives poor resolution and is slow. I tried using getframe on a plot of just the contour, but that returns images scaled to the wrong size with weird margins, especially when using 'axis equal,' which I need.
Updated to accommodate feedback from OP
Getting the contour data as pixel data is not trivial (if possible at all) since using getframe doesn't yield predictable results
What we can do is to extract the contour data and then overlay it on the pixel data frames, forcing them to be to the same scale and then do a getframe on the resultant merged image. This will at least ensure that they two data sets area aligned.
The following code shows the principle though you'd need to modify it for your own needs:
%% Generate some random contours to use
x = linspace(-2*pi,2*pi);
y = linspace(0,4*pi);
[X,Y] = meshgrid(x,y);
Z = sin(X)+cos(Y);
[~,h] = contour(X,Y,Z);
This yields the following contours
Now we get the handles of the children of this image. These will all be 'patch' type objects
patches = get(h,'Children');
Also get the axis limits for the contours
lims = axis;
Next, create a new figure and render the pixel frame data into it
In this example I'm just loading an image but you get the idea.
%% Render frame data
figure
i = imread( some_image_file_png );
This image is actually 194 x 259 x 3. I can display it and rescale the X and Y axes using
%% Set image axes
image(flipdim(i,1),'XData',[lims(1) lims(2)],'YData',[lims(4) lims(3)]);
Note the use of flipdim() to vertically flip the image since the image Y-axis runs in the opposite sense to the contour Y axis. This gives me:
Now I can plot the contours (patches) form the contour plot over the top of the image in the same coordinate space
%% Plot patches
for p =1:length(patches)
xd = get( patches(p), 'XData' );
yd = get( patches(p), 'YData' );
% This causes all contours to be rendered in white. You may
% want to play with this a little
cd = zeros(size(xd));
patch( xd, yd, cd, 'EdgeColor', 'w');
end
This yields
You can now use getframe to extract the frame. If it's important to have coloured contours, you will need to extract colour data from the original contour map and use it to apply an appropriate colouring in the overlaid image.
As a short cut, it's also possible to compile all patch data into a single MxN matrix and render with a single call to patch but I wrote it this way to demonstrate the process.
Well, here's a Bresenham-esque solution based on the ContourMatrix. Not ideal cuz doesn't handle line width, antialiasing, or any more than a single color. But it's pretty efficient (not quite Bham efficient).
function renderContour
clc
close all
x = randn(100,70);
[c,h] = contour(x,[0 0],'LineColor','r');
axis equal
if ~isnumeric(h.LineColor)
error('not handled')
end
cs = nan(size(c,2),4);
k = 0;
ci = 1;
for i = 1:size(c,2)
if k <= 0
k = c(2,i);
else
if k > 1
cs(ci,:) = reshape(c(:,i+[0 1]),[1 4]);
ci = ci + 1;
end
k = k - 1;
end
end
pix = renderLines(cs(1:ci-1,:),[1 1;fliplr(size(x))],10,h.LineColor);
figure
image(pix)
axis equal
end
function out = renderLines(cs,rect,res,color)
% cs = [x1(:) y1(:) x2(:) y2(:)]
% rect = [x(1) y(1);x(2) y(2)]
% doesnt handle line width, antialiasing, etc
% could do those with imdilate, imfilter, etc.
test = false;
if test
if false
cs = [0 0 5 5; 0 5 2.5 2.5];
rect = [0 0; 10 10];
else
cs = 100 * randn(1000,4);
rect = 200 * randn(2);
end
res = 10;
color = [1 .5 0];
end
out = nan(abs(res * round(diff(fliplr(rect)))));
cs = cs - repmat(min(rect),[size(cs,1) 2]);
d = [cs(:,1) - cs(:,3) cs(:,2) - cs(:,4)];
lens = sqrt(sum(d.^2,2));
for i = 1:size(cs,1)
n = ceil(sqrt(2) * res * lens(i));
if false % equivalent but probably less efficient
pts = linspace(0,1,n);
pts = round(res * (repmat(cs(i,1:2),[length(pts) 1]) - pts' * d(i,:)));
else
pts = round(res * [linspace(cs(i,1),cs(i,3),n);linspace(cs(i,2),cs(i,4),n)]');
end
pts = pts(all(pts > 0 & pts <= repmat(fliplr(size(out)),[size(pts,1) 1]),2),:);
out(sub2ind(size(out),pts(:,2),pts(:,1))) = 1;
end
out = repmat(flipud(out),[1 1 3]) .* repmat(permute(color,[3 1 2]),size(out));
if test
image(out)
axis equal
end
end

how to produce this particular 3D graph from scalar data in Matlab?

I am trying to produce this graph using Matlab. The built-in ellipsoid function is confusing. For this problem I have two variables ( width and length ) and a constant height.
to make it very simple I want to show that the width is changing while we approach the tip but height is constant. w,x,h are the variables shown in the graph.
I would really appreciate it if someone can help.
The following code gets you a long way, I think. See example output:
I added enought comments that you should be able to take it from here...
% plot ellipsoid in 3D
% height and width of ellipsoid:
e_h = 10;
e_w = 3;
% position where the "quivers" (arrows) go:
q_offset = 2; % distance from axis
q_scale = 0.5; % multiplier to give parabola some size
q_spacing = 0.5; % distance between arrows
q_height = 2.5; % height above XY plane where arrows are drawn
N = 1000; % number of points for drawing
theta = linspace(0, 2*pi, N); % parameter to help drawing ellipse
zerov = zeros(1, N); % array of zeros that I will need
% coordinates of main ellipse:
x = e_w * sin(theta);
y = zeros(size(x));
z = e_h * cos(theta);
% plot main ellipse:
figure;
plot3(x, y, z)
% secondary plot
y2 = q_scale*(e_w.^2 - x.^2) + 2; % offset parabola - what your plot looked like...
hold on
plot3(x, y2, zerov+q_height); % plotting the parabola in the XY plane at height
axis equal % make the plot dimensions isotropic
% add quivers
q_base = -e_w:q_spacing:e_w; % x coordinate; y and z are fixed
q_length = (e_w.^2 - q_base.^2)*q_scale; % length of quiver - just an equation I chose
q0 = zeros(size(q_base)); % another vector I will need multiple times
q1 = ones(size(q_base)); % ditto
% plot the arrows: the "-1" argument means "don't scale"
quiver3(q_base, q0+q_offset, q_height*q1, q0, q_length, q0, -1)