I was wondering if anyone knew how to emulate the ggplot2 default color palette in MATLAB? i.e the one given by scale_color_hue() in ggplot2.
Or equivalently, does anyone know how to pick evenly spaced colors around the HCL color wheel in Matlab?
Some code would be nice. Thank you very much!
Here's a function to get equidistant hsv colours, which is more or less the default scale_colour_hue in ggplot2 for discrete values,
%Color scale in hsv
%
%colorscale(n)
%colorscale(n, 'hue', [min max])
%colorscale(n, 'saturation', saturation)
%colorscale(n, 'value', value)
%
%Input: n
%Optional: hue in [0 1]x[0 1] range (default [0.1 0.9]),
% saturation [0 1] (default 0.5), value in [0 1] (default 0.8)
%
%Output: nx3 rgb matrix
%
%Examples:
% n = 10;
% cols = colorscale(n, 'hue', [0.1 0.8], 'saturation' , 1, 'value', 0.5);
%
%for aa = 1:10;
% plot(1:10, (1:10) + aa, 'Color', cols(aa,:), 'Linewidth',2)
% hold on
%end;
%
% % plot a matrix
% v = transpose(1:10);
% set(gca, 'ColorOrder', colorscale(5));
% set(gca,'NextPlot','replacechildren')
% plot(v, [v, v+1, v+2, v+ 3, v+4, v+5]) ;
%
function cols = colorscale(n, varargin)
p = inputParser;
p.addRequired('n', #isnumeric);
p.addOptional('hue', [0.1 0.9], #(x) length(x) == 2 & min(x) >=0 & max(x) <= 1);
p.addOptional('saturation', 0.5, #(x) length(x) == 1);
p.addOptional('value', 0.8, #(x) length(x) == 1);
p.parse(n, varargin{:});
cols = hsv2rgb([transpose(linspace(p.Results.hue(1), p.Results.hue(2), p.Results.n)), ...
repmat(p.Results.saturation, p.Results.n, 1), repmat(p.Results.value, n,1) ]);
I created a ggplot2-like plotting library for Matlab called gramm, which reproduces many of ggplot2 functionalities, including its Hue-Chroma-Lightness color palette. It's on gitHub/gramm and fileexchange/gramm. You can look inside for how HCL colormaps are created (This part of gramm uses code from the PandA – Perception and Action – toolbox).
I think in general ggplot2 relies heavily on the Brewer Colour Palettes, which should thus have pallettes like the one you are looking for. So maybe just go to the above link and get the RGB values of any set you like (and cite accordingly).
And Matlab should have some way of specifying RGB colours, I'm sure (although I have no clue how to do that - maybe worth a new question on its own?).
Related
I want the color of each arrow in a quiver3 plot from MATLAB to correspond to the magnitude of each arrow. Is there any way to do that?
I saw a few examples online that are able to do this for the 2D quiver, however none of them work for the 3D variant, quiver3.
I have the following plot and want to replace the blue arrows with a color corresponding to their magnitude.
In the old graphics system (R2014a and earlier) this is not possible using the built-in quiver object. You can easily get all of the plot objects that are used to compose the quiver plot
q = quiver(1:5, 1:5, 1:5, 1:5);
handles = findall(q, 'type', 'line');
But the tails are all represented by one plot object, and the arrow heads are represented by another. As such, you can't alter the color of each head/tail individually.
set(handles(1), 'Color', 'r')
set(handles(2), 'Color', 'g')
However, with the introduction of HG2 (R2014b and later), you can actually get access to two (undocumented) LineStrip objects (matlab.graphics.primitive.world.LineStrip) (one represents the heads and one represents the tails). These are accessible via the hidden properties Tail and Head.
q = quiver(1, 1, 1, 1);
headLineStrip = q.Head;
tailLineStrip = q.Tail;
You can then alter the color properties of these objects to make each arrow a different color.
The Basic Idea
To do this, I first compute the magnitude of all quiver arrows (this works for both quiver and quiver3)
mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
reshape(q.WData, numel(q.UData), [])).^2, 2));
Then I use the current colormap to map each magnitude to an RGB value. The shortest arrow is assigned the lowest color on the colormap and the longest arrow is assigned the highest color on the colormap. histcounts works great for assigning each magnitude an index which can be passed to ind2rgb along with the colormap itself. We have to multiply by 255 because we need the color to be RGB as an 8-bit integer.
% Get the current colormap
currentColormap = colormap(gca);
% Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));
% Now map this to a colormap
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);
The LineStrip ColorData property (when specified as truecolor) also needs to have an alpha channel (which we will set to 255 meaning opaque).
cmap(:,:,4) = 255;
At this point we can then set the ColorBinding property to interpolated rather than object (to decouple it from the quiver object) and set the ColorData property of both q.Head and q.Tail to the colors we created above giving each arrow it's own color.
Full Solution
NOTE: This solution works for both quiver and quiver3 and the code does not have to be adapted at all.
%// Create a quiver3 as we normally would (could also be 2D quiver)
x = 1:10;
y = 1:10;
[X,Y] = meshgrid(x, y);
Z = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
W = sqrt(X.^2 + Y.^2);
q = quiver3(X, Y, Z, U, V, W);
%// Compute the magnitude of the vectors
mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
reshape(q.WData, numel(q.UData), [])).^2, 2));
%// Get the current colormap
currentColormap = colormap(gca);
%// Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));
%// Now map this to a colormap to get RGB
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);
cmap(:,:,4) = 255;
cmap = permute(repmat(cmap, [1 3 1]), [2 1 3]);
%// We repeat each color 3 times (using 1:3 below) because each arrow has 3 vertices
set(q.Head, ...
'ColorBinding', 'interpolated', ...
'ColorData', reshape(cmap(1:3,:,:), [], 4).'); %'
%// We repeat each color 2 times (using 1:2 below) because each tail has 2 vertices
set(q.Tail, ...
'ColorBinding', 'interpolated', ...
'ColorData', reshape(cmap(1:2,:,:), [], 4).');
And applied to a 2D quiver object
If you don't necessarily want to scale the arrows to the entire range of the colormap you could use the following call to histcounts (instead of the line above) to map the magnitudes using the color limits of the axes.
clims = num2cell(get(gca, 'clim'));
[~, ~, ind] = histcounts(mags, linspace(clims{:}, size(currentColormap, 1)));
If your using a post r2014b version you can use undocumented features to change the colour of each line and head:
figure
[x,y] = meshgrid(-2:.5:2,-1:.5:1);
z = x .* exp(-x.^2 - y.^2);
[u,v,w] = surfnorm(x,y,z);
h=quiver3(x,y,z,u,v,w);
s = size(x);
nPoints = s(1)*s(2);
% create a colour map
cmap = parula(nPoints);
% x2 because each point has 2 points, a start and an end.
cd = uint8(repmat([255 0 0 255]', 1, nPoints*2));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
% and we need to assign a colour to the start and end of the
% line.
for jj=1:2
count = count + 1;
cd(1:3,count) = uint8(255*cmap(ii,:)');
end
end
% set the colour binding method and the colour data of the tail
set(h.Tail, 'ColorBinding','interpolated', 'ColorData',cd)
% create a color matrix for the heads
cd = uint8(repmat([255 0 0 255]', 1, nPoints*3));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
% and we need to assign a colour to the all the points
% at the head of the arrow
for jj=1:3
count = count + 1;
cd(1:3,count) = uint8(255*cmap(ii,:)');
end
end
% set the colour binding method and the colour data of the head
set(h.Head, 'ColorBinding','interpolated', 'ColorData',cd)
Note: I've not done anything clever with the magnitude and simply change the colour of each quiver based on the order in the original matrix - but you should be able to get the idea on how to use this "feature"
Note that if you are using Suevers solution and have NaNs in your data you should include this line before calling histcounts:
mags(isnan(mags)) = [];
Otherwise you will get an error about wrong input size because matlab does not create vertices for NaNs in your U/V/W data.
I would like to create a density plot of this function:
In Maple, one could use the densityplot function to achieve this (code at the end), which gives:
However, I am not sure what to use for plotting a similar figure in MATLAB.
Here is my current MATLAB code:
x = [0:10:100];
y = [-50:10:50];
s = [10, 0];
i = [50,25];
for ii = 1 : length(x)
sir(ii) = -10 * 9.8 * log10((power((x(ii) - s(1)),2) + power((y(ii) - s(2)),2)) / (power((x(ii) - i(1)),2) + power((y(ii) - i(2)),2)));
end
Could someone suggest an equivalent in MATLAB?
For the density plot in Maple, I used
densityplot(sir(x,y), x=0..100, y=-50..50, axes=boxed, style=patchnogrid, scaletorange=-5..50, colorscheme = [black, "green", "white"])
You can use surf (a 3D surface plot) to achieve this, but you will need a finer grid than steps of 10 for it to look good!
Also you will need meshgrid to get all combinations of the x and y coordinates.
Please see the comments for further details.
% Set up grid points
x = 0:0.1:100;
y = -50:0.1:50;
[x,y] = meshgrid(x,y);
% Set up parameters i, s and g
i = [50 25]; s = [10 0]; g = 9.8;
% Work out density
% - no need for loop if we use element-wise operations ./ and .^
% - power(z,2) replaced by z.^2 (same function, more concise)
% - You forgot the sqare roots in your question's code, included using .^(1/2)
% - line continuation with "...", could remove and have on one line
sir = -10*g*log10( ((x-s(1)).^2 + (y-s(2)).^2).^(1/2) ./ ...
((x-i(1)).^2 + (y-i(2)).^2).^(1/2) );
% Plot, and set to a view from above
surf(x,y,sir,'edgecolor','none','facecolor','interp');
view(2);
% Change the colour scheme
colormap('bone')
Result:
Matching your example
You used the Maple command scaletorange=-5..50. This limits the scale between -5 and 50 (docs), so since sir is our scale variable, we should limit it the same. In MATLAB:
% Restrict sir to the range [-5,50]
sir = min(max(sir,-5),50);
% Of course we now have to replot
surf(x,y,sir,'edgecolor','none','facecolor','interp');
view(2);
Now, if you wanted the black/green colours, you can use a custom colormap, this would also smooth out the banding caused by the 'bone' colormap only having 64 colours.
% Define the three colours to interpolate between, and n interpolation points
black = [0 0 0]; green = [0 1 0]; white = [1 1 1];
n = 1000;
% Do colour interpolation, equivalent to Maple's 'colorscheme = [black, "green", "white"]'
% We need an nx3 matrix of colours (columns R,G,B), which we get using interp1
colormap(interp1(1:3, [black; green; white], linspace(1,3,n)));
With g=3.5 (not sure what you used), we get an almost identical plot
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 want the color of each arrow in a quiver3 plot from MATLAB to correspond to the magnitude of each arrow. Is there any way to do that?
I saw a few examples online that are able to do this for the 2D quiver, however none of them work for the 3D variant, quiver3.
I have the following plot and want to replace the blue arrows with a color corresponding to their magnitude.
In the old graphics system (R2014a and earlier) this is not possible using the built-in quiver object. You can easily get all of the plot objects that are used to compose the quiver plot
q = quiver(1:5, 1:5, 1:5, 1:5);
handles = findall(q, 'type', 'line');
But the tails are all represented by one plot object, and the arrow heads are represented by another. As such, you can't alter the color of each head/tail individually.
set(handles(1), 'Color', 'r')
set(handles(2), 'Color', 'g')
However, with the introduction of HG2 (R2014b and later), you can actually get access to two (undocumented) LineStrip objects (matlab.graphics.primitive.world.LineStrip) (one represents the heads and one represents the tails). These are accessible via the hidden properties Tail and Head.
q = quiver(1, 1, 1, 1);
headLineStrip = q.Head;
tailLineStrip = q.Tail;
You can then alter the color properties of these objects to make each arrow a different color.
The Basic Idea
To do this, I first compute the magnitude of all quiver arrows (this works for both quiver and quiver3)
mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
reshape(q.WData, numel(q.UData), [])).^2, 2));
Then I use the current colormap to map each magnitude to an RGB value. The shortest arrow is assigned the lowest color on the colormap and the longest arrow is assigned the highest color on the colormap. histcounts works great for assigning each magnitude an index which can be passed to ind2rgb along with the colormap itself. We have to multiply by 255 because we need the color to be RGB as an 8-bit integer.
% Get the current colormap
currentColormap = colormap(gca);
% Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));
% Now map this to a colormap
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);
The LineStrip ColorData property (when specified as truecolor) also needs to have an alpha channel (which we will set to 255 meaning opaque).
cmap(:,:,4) = 255;
At this point we can then set the ColorBinding property to interpolated rather than object (to decouple it from the quiver object) and set the ColorData property of both q.Head and q.Tail to the colors we created above giving each arrow it's own color.
Full Solution
NOTE: This solution works for both quiver and quiver3 and the code does not have to be adapted at all.
%// Create a quiver3 as we normally would (could also be 2D quiver)
x = 1:10;
y = 1:10;
[X,Y] = meshgrid(x, y);
Z = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
W = sqrt(X.^2 + Y.^2);
q = quiver3(X, Y, Z, U, V, W);
%// Compute the magnitude of the vectors
mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
reshape(q.WData, numel(q.UData), [])).^2, 2));
%// Get the current colormap
currentColormap = colormap(gca);
%// Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));
%// Now map this to a colormap to get RGB
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);
cmap(:,:,4) = 255;
cmap = permute(repmat(cmap, [1 3 1]), [2 1 3]);
%// We repeat each color 3 times (using 1:3 below) because each arrow has 3 vertices
set(q.Head, ...
'ColorBinding', 'interpolated', ...
'ColorData', reshape(cmap(1:3,:,:), [], 4).'); %'
%// We repeat each color 2 times (using 1:2 below) because each tail has 2 vertices
set(q.Tail, ...
'ColorBinding', 'interpolated', ...
'ColorData', reshape(cmap(1:2,:,:), [], 4).');
And applied to a 2D quiver object
If you don't necessarily want to scale the arrows to the entire range of the colormap you could use the following call to histcounts (instead of the line above) to map the magnitudes using the color limits of the axes.
clims = num2cell(get(gca, 'clim'));
[~, ~, ind] = histcounts(mags, linspace(clims{:}, size(currentColormap, 1)));
If your using a post r2014b version you can use undocumented features to change the colour of each line and head:
figure
[x,y] = meshgrid(-2:.5:2,-1:.5:1);
z = x .* exp(-x.^2 - y.^2);
[u,v,w] = surfnorm(x,y,z);
h=quiver3(x,y,z,u,v,w);
s = size(x);
nPoints = s(1)*s(2);
% create a colour map
cmap = parula(nPoints);
% x2 because each point has 2 points, a start and an end.
cd = uint8(repmat([255 0 0 255]', 1, nPoints*2));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
% and we need to assign a colour to the start and end of the
% line.
for jj=1:2
count = count + 1;
cd(1:3,count) = uint8(255*cmap(ii,:)');
end
end
% set the colour binding method and the colour data of the tail
set(h.Tail, 'ColorBinding','interpolated', 'ColorData',cd)
% create a color matrix for the heads
cd = uint8(repmat([255 0 0 255]', 1, nPoints*3));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
% and we need to assign a colour to the all the points
% at the head of the arrow
for jj=1:3
count = count + 1;
cd(1:3,count) = uint8(255*cmap(ii,:)');
end
end
% set the colour binding method and the colour data of the head
set(h.Head, 'ColorBinding','interpolated', 'ColorData',cd)
Note: I've not done anything clever with the magnitude and simply change the colour of each quiver based on the order in the original matrix - but you should be able to get the idea on how to use this "feature"
Note that if you are using Suevers solution and have NaNs in your data you should include this line before calling histcounts:
mags(isnan(mags)) = [];
Otherwise you will get an error about wrong input size because matlab does not create vertices for NaNs in your U/V/W data.
I want the color of each arrow in a quiver3 plot from MATLAB to correspond to the magnitude of each arrow. Is there any way to do that?
I saw a few examples online that are able to do this for the 2D quiver, however none of them work for the 3D variant, quiver3.
I have the following plot and want to replace the blue arrows with a color corresponding to their magnitude.
In the old graphics system (R2014a and earlier) this is not possible using the built-in quiver object. You can easily get all of the plot objects that are used to compose the quiver plot
q = quiver(1:5, 1:5, 1:5, 1:5);
handles = findall(q, 'type', 'line');
But the tails are all represented by one plot object, and the arrow heads are represented by another. As such, you can't alter the color of each head/tail individually.
set(handles(1), 'Color', 'r')
set(handles(2), 'Color', 'g')
However, with the introduction of HG2 (R2014b and later), you can actually get access to two (undocumented) LineStrip objects (matlab.graphics.primitive.world.LineStrip) (one represents the heads and one represents the tails). These are accessible via the hidden properties Tail and Head.
q = quiver(1, 1, 1, 1);
headLineStrip = q.Head;
tailLineStrip = q.Tail;
You can then alter the color properties of these objects to make each arrow a different color.
The Basic Idea
To do this, I first compute the magnitude of all quiver arrows (this works for both quiver and quiver3)
mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
reshape(q.WData, numel(q.UData), [])).^2, 2));
Then I use the current colormap to map each magnitude to an RGB value. The shortest arrow is assigned the lowest color on the colormap and the longest arrow is assigned the highest color on the colormap. histcounts works great for assigning each magnitude an index which can be passed to ind2rgb along with the colormap itself. We have to multiply by 255 because we need the color to be RGB as an 8-bit integer.
% Get the current colormap
currentColormap = colormap(gca);
% Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));
% Now map this to a colormap
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);
The LineStrip ColorData property (when specified as truecolor) also needs to have an alpha channel (which we will set to 255 meaning opaque).
cmap(:,:,4) = 255;
At this point we can then set the ColorBinding property to interpolated rather than object (to decouple it from the quiver object) and set the ColorData property of both q.Head and q.Tail to the colors we created above giving each arrow it's own color.
Full Solution
NOTE: This solution works for both quiver and quiver3 and the code does not have to be adapted at all.
%// Create a quiver3 as we normally would (could also be 2D quiver)
x = 1:10;
y = 1:10;
[X,Y] = meshgrid(x, y);
Z = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
W = sqrt(X.^2 + Y.^2);
q = quiver3(X, Y, Z, U, V, W);
%// Compute the magnitude of the vectors
mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
reshape(q.WData, numel(q.UData), [])).^2, 2));
%// Get the current colormap
currentColormap = colormap(gca);
%// Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));
%// Now map this to a colormap to get RGB
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);
cmap(:,:,4) = 255;
cmap = permute(repmat(cmap, [1 3 1]), [2 1 3]);
%// We repeat each color 3 times (using 1:3 below) because each arrow has 3 vertices
set(q.Head, ...
'ColorBinding', 'interpolated', ...
'ColorData', reshape(cmap(1:3,:,:), [], 4).'); %'
%// We repeat each color 2 times (using 1:2 below) because each tail has 2 vertices
set(q.Tail, ...
'ColorBinding', 'interpolated', ...
'ColorData', reshape(cmap(1:2,:,:), [], 4).');
And applied to a 2D quiver object
If you don't necessarily want to scale the arrows to the entire range of the colormap you could use the following call to histcounts (instead of the line above) to map the magnitudes using the color limits of the axes.
clims = num2cell(get(gca, 'clim'));
[~, ~, ind] = histcounts(mags, linspace(clims{:}, size(currentColormap, 1)));
If your using a post r2014b version you can use undocumented features to change the colour of each line and head:
figure
[x,y] = meshgrid(-2:.5:2,-1:.5:1);
z = x .* exp(-x.^2 - y.^2);
[u,v,w] = surfnorm(x,y,z);
h=quiver3(x,y,z,u,v,w);
s = size(x);
nPoints = s(1)*s(2);
% create a colour map
cmap = parula(nPoints);
% x2 because each point has 2 points, a start and an end.
cd = uint8(repmat([255 0 0 255]', 1, nPoints*2));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
% and we need to assign a colour to the start and end of the
% line.
for jj=1:2
count = count + 1;
cd(1:3,count) = uint8(255*cmap(ii,:)');
end
end
% set the colour binding method and the colour data of the tail
set(h.Tail, 'ColorBinding','interpolated', 'ColorData',cd)
% create a color matrix for the heads
cd = uint8(repmat([255 0 0 255]', 1, nPoints*3));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
% and we need to assign a colour to the all the points
% at the head of the arrow
for jj=1:3
count = count + 1;
cd(1:3,count) = uint8(255*cmap(ii,:)');
end
end
% set the colour binding method and the colour data of the head
set(h.Head, 'ColorBinding','interpolated', 'ColorData',cd)
Note: I've not done anything clever with the magnitude and simply change the colour of each quiver based on the order in the original matrix - but you should be able to get the idea on how to use this "feature"
Note that if you are using Suevers solution and have NaNs in your data you should include this line before calling histcounts:
mags(isnan(mags)) = [];
Otherwise you will get an error about wrong input size because matlab does not create vertices for NaNs in your U/V/W data.