I need to control the transparency of the markers in the figure produced with the scatterhist command in MATLAB.
The following post is helpful in handling the color of the histograms: Controlling scatterhist bar colors.
How can the transparency of the markers be modified?
How can I add a contour plot on top of the markers?
tl;dr:
In MATLAB R2019a,
scatterhist() can do contours but it is difficult (yet possible) to add marker transparency, and
scatterhistogram() can easily do transparency but contours are difficult.
See the third option below using alpha(), scatter(), and histogram() which builds this from scratch.
% MATLAB R2019a
n = 250; % Number of Points
X = exprnd(3,n,1);
Y = gamrnd(9,1/3,n,1);
Using scatterhistogram():
You can adjust the marker transparency with the MarkerAlpha Property.
T = table(X,Y);
figure
s = scatterhistogram(T,'X','Y',...
'HistogramDisplayStyle','smooth',...
'LineStyle','-')
s.MarkerAlpha = 0.5; % adjust transparency
The documentation demonstrates variations of this technique.
Notice that scatterhistogram() cannot be used with hold on either before or after, which prevents using this solution from MATLAB Central.
% This will give an error in R2019a
figure
s = scatterhistogram(T,'X','Y','HistogramDisplayStyle','smooth','LineStyle','-')
hold on
[m,c] = hist3([X', Y']); % [m,c] = hist3([X(:), Y(:)]);
contour(c{1},c{2},m)
Using scatterhist():
If you name s = scatterhist(X,Y), then s(1) is the scatter plot, s(2) & s(3) are the histograms. This allows you to change properties. Notice that s(1).Children.MarkerFaceColor = 'b' works fine but there is no MarkerAlpha or MarkerFaceAlpha property (you'll get an error telling you so).
But, contours are possible. I think transparency is possible to based on this comment from #Dev-iL, but I haven't figured it out yet.
figure
s = scatterhist(X,Y,'Direction','out')
s(1).Children.Marker = '.'
hold on
[m,c] = hist3([X(:), Y(:)]);
ch = contour(c{1},c{2},m)
Build it from scratch:
Obviously the entire thing can be manually constructed from scratch (but that's not appealing).
Using the alpha() command gets it done.
figure1 = figure;
% Create axes
axes1 = axes('Tag','scatter','Parent',figure1,...
'Position',[0.35 0.35 0.55 0.55]);
hold(axes1,'on');
% Create plot
s = scatter(X,Y,'Parent',axes1,'MarkerFaceColor','r','Marker','o');
ylabel('Y');
xlabel('X');
box(axes1,'on');
% Create axes
axes2 = axes('Tag','yhist','Parent',figure1,...
'Position',[0.0325806451612903 0.35 0.217016129032258 0.55]);
axis off
hold(axes2,'on');
% Create histogram
hx = histogram(X,'Parent',axes2,'FaceAlpha',1,'FaceColor','r',...
'Normalization','pdf',...
'BinMethod','auto');
view(axes2,[270 90]);
box(axes2,'on');
% Create axes
axes3 = axes('Tag','xhist','Parent',figure1,...
'Position',[0.35 0.0493865030674847 0.55 0.186679572132827]);
axis off
hold(axes3,'on');
% Create histogram
hy = histogram(Y,'Parent',axes3,'FaceAlpha',1,'FaceColor','r',...
'Normalization','pdf',...
'BinMethod','auto');
box(axes3,'on');
axis(axes3,'ij');
[m,c] = hist3([X(:), Y(:)]);
contour(axes1,c{1},c{2},m)
alphaVal = 0.3;
alpha(s,0.5) % Set Transparency
alpha(hx,0.5)
alpha(hy,0.5)
References:
1. Access Property Values in MATLAB
2. Plot markers transparency and color gradient
For Matlab versions prior to 2018, scatterhistogram isn't available. And so, I found an alternative easy way to accomplish that markers have transparency:
figure
scatterhist(X,Y,'Kernel','on'); hold on
hdl = get(gca,'children');
set(hdl,'MarkerEdgeColor','none')
scatter(hdl.XData,hdl.YData,50,'MarkerFaceColor','r',...
'MarkerEdgeColor','none','MarkerFaceAlpha',0.2)
This works nicely.
Related
What is a proper way to separate the initialization and the display of plots in Matlab? (I mean plots in a wide sense here; could be plot, plot3, scatter etc.) To give a concrete example, I have a pretty complex 3D visualization that uses sphere and mesh to draw a static sphere mesh and then scatter3 to plot a moving trajectory on the sphere. To be able to do this in real time I have implemented some simple optimizations, such as only updating the scatter3 object each frame. But the code is a bit messy, making it hard to add additional features that I want, so I would like improve code separation.
I also feel like it might sometimes be useful to return some kind of plot object from a function without displaying it, for example to combine it with other plots in a nice modular way.
An example of what I have in mind would be something like this:
function frames = spherePlot(solution, options)
% Initialize sphere mesh and scatter objects, configure properties.
...
% Configure axes, maybe figure as well.
...
% Draw sphere.
...
if options.display
% Display figure.
end
for step = 1:solution.length
% Update scatter object, redraw, save frame.
% The frames are saved for use with 'movie' or 'VideoWriter'.
end
end
Each step might also be separated out as a function.
So, what is a neat and proper way to do stuff like this? All documentation seems to assume that one wants to display everything right away.
For example
% some sample data
N = 100;
phi = linspace(-pi, pi, N);
theta = linspace(-pi, pi, N);
f = #(phi, theta) [sin(phi).*cos(theta); sin(phi).*sin(theta); cos(phi)];
data = f(phi, theta);
% init plot
figure(1); clf
plot3(data(1,:), data(2,:), data(3,:)); % plot path, not updated
hold on
p = plot3([0 data(1,1)], [0 data(2,1)], [0 data(3,1)]); % save handle to graphics objects to update
s = scatter3(data(1,1), data(2,1), data(3,1), 'filled');
axis equal
xlabel('x'); ylabel('y'); zlabel('z');
t = title('first frame'); % also store handle for title or labels to update during animation
% now animate the figure
for k = 1:N
p.XData = [0 data(1,k)]; % update line data
p.YData = [0 data(2,k)];
p.ZData = [0 data(3,k)];
s.XData = data(1,k); % update scatter data
s.YData = data(2,k);
s.ZData = data(3,k);
t.String = sprintf('frame %i', k); % update title
drawnow % update figure
end
Basically you can update all values for a graphics handle, in this case 'p' and 's'. If you open the matlab doc for plot or plot3 you will find a link to all properties of that primitive: e.g. Line Properties. Similar documentation pages exist for scatter/imagesc etc.
So the general idea is to first create a figure with the first frame, save the handles to the objects you would like to update (p = plot(...), and then enter a loop in which you update the required property of that graphics object (e.g. p.Color = 'r', or p.XData = ...).
I am building a demonstration application using the matlab application designer.
It has two axes. One shows an image. The other shows the profile of the image, and the derivative of the profile.
In the example below, I have a 200 column, by 5 row image.
Below the image, I have a plot of the image profile, and a plot of the derivative. The image profile has (not surprisingly) 200 elements. I'd like the X/Y plots to align consistently with the image axis.
Is there a way to control the image axes, to align correctly with the plot axes?
Obviously, I could remove the axis(app.AxesImageView,'off') line below, and force the axes on. But, that doesn't work either, because the axis labels are very different, and so they don't line up. I want this to be flexible to work for any size image, and the label sizes impact this as well.
TLDR: Is it possible to force the axes in a plot or an imagesc to reside in a particular spot in the region the axes have set aside for rendering?
The current code for rendering the image and the plot are:
w = 5; l = 200;
parms.filterHalfWidth = 20;
img = zeros(w,l);
img(:,ceil(l/2):end)=255;
img = uint8(img);
imagesc(app.AxesImageView,img,[0,255]);
colormap(app.AxesImageView, 'gray');
axis(app.AxesImageView,'off');
title(app.AxesImageView,'Image to find edge');
profile = mean(img,2);
vals = derivative(profile, parms.filterHalfWidth);
[~, peak] = max(vals);
plot(app.AxesProfiles, profile);
hold(app.AxesProfiles, 'all');
plot(app.AxesProfiles, parms.filterHalfWidth + (1:numel(vals)), vals);
plot(app.AxesProfiles, peak*[1,1], [0,255],'Color','Red','LineWidth',2);
hold(app.AxesProfiles, 'off');
i wasn't able to reproduce your code but I wrote a piece of code with uifigure and ... (which is primary used in appdesigner)
it is completely flexible
p.s: I don't have required toolbox to calculate derivative so I used another plot.
f=uifigure;
f.Units = "normalized"; % essential
f.Position= [0.3 0.2 0.5 0.7];
f.AutoResizeChildren='off'; % essential
ax2=uiaxes(f);
ax2.Units = "normalized";
ax2.InnerPosition=[0.1 0.1 0.8 0.4]; % set Innerposition of axes at your desired position relative to the figureto ensure axes alignment
ax1=uiaxes(f);
ax1.Units = "normalized";
ax1.InnerPosition=[0.1 0.55 0.8 0.4];
w = 5; l = 200;
parms.filterHalfWidth = 20;
img = zeros(w,l);
img(:,ceil(l/2):end)=255;
img = uint8(img);
imagesc(ax1,img,[0,255]);
colormap(ax1, 'gray');
axis(ax1,'off');
title(ax1,'Image to find edge');
profile = mean(img,2);
vals = derivative(profile, parms.filterHalfWidth);
[~, peak] = max(vals);
plot(ax2, profile);
hold(ax2, 'all');
plot(ax2, parms.filterHalfWidth + (1:numel(vals)), vals);
plot(ax2, peak*[1,1], [0,255],'Color','Red','LineWidth',2);
hold(ax2, 'off');
I've found this answer, but I can't complete my work. I wanted to plot more precisely the functions I am studying, without overcoloring my function with black ink... meaning reducing the number of mesh lines. I precise that the functions are complex.
I tried to add to my already existing code the work written at the link above.
This is what I've done:
r = (0:0.35:15)'; % create a matrix of complex inputs
theta = pi*(-2:0.04:2);
z = r*exp(1i*theta);
w = z.^2;
figure('Name','Graphique complexe','units','normalized','outerposition',[0.08 0.1 0.8 0.55]);
s = surf(real(z),imag(z),imag(w),real(w)); % visualize the complex function using surf
s.EdgeColor = 'none';
x=s.XData;
y=s.YData;
z=s.ZData;
x=x(1,:);
y=y(:,1);
% Divide the lengths by the number of lines needed
xnumlines = 10; % 10 lines
ynumlines = 10; % 10 partitions
xspacing = round(length(x)/xnumlines);
yspacing = round(length(y)/ynumlines);
hold on
for i = 1:yspacing:length(y)
Y1 = y(i)*ones(size(x)); % a constant vector
Z1 = z(i,:);
plot3(x,Y1,Z1,'-k');
end
% Plotting lines in the Y-Z plane
for i = 1:xspacing:length(x)
X2 = x(i)*ones(size(y)); % a constant vector
Z2 = z(:,i);
plot3(X2,y,Z2,'-k');
end
hold off
But the problem is that the mesh is still invisible. How to fix this? Where is the problem?
And maybe, instead of drawing a grid, perhaps it is possible to draw circles and radiuses like originally on the graph?
I found an old script of mine where I did more or less what you're looking for. I adapted it to the radial plot you have here.
There are two tricks in this script:
The surface plot contains all the data, but because there is no mesh drawn, it is hard to see the details in this surface (your data is quite smooth, this is particularly true for a more bumpy surface, so I added some noise to the data to show this off). To improve the visibility, we use interpolation for the color, and add a light source.
The mesh drawn is a subsampled version of the original data. Because the original data is radial, the XData and YData properties are not a rectangular grid, and therefore one cannot just take the first row and column of these arrays. Instead, we use the full matrices, but subsample rows for drawing the circles and subsample columns for drawing the radii.
% create a matrix of complex inputs
% (similar to OP, but with more data points)
r = linspace(0,15,101).';
theta = linspace(-pi,pi,101);
z = r * exp(1i*theta);
w = z.^2;
figure, hold on
% visualize the complex function using surf
% (similar to OP, but with a little bit of noise added to Z)
s = surf(real(z),imag(z),imag(w)+5*rand(size(w)),real(w));
s.EdgeColor = 'none';
s.FaceColor = 'interp';
% get data back from figure
x = s.XData;
y = s.YData;
z = s.ZData;
% draw circles -- loop written to make sure the outer circle is drawn
for ii=size(x,1):-10:1
plot3(x(ii,:),y(ii,:),z(ii,:),'k-');
end
% draw radii
for ii=1:5:size(x,2)
plot3(x(:,ii),y(:,ii),z(:,ii),'k-');
end
% set axis properties for better 3D viewing of data
set(gca,'box','on','projection','perspective')
set(gca,'DataAspectRatio',[1,1,40])
view(-10,26)
% add lighting
h = camlight('left');
lighting gouraud
material dull
How about this approach?
[X,Y,Z] = peaks(500) ;
surf(X,Y,Z) ;
shading interp ;
colorbar
hold on
miss = 10 ; % enter the number of lines you want to miss
plot3(X(1:miss:end,1:miss:end),Y(1:miss:end,1:miss:end),Z(1:miss:end,1:miss:end),'k') ;
plot3(X(1:miss:end,1:miss:end)',Y(1:miss:end,1:miss:end)',Z(1:miss:end,1:miss:end)','k') ;
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 would like to set some transparency in my plot which I can do with alpha. This works great but I also want to adapt the colorbar. Here is an example:
subplot(2,1,1)
A = imagesc(meshgrid(0:10,0:5));
alpha(A,1)
colorbar
subplot(2,1,2)
B = imagesc(meshgrid(0:10,0:5));
alpha(B,.1)
colorbar
The example is taken from here. On this page two solutions exists but none works for Matlab R2015b.
With HG2 graphics (R2014b+) you can get some of the undocumented underlying plot objects and alter the transparency.
c = colorbar();
% Manually flush the event queue and force MATLAB to render the colorbar
% necessary on some versions
drawnow
alphaVal = 0.1;
% Get the color data of the object that correponds to the colorbar
cdata = c.Face.Texture.CData;
% Change the 4th channel (alpha channel) to 10% of it's initial value (255)
cdata(end,:) = uint8(alphaVal * cdata(end,:));
% Ensure that the display respects the alpha channel
c.Face.Texture.ColorType = 'truecoloralpha';
% Update the color data with the new transparency information
c.Face.Texture.CData = cdata;
You have to be careful doing this as the colorbar is continually refreshed and these changes will not stick. To get them to stay while I printed the figure, I just changed the ColorBinding mode of the Face to something besides interpolated
c.Face.ColorBinding = 'discrete';
This means that it won't be updated when you change color limits or the colormap. If you want to change either of those things you'll need to reset the ColorBinding to intepolated and then run the above code again.
c.Face.ColorBinding = 'interpolated';
For example, the following would save an image with a transparent colorbar for two colormaps:
c = colorbar();
drawnow;
alphaVal = 0.1;
% Make the colorbar transparent
cdata = c.Face.Texture.CData;
cdata(end,:) = uint8(alphaVal * cdata(end,:));
c.Face.Texture.ColorType = 'truecoloralpha';
c.Face.Texture.CData = cdata;
drawnow
% Make sure that the renderer doesn't revert your changes
c.Face.ColorBinding = 'discrete';
% Print your figure
print(gcf, 'Parula.png', '-dpng', '-r300');
% Now change the ColorBinding back
c.Face.ColorBinding = 'interpolated';
% Update the colormap to something new
colormap(jet);
drawnow
% Set the alpha values again
cdata = c.Face.Texture.CData;
cdata(end,:) = uint8(alphaVal * cdata(end,:));
c.Face.Texture.CData = cdata;
drawnow
% Make sure that the renderer doesn't revert your changes
c.Face.ColorBinding = 'discrete';
print(gcf, 'Ugly_colormap.png', '-dpng', '-r300');
The solution form Suever works however when working in the live editor (R2020b) I had to add:
set(gcf,'Visible','on')
This makes it such that the figure is plotted in an external pop up. Then it does work, but I do not know why.
Working example for live editor:
figure(1);clf;
set(gcf,'Visible','on')
c = colorbar();
drawnow;
alphaVal = 0.5;
% Make the colorbar transparent
cdata = c.Face.Texture.CData;
cdata(end,:) = uint8(alphaVal * cdata(end,:));
c.Face.Texture.ColorType = 'truecoloralpha';
c.Face.Texture.CData = cdata;