Related
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.
I have a problem with saving a Matlab figure as ".svg" and subsequently opening it in Inkscape. More precisely, I need two subplots to be a specific height, i.e. 6cm. This can be done in Matlab by setting the "Position" property (and setting the units to "centimeters"). This all works as expected and I then export the figure as ".svg"
The problem is that when I import the figure to Inkscape the axes length is close to the value I set but not correct. I.e. I set it to 6 cm and it is 6.28 in Inkscape. It is not much of an error, but it completely defeats the purpose of defining it in the first place. Any ideas?
I tried exporting the figure in several different ways but the result is always the same.
figure('name','representative plasticity figure');
set(gcf,'Color','w','units','centimeters','position',...
[0 0 8.6 8.4],'PaperPositionMode','auto');
s1=subplot(2,1,1)
img = imagesc(magic(8)); hold on;
set(gca, 'TickDir','out','FontSize',8.5,'LineWidth',0.59,'TickLength'...
,[0.03 0.00001]);
c1 = colorbar; c1.Box = 'off';c1.TickDirection = 'out'; c1.FontSize = 8.5;
ax1 = gca; ax1.Units = 'Centimeters';ax1.Position(3:4) = [3.427, 1.59];
box off; % THIS IS THE SIZE I NEED BUT WHICH ISN'T PRINTED CORRECTLY
c1.Label.String = '[whatever]';
subplot(2,1,2)
p1=plot(randi(5,5),'r','LineWidth',0.64); hold on;
box off; set(gca, 'TickDir','out','TickLength',...
[0.03 0.00001],'FontSize',8.5,'LineWidth',0.64);% legend('pre','post');
legend('boxoff');
ax2 = gca;ax2.Units = 'Centimeters';ax2.Position(3:4) = ax1.Position(3:4);
xlabel ('whatever' ); ylabel('whatever');
print myplot -dsvg
The size of the figure should be [3.427, 1.59] in cm. And it is so in the resulting matlab figure, however, in Inkscape it is more like 3.6 and 1.7.
I have plenty of subplots I have to load and put all together using Matlab. I want to add personalized Ticks but my approach does not seem to work. My mwe is the following:
x = 1:1:1000;
r = rand(1000,1);
my1 = subplot(2,3,1);
my1 = bar(x,sort(r));
title ('This works')
xlabel ('This works too')
xlim ([0 1000])
my = get(gca);
my.XTick = [1 200 499]
And this last point does not work. Why? How can I fix it?
get(gca) returns a struct of all graphics properties of the current axes, not the axes handle itself. Any changes made to this struct of properties are not mirrored in your actual axes. You need to modify the properties of the axes directly using set
set(gca, 'XTick', [1 200 499])
Or if you're on 2014b
% Don't use get(gca) to get the handle
ax = gca;
% Set the XTick property
ax.XTick = [1 200 499];
I have some figures, for which I want to change:
The title
The xlabel and the ylabel (both font size and content)
The ticks size.
This is how I usually do it:
title('new title ');
xlhand = get(gca,'xlabel');
set(xlhand,'string','xlabel','fontsize',13);
ylhand = get(gca,'ylabel');
set(ylhand,'string','ylabel','fontsize',13);
set(gca,'FontSize',13);
It usually works fine. However, it doesn't work when I want to edit a plot made with the ploty function. The only effect is that my right ylabel changes.
I'm aware that since I have two ylabels now, changing them won't be as easy as for a normal plot. However, I'm surprised that I can't change the xlabels and the title. Why is that?
What's wrong with the above code in relation to the plotxy function? How can I make it work? The documentation doesn't contain any relevant information.
I'm using Matlab R2015a.
Edit: Yes, I meant plotyy (there was a typo in my question). Here is sample code from the documentation:
x = 0:0.01:20;
y1 = 200*exp(-0.05*x).*sin(x);
y2 = 0.8*exp(-0.5*x).*sin(10*x);
figure % new figure
plotyy(x,y1,x,y2)
If you look at the documentation, you can see that plotyy can return the axis handles. So first, you that option to obtain the handles:
Ax = plotyy(x,y1,x,y2);
Now, Ax(1) is the handle to the left axes and Ax(2) is the right one. So you can change the attributes of each of them, for example
set(Ax(1),'FontSize',13);
For reasons I don't fully understand, setting the label is done using
set(get(Ax(1),'YLabel'),'String','Whatever you want...');
EDIT:
If you already plotted the data, you can retrieve the handles using
Ax = findobj(gcf,'type','axes')
From documentation without using get, set :
x = 0:0.01:20;
y1 = 200*exp(-0.05*x).*sin(x);
y2 = 0.8*exp(-0.5*x).*sin(10*x);
figure % new figure
hAx = plotyy(x,y1,x,y2);
title('Multiple Decay Rates')
xlabel('Time (\musec)')
ylabel(hAx(1),'Slow Decay') % left y-axis
ylabel(hAx(2),'Fast Decay') % right y-axis
Then change values by
xlabel('New label','fontsize',10)
title('New Title','fontsize',10)
ylabel(hAx(2),'Fast Decay','fontsize',20)
hAx(1).FontSize=5
This issue is only for unix matlabs, windows users won't be able to reproduce it.
I am having trouble while trying to create datatips in which are on top of the y axis label. The following picture illustrate the issue:
As you can see, the datatips created close to the ylabel will get bottom to the ylabel text, while the desire effect is the opposite: the datatip to be on top of the axis label.
I generated the plot with the following (not so minimal) code, which is available bellow. You may remove the lines commented with % may be removed, or even just put a datatip on −78 instead of a loop in order to achieve a faster testing script, but I leave this code if someone one day wants it to create custom datatips (in this case, consider seeing also http://undocumentedmatlab.com/blog/controlling-plot-data-tips/):
gradientStep = 1e-1;
x=-100:gradientStep:100; xSize=numel(x);
y=x.^3-x.^2;
figH=figure(42);
lineH=plot(x,y);
ylabel('YLabel (YUnits)','FontSize',16)
xlabel('XLabel (XUnits)','FontSize',16)
dcH=datacursormode(figH);
nTips = 20; % May change the loop for a datatip at x=-78.
for pos = round(linspace(2,xSize,nTips))
datatipH=dcH.createDatatip(lineH,...
struct('Position',[x(pos) y(pos)]));
orientation = 'top-left';
if pos>1
tipText{1} = 'The grandient here is: ';
tipText{2} = ['\Deltax:',sprintf('%d',x(pos)-x(pos-1)),' XUnits'];
tipText{3} = ['\Deltay:',sprintf('%d',y(pos)-y(pos-1)),' YUnits'];
else
tipText = 'Cannot calculate gradient here.';
end
bkgColor = [1 1 .5]; % May be removed.
fontSize = 12; % May be removed.
set(datatipH,'StringFcn',(#(~,~) tipText),'Orientation',...
orientation,'backGroundColor',bkgColor,'FontSize',...
fontSize,'Draggable','on'); % Only set text and orientation needed.
datatipTextBoxH=get(datatipH,'TextBoxHandle'); % May be removed.
uistack(datatipH,'top'); % Unfortunately makes no effect, since the ylabel handles is not at the axes children list
datatipTextBoxH=get(datatipH,'TextBoxHandle');
set(datatipTextBoxH,'HorizontalAlignment','left',...
'VerticalAlignment','top','Margin',0.02,'Interpreter',...
'tex','FontName','Courier','FontSize',fontSize); % May be removed.
end
uistack(get(gca,'YLabel'),'bottom') % Also makes no effect, for the same reason.
I have tried:
uistack all datatips to top,
uistack the label to bottom (both of them don't work because the ylabel handle is not in the axes children handles).
Update: After implementing the #horchler' solution, a new issue appeared: when zooming and panning the axes, the axes label would also move. I've found a small fix for that, I changed the following aspects:
Set datatip z-value to 1, so that it will always be higher than ylabel axis z.
Recreating the ylabel afterwards a pan or zoom movement occurs. For this, I implemented localAxisUpdate function that get the old ylabel properties, replace it by a new one, and them reset all settable properties but the ylabel position. For this I used this reference
The resulting code is as follows:
function test
gradientStep = 1e-1;
x=-100:gradientStep:100; xSize=numel(x);
y=x.^3-x.^2;
figH=figure(42);
lineH=plot(x,y);
ylabel('YLabel (YUnits)','FontSize',16)
xlabel('XLabel (XUnits)','FontSize',16)
dcH=datacursormode(figH);
%nTips = 20;
%for pos = round(linspace(2,xSize,nTips))
pos = find(x>-78,1);
datatipH=dcH.createDatatip(lineH,...
struct('Position',[x(pos) y(pos) 1]));
orientation = 'top-left';
if pos>1
tipText{1} = 'The grandient here is: ';
tipText{2} = ['\Deltax:',sprintf('%d',x(pos)-x(pos-1)),' XUnits'];
tipText{3} = ['\Deltay:',sprintf('%d',y(pos)-y(pos-1)),' YUnits'];
else
tipText = 'Cannot calculate gradient here.';
end
bkgColor = [1 1 .5]; % Light Yellow
fontSize = 12;
set(datatipH,'StringFcn',(#(~,~) tipText),'Orientation',...
orientation,'backGroundColor',bkgColor,'FontSize',...
fontSize,'Draggable','on');
datatipTextBoxH=get(datatipH,'TextBoxHandle');
datatipTextBoxH=get(datatipH,'TextBoxHandle');
set(datatipTextBoxH,'HorizontalAlignment','left',...
'VerticalAlignment','top','Margin',0.02,'Interpreter',...
%end
% Set changes due to zoom and pan to also use adaptativeDateTicks:
set(zoom(figH),'ActionPostCallback',...
#(~,~) localAxisUpdate(gca));
set(pan(figH),'ActionPostCallback',...
#(~,~) localAxisUpdate(gca));
end
function localAxisUpdate(aH)
% Fix axis label on top of datatip:
ylh = get(aH,'YLabel');
% Get original YLabel properties
ylstruct = get(ylh);
% Get settable fields:
yfieldnames=fieldnames(rmfield(set(ylh),'Position'))';
% Remove old label:
delete(ylh)
% Create new one:
ylh = ylabel(aH,'Dummy');
% Send it bottom:
ylpos = get(ylh,'Position');
set(ylh, 'Position', [ylpos(1:2) 0]);
% Reset new ylabel to old values:
for field=yfieldnames
field = field{1};
set(ylh,field,ylstruct.(field));
end
end
This approach creates an unwanted effect, which is the ylabel will move across the figure until the mouse button is released. How can I remove this unwanted effect ?
I think the solution may be more or less as it was done in undocummented matlab solution for updating axes ticks, but now I would need the listener to the ylabel postset property. Does anyone knows how to do that? If you are a windows user, you can also try to help, all I need is to reset the position of the ylabel after a change (pan, zoom or whatever) is made on the figure.
How about explicitly setting the z-position of the y-label via it's handle? If I put this after your loop it seems to work in R2012b:
ylh = get(gca,'Ylabel')
ylpos = get(ylh,'Position');
set(ylh,'Position',[ylpos(1:2) 0]);
If I adjust the z-position I can get the y-label to pop up and even interleave between the datatips. I'm not completely sure if this is a bug or a feature, but sometimes there are workarounds to rendering issues that involve tweaking the position of an element slightly to get Matlab to recalculate and redraw the figure.
A workaround that uses both linkaxes, so useful when zooming/panning multiple plots, and the visibilty of plots.
create an axes (hax_1) with the function to be plotted, without the datatips
create an axes (hax_2) with the function to be plotted AND the datatips but without the axes labels
set hax_2 visibility to 'off' (this will plot the datatips above the first axes labels)
link the 2 axes with linkaxes([hax_1 hax_2],'xy'); (zooming and panning on one of the axes will modify on the fly the second axes)
This gives with your first code (not the edited one):
gradientStep = 1e-1;
x=-100:gradientStep:100; xSize=numel(x);
y=x.^3-x.^2;
figH=figure(42);
plot(x,y);
ylabel('YLabel (YUnits)','FontSize',16)
xlabel('XLabel (XUnits)','FontSize',16)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% modification starts
hax_1 = gca;
hax_2 = axes('Position', get(hax_1,'Position'));
lineH = plot(x,y);
linkaxes([hax_1 hax_2],'xy');
set(hax_2,'Visible', 'off');
% modification ends
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
dcH=datacursormode(figH);
nTips = 20; % May change the loop for a datatip at x=-78.
for pos = round(linspace(2,xSize,nTips))
datatipH=dcH.createDatatip(lineH,struct('Position',[x(pos) y(pos)]));
orientation = 'top-left';
if pos>1
tipText{1} = 'The grandient here is: ';
tipText{2} = ['\Deltax:',sprintf('%d',x(pos)-x(pos-1)),' XUnits'];
tipText{3} = ['\Deltay:',sprintf('%d',y(pos)-y(pos-1)),' YUnits'];
else
tipText = 'Cannot calculate gradient here.';
end
bkgColor = [1 1 .5]; % May be removed.
fontSize = 12; % May be removed.
set(datatipH,'StringFcn',(#(~,~) tipText),'Orientation',orientation,'backGroundColor',bkgColor,'FontSize',fontSize,'Draggable','on'); % Only set text and orientation needed.
datatipTextBoxH=get(datatipH,'TextBoxHandle');
set(datatipTextBoxH,'HorizontalAlignment','left','VerticalAlignment','top','Margin',0.02,'Interpreter','tex','FontName','Courier','FontSize',fontSize); % May be removed.
end
I am on OSX 10.8.4, R2012b, and had the same issue as yours. Here, the proposed solution plots datatips above the axis labels and allow zooming/panning without making use of undocumented features of matlab.