I am creating a 2D plot in Matlab by calling this command: imagesc(vector1, vector2, mat_weights). Then, I run the colorbar command.
I now have a smooth 2D plot, but I want to add space between the cells. Here's how I want it to look:
How do I add such spacing between the cells/boxes?
You can add spaces between patches of color using another function than imagesc. Here, scatter provides a straightforward solution when used with option 'filled' and marker 'square'.
Note that you need to transform your 2-D matrix into a vector, but you don't have to scale your data: scatter takes the min and max values from your data and assign them to the min and max colors of the colormap.
The code
% 2-D in 1-D:
Z = diag(1:10); %example of 2-D matrix to be plotted
C = reshape(Z,1,[]); %1-D transform for vector color
% input definition
sz_matrix = 10;
X = repmat( (1:sz_matrix), 1, sz_matrix);
Y = kron(1:sz_matrix,ones(1,sz_matrix));
S = 1000; % size of marker (handle spaces between patches)
%C = (X.^2 + Y.^2); % second color scheme
%plot
figure('Color', 'w', 'position', [10 10 600 400]);
scatter(X, Y, S, C, 'fill', 's');
set(gca, 'XLim', [0 11], 'YLim', [0 11]);
axis square;
colormap summer
colorbar
will give
EDIT
Here is a piece of code for a rectangular matrix. Please note the inversion of the Y axis direction so that the graphical representation matches disp(Z). To have similar (x,y) proportion in the white area separating color patches, one may try to resize manually the figure.
Z = diag(1:10); %example of 2-D matrix to be plotted
Z = Z(1:end-2,:); %trim for rectangular
% input definition
X = repmat(1:size(Z,2), 1, size(Z,1));
Y = kron(1:size(Z,1),ones(1,size(Z,2)));
C = reshape(Z',1,[]); %1-D transform for vector color
S = 1000; % size of marker (handle spaces between patches)
%plot
figure('Color', 'w');
scatter(X, Y, S, C, 'fill', 's');
set(gca, 'XLim', [0 size(Z,2)+1], 'YLim', [0 size(Z,1)+1]);
colormap jet
colorbar
set(gca, 'YDir','reverse');
The ouput:
Related
Given a N x N array I want to generate a heat map that visualizes data in such a way:
Given the source image below I created a sparsely populated N X N array that contained the points listed below. 90 points in a 1000x800 array.
When researching online how to generate such a heatmap I stumbled on using colormap only to get disappointing results.
colormap('hot'); % set colormap
imagesc(points); % draw image and scale colormap to values range
colorbar;
I got rather disappointing results.
What other alternatives do I have to make my image above resemble the top one?
There are a few different ways you can convert scattered or sparse matrix data into a heatmap that provides some better visualization of the point density. The examples I'll show here will start with scattered data, so if you already have data in a 2D matrix/histogram you can skip the initial steps...
Histogram:
If your scattered data is rather dense, a simple 2D histogram may be all you need. You can create a grid covering your scattered points (at a resolution of your choosing) and bin your data in the x and y directions using histcounts2:
% Normally distributed sample points:
x = randn(1, 10000);
y = randn(1, 10000);
% Bin the data:
pts = linspace(-4, 4, 101);
N = histcounts2(y(:), x(:), pts, pts);
% Plot scattered data (for comparison):
subplot(1, 2, 1);
scatter(x, y, 'r.');
axis equal;
set(gca, 'XLim', pts([1 end]), 'YLim', pts([1 end]));
% Plot heatmap:
subplot(1, 2, 2);
imagesc(pts, pts, N);
axis equal;
set(gca, 'XLim', pts([1 end]), 'YLim', pts([1 end]), 'YDir', 'normal');
And here's the resulting plot:
Histogram + filtering:
If your scattered data is rather sparse, you can still create a histogram as above, but then filter the result to smooth it out. You could use imdilate if you have the Image Processing Toolbox, or create a filter matrix and use conv2. Here's an example of the latter:
% Normally distributed sample points:
x = randn(1, 100);
y = randn(1, 100);
% Bin the data:
pts = linspace(-3, 3, 101);
N = histcounts2(y(:), x(:), pts, pts);
% Create Gaussian filter matrix:
[xG, yG] = meshgrid(-5:5);
sigma = 2.5;
g = exp(-xG.^2./(2.*sigma.^2)-yG.^2./(2.*sigma.^2));
g = g./sum(g(:));
% Plot scattered data (for comparison):
subplot(1, 2, 1);
scatter(x, y, 'r.');
axis equal;
set(gca, 'XLim', pts([1 end]), 'YLim', pts([1 end]));
% Plot heatmap:
subplot(1, 2, 2);
imagesc(pts, pts, conv2(N, g, 'same'));
axis equal;
set(gca, 'XLim', pts([1 end]), 'YLim', pts([1 end]), 'YDir', 'normal');
And here's the resulting plot:
Distance transform:
Starting with a sparse histogram from above, you could use bwdist from the Image Processing Toolbox to create a distance transform of the data. This would assign each pixel a value based on its distance from the nearest nonzero pixel.
Alternatively, you could avoid computing the 2D histogram by creating a grid covering your scattered points and computing the minimum distance from each grid point to one of your scattered points using pdist2 from the Statistics Toolbox. Here's an example (using the same sample data as above):
% Generate grid and compute minimum distance:
pts = linspace(-3, 3, 101);
[X, Y] = meshgrid(pts);
D = pdist2([x(:) y(:)], [X(:) Y(:)], 'euclidean', 'Smallest', 1);
% Plot scattered data:
subplot(1, 2, 1);
scatter(x, y, 'r.');
axis equal;
set(gca, 'XLim', pts([1 end]), 'YLim', pts([1 end]));
% Plot heatmap:
subplot(1, 2, 2);
imagesc(pts, pts, reshape(D, size(X)));
axis equal;
set(gca, 'XLim', pts([1 end]), 'YLim', pts([1 end]), 'YDir', 'normal');
colormap(flip(parula(), 1));
And here's the resulting plot:
You first need to calculate the density of points on a xy grid. Here you are just plotting an "image version" of any scatter plot in matlab. So, before plotting, you need to process the data and obtaining the density map derived from you points.
You could use for example the ksdensity function, that will estimate the density of points on a grid base. If this function is not available to you, there is a lot of function on the fileexchage that will do the same thing.
% get the x y coordinates of your points
[y,x] = find(points);
P = [x,y];
% estimate and plot the density
[Est,XY] = ksdensity(P);
imagesc(XY(:,1), XY(:,2),Est);
colormap('hot');
colorbar;
I created the following 3d plot in MATLAB using the function plot3:
Now, I want to get a hatched area below the "2d sub-graphs" (i.e. below the blue and red curves). Unfortunately, I don't have any idea how to realize that.
I would appreciate it very much if somebody had an idea.
You can do this using the function fill3 and referencing this answer for the 2D case to see how you have to add points on the ends of your data vectors to "close" your filled polygons. Although creating a pattern (i.e. hatching) is difficult if not impossible, an alternative is to simply adjust the alpha transparency of the filled patch. Here's a simple example for just one patch:
x = 1:10;
y = rand(1, 10);
hFill = fill3(zeros(1, 12), x([1 1:end end]), [0 y 0], 'b', 'FaceAlpha', 0.5);
grid on
And here's the plot this makes:
You can also create multiple patches in one call to fill3. Here's an example with 4 sets of data:
nPoints = 10; % Number of data points
nPlots = 4; % Number of curves
data = rand(nPoints, nPlots); % Sample data, one curve per column
% Create data matrices:
[X, Y] = meshgrid(0:(nPlots-1), [1 1:nPoints nPoints]);
Z = [zeros(1, nPlots); data; zeros(1, nPlots)];
patchColor = [0 0.4470 0.7410]; % RGB color for patch edge and face
% Plot patches:
hFill = fill3(X, Y, Z, patchColor, 'LineWidth', 1, 'EdgeColor', patchColor, ...
'FaceAlpha', 0.5);
set(gca, 'YDir', 'reverse', 'YLim', [1 nPoints]);
grid on
And here's the plot this makes:
I have the following script:
close all; clear all; clc;
x = linspace(-2*pi,2*pi);
y = linspace(0,4*pi);
[X,Y] = meshgrid(x,y);
Z = sin(X)+cos(Y);
values = -10:0.5:10;
figure
[C,hh] = contour(X, Y, Z, values,'r', 'LineWidth',1);
clabel(C, hh, values, 'fontsize',7)
As you can see in the contour lines, all of the lines are plotted with LineWidth = 1. I would like to plot special line for the value = 0, with LineWidth = 2, how to set it? Thanks a lor for your help.
You will need to make a secondary contour plot to highlight the desired contour levels. The MathWorks has an example of this in the documentation.
For your case we'll have something like the following:
% Generate sample data
x = linspace(-2*pi,2*pi);
y = linspace(0,4*pi);
[X,Y] = meshgrid(x,y);
Z = sin(X)+cos(Y);
values = -10:0.5:10;
% Generate initial contour plot
figure
[C,hh] = contour(X, Y, Z, values,'r', 'LineWidth',1);
clabel(C, hh, values, 'fontsize',7)
% Generate second contour plot with desired contour level highlighted
hold on
contour(X, Y, Z, [0 0], 'b', 'LineWidth', 2);
hold off
Which returns the following:
Not that I've specified the single contour level as a vector. This is explained by the documentation for contour:
contour(Z,v) draws a contour plot of matrix Z with contour lines at the data values specified in the monotonically increasing vector v. To display a single contour line at a particular value, define v as a two-element vector with both elements equal to the desired contour level. For example, to draw contour lines at level k, use contour(Z,[k k])
If you want to highlight multiple levels then this does not apply (e.g. contour(X, Y, Z, [-1 0], 'b', 'LineWidth', 2) to highlight -1 and 0)
I have a Matlab data set from an equation z=f(x,y).
So for each set of (x,y) I have a corresponding value of z. Can I plot the data on a x,y plane where at each location the z-value is printed instead of a dot or a colored dot?
figure;
hold on;
scatter(x,y);
ma = cellstr(num2str(z(:)));
text(x, y + <some_offset>, ma, 'FontSize', 10, 'Color', 'r');
I want to put two values on the x-axis and y-axis of a imagesc and surf plot. Both plots plot the same values but the first is 2D and the second 3D.
The arrays that I want to put on the x-axis and y-axis have the same length and are both interesting to display in a single plot because they are related to each other.
So the x-axis and y-axis should look like the example solution in this post (matlab multiple x axis one below another).
In case of a imagesc plot a double x-axis is not that difficult with the code of johan of the example solution and some random data.
Z = rand(20,30);
Y = 32.*(1:size(Z,1));
X = 1:size(Z,2);
scale_factor_xaxis=10;
scale_factor_yaxis=100;
figure(1)
imagesc(X,Y,Z)
set(gca,'XDir','normal','YDir','normal');
title('title')
xlabel('first x label')
ylabel('first y label')
first_axis = gca;
sqzx = 0.15; %// distance to squeeze the first x-axis plot
sqzy = 0.15; %// distance to squeeze the first y-axis plot
set(first_axis, 'Position', get(first_axis, 'Position') + [0 sqzx 0 -sqzx ]);
ax2 = axes('Position', get(first_axis, 'Position') .* [1 1 1 1e-12] - [0 sqzx 0 0],'Color','none');
xlim(get(first_axis, 'XLim') * scale_factor_xaxis);
set(ax2, 'XScale', get(first_axis, 'XScale')); %// make logarithmic if first axis is too
xlabel('second x label')
The next step should be to put also a second scale and label to the y-axis. But I this won't work with the next part of the code:
ax2 = axes('Position', get(first_axis, 'Position') .* [1 1 1 1e-12] - [0 sqzy 0 0],'Color','r');
ylim(get(first_axis, 'YLim') * scale_factor_yaxis);
set(ax2, 'YScale', get(first_axis, 'YScale')); %// make logarithmic if first axis is too
ylabel('second y label')
With this the second y-label is plotted next to the second x-axis and the second y-scale is a x-scale. But I do not understand the code enough to get this the way I describe.