I am currently working on adding annotations to satellite images in MATLAB. Since the color underneath each text field can vary quite a lot, I want to use a background color under the text to make it easier to see and read.
However, when I do this, a lot of the terrain gets obscured. I though of trying to make the background color for each text box semi transparent, but hit a dead end trying to come up with a solution.
Any ideas? I was hoping for some UI-element where I could just set the 'facealpha' to maybe 0.5. I also need the text to support being rotated (as can be seen in the examples below).
Below is some example code and the resulting image. The workspace with the satellite data can also be found in the link:
Example workspace
figure(1);clf
imagesc(xx,yy,Map);
hold on
plot(xInspection,yInspection,'g.-')
% # Two ways of making a rotated text annotation.
% # Cant make background semi-transparent
testAnno= annotation('textarrow',[0.5 0.5],[0.5 0.5], ...
'string','textarrow annotation', ...
'HeadStyle','none','LineStyle', 'none',...
'TextRotation',asin(directionVec(1))*180/pi,...
'TextBackgroundColor',[0.7 0.7 0.7]);
testText = text(mean(xInspection),mean(yInspection),'text annotation', ...
'rotation',asin(directionVec(1))*180/pi, ...
'HorizontalAlignment','right', ...
'color',[0 0 0], ...
'backgroundcolor',[0.7 0.7 0.7], ...
'fontsize',8);
It doesn't look like either annotation or text return HgObjects that have BackgroundAlpha properties (they might exist but I wasn't able to find them using getundoc or by trying various different hacks).
I was able to get something working by drawing the background myself. Here is a simple proof of concept:
f = figure;
tObj = text(.5, .5, 'text object', 'FontSize', 20);
set(gca,'XLimMode', 'manual', 'YLimMode', 'manual'); % prevent the axes from resizing automatically
p = get(tObj, 'Extent'); %Get the outer position of the text
% now create a patch around the text object
pObj = patch([p(1) p(1) p(1)+p(3) p(1)+p(3)], [p(2) p(2)+p(4) p(2)+p(4) p(2)], 'r');
uistack(tObj, 'top'); % put the text object on top of the patch object
set(pObj , 'FaceAlpha', .2); % set the alpha of the patch face to .2
%Rotate the objects
set(tObj, 'Rotation', 20);
rotate(pObj, [0 0 1], 20);
I am afraid the only way you can do this is by not setting any color to your annotations, and then placing a patch in the background of each annotation. So something like this:
% Use completely transparent annotations
hA = annotation('textarrow', ..., 'TextBackgroundColor', 'none')
% Place a transparent patch exactly in the background of your annotation
hP = patch(X, Y, 'white', 'EdgeColor', 'none', 'FaceColor', 'white', ...
'alpha', 0.3)
% Ensure that your annotation is on top
uistack(hA, 'top')
But of course the big problem is to determine the correct coordinates of the patch (X and Y). Rotating is easy by simply multiplying your coordinates by a rotation matrix. However, finding the length and height of the patch and its central location is not that easy. You might be able to find some useful functions for this at Matlab central...
Related
I'm representing a surface using "surf" function, with a colorbar. I would like to keep the default ticks of the colorbar, but add a custom tick on this colorbar, at a specific value (that I could make red to distinguish it from other ticks for example). Any idea on how to add a custom tick like that with keeping existing ticks on the colorbar ?
Thanks
As Luis mentioned in the comments, you can add an additional tick mark like so
h = colorbar;
newTick = 0.75;
h.Ticks = sort([h.Ticks newTick]);
If you want to add a line to the bar, the easiest thing (I think) is to use an annotation which is positioned relative to the figure (the same as the colorbar), so we can overlay it
pos = h.Position;
r = (newTick - min(h.Ticks))/(max(h.Ticks)-min(h.Ticks));
annotation( 'line', pos(1)+[0, pos(3)], [1, 1]*(pos(2)+pos(4)*r), ...
'color', [1,0,0], 'linewidth', 2 );
I'm setting the x position of the annotation to match the left and right sides of the colorbar, and the y position to match the bottom plus the relative % of the height according to the tick value.
Result:
Similarly, you could use annotatation exclusively to just get a red label, it's a little more convoluted to get everything lined up correctly, you have to make sure the text box is wide enough to be on a single line and vertically aligned to the middle to get the position right:
h = colorbar;
newTick = 0.75;
pos = h.Position;
r = (newTick - min(h.Ticks))/(max(h.Ticks)-min(h.Ticks));
h = 0.2;
annotation( 'textbox', [pos(1)+pos(3)/2, (pos(2)+pos(4)*r)-(h/2), pos(3)*2, h], ...
'color', [1,0,0], 'string', ['- ' num2str(newTick)], 'linestyle', 'none', ...
'VerticalAlignment', 'middle' );
I would like to know how to draw the following meshes in such color in Matlab. The images are extracted from Microsoft paper on Kinect (link). It seems there is no default colormap of these sort. Do I need to create a new colormap?
The image shown is from figure 1, where they write that the lighting is Phong-shaded renderings (greyscale). This is what you call "silver-colored", i.e. colormap('gray') combined with reflections.
A quick google search suggests you looking at https://se.mathworks.com/matlabcentral/fileexchange/35240-matlab-plot-gallery-change-lighting-to-phong/content/html/Lighting_Phong.html
I've tried to make a custom milky colormap.
trisurf(tri, vertex(:, 1), vertex(:, 2), vertex(:, 3), 0, 'edgecolor', 'none');
axis equal;
axis vis3d;
light('Position', [0 0 1], 'Style', 'infinite');
colormap jet;
map = [0.83,0.82,0.78
1,1,1];
colormap(map);
lighting phong;
The result goes like this,
I would like to add labels to some points plotted using the command scatter. For the sake of simplicity, let's say I have only one point:
x = 10;
pointSize = 100;
fontSize = 20;
P = scatter(x, 0, pointSize, [0,0,0], 'filled');
text(x, 0, 'pointLabel',...
'HorizontalAlignment', 'center',...
'VerticalAlignment', 'bottom',...
'FontSize', fontSize);
The problem with the previous commands is that the text pointLabel overlaps with the point P depending on the values assigned to the properties pointsize and fontSize.
I have read the documentation of the text command, but the examples only show how to put a label horizontally aligned with a specific point in the diagram. If the alignment needs to be horizontal it is easy, but I could not find a general way to compute the y coordinate of the label pointLabel from the values of the other dimensions.
Clearly I can reach a good alignment by testing various combinations of values, but I am looking for a general solution.
Is there anyone who can help me?
This assumes you are using >=R2014b, though it can also be accomplished in older versions using set and get commands.
When a text object is created, its default units are data coordinates, but those can be changed. In your case, I'd go with points.
x = 10;
pointSize = 100;
fontSize = 20;
P = scatter(x, 0, pointSize, [0,0,0], 'filled');
t = text(x, 0, 'pointLabel',...
'HorizontalAlignment', 'center',...
'VerticalAlignment', 'bottom',...
'FontSize', fontSize);
% It's always a good idea to switch back to the default units, so remember them.
originalUnits = t.Units;
t.Units = 'points';
% Shift the text up by the sqrt(pi)/2 times the radius of the point
t.Position(2) = t.Position(2) + sqrt(pointSize)/2;
t.Units = originalUnits;
Check out Text Properties for more info. If you want to get really sophisticated, you can use the read-only property Extent and your known marker size and position to calculate when a label is overlapping one of your points. Since the default unit is in data space, no conversions are necessary.
If you're working with an older version of MATLAB, all of these options and properties are still available, you just have to work a little harder to use them. For instance, you can't direction set the position as above, but you would instead use get to assign it to a temporary variable, change it, and then use set to update. More lines of code, but ultimately the same effect.
I have a very simple script that plots some random stuff and puts a textbox with background color. I am attempting to change the transparency of the background so that the plot shows through.
I have the following code:
x = rand(10);
plot(sin(x))
a = annotation('textbox', [0.5 0.5 0.1 0.1], 'String', 'Some Random Text');
set(a, 'BackgroundColor', [.7 .9 .7]);
set(a, 'FaceAlpha', 0.5);
And it results in an image like this:
So obviously the transparency has worked because part of the background colour is transparent.
Why is all of it not transparent? Have I done something wrong here?
Update: Mathworks confirmed that it probably is a bug which might be fixed in 2014b (to be released in July 2014). A temporary workaround is:
plot(sin(rand(10)))
a = annotation('textbox', [0.5 0.5 0.1 0.1], 'String', 'Some Random Text');
b = annotation('textbox', get(a,'Position'));
set(b, 'BackgroundColor', [0 0.5 0]);
set(b, 'FaceAlpha', 1);
uistack(a,'top')
One annotation for the text and below another for the background color.
It might be a Matlab bug actually. The documentation about annotations says:
FaceAlpha
Scalar alpha value in range [0 1] Transparency of object background.
Defines the degree to which the object's background color is
transparent. A value of 1 (the default) makes the background opaque, a
value of 0 makes the background completely transparent (that is,
invisible). The default value is 1.
I would conclude that the whole background should be affected but I can confirm that this is not the case also here (Matlab 2012b). I might file a bug report with them.
For a temporary fix, set the backgroundcolor as bright as possible ([0.9, 0.9, 0.9] for example) then one doesn't see the effect immediately.
I'm trying to make the red bands in the second subplot of the figure below go transparent with an opacity similar to alpha(0.2).
http://i.stack.imgur.com/zJjYk.jpg
However, when I try to call alpha(0.2) after the following code that generates the red bands:
Plotha1 = area([datenum(time(11,1),1,1) datenum(time(15,1),1,1)],[1.3*max(SA(:,2)) 1.3*max(SA(:,2))]);
set(Plotha1,'BaseValue',1.3*min(SA(:,2)),'FaceColor','r','LineStyle', 'none');
Plotha2 = area([datenum(time(4,1),1,1) datenum(time(8,1),1,1)],[1.3*max(SA(:,2)) 1.3*max(SA(:,2))]);
set(Plotha2,'BaseValue',1.3*min(SA(:,2)),'FaceColor','r','LineStyle', 'none');
alpha(0.2);
The third subplot goes blank like in the second figure.
http://i.stack.imgur.com/tjgIT.jpg
The code generating the third subplot comes last in my code:
subplot(3,1,3),
W = zeros(T,1);
PlotZeros = plot(datenum(time,1,1),W);
dateFormat = 'yyyy';
datetick('x',dateFormat);
hold on
PlotResid = plot(datenum(time,1,1),Resid);
set(PlotZeros,'Color',[0.5 0.5 0.5]); %grey
set(PlotResid,'Color','blue');
axis([datenum(time(1,1),1,1) datenum(time(end,1),1,1) 1.3*min(Resid) 1.3*max(Resid)])
hold off
I have tried moving things around so that the code generating the 2nd subplot comes last but it still causes the 3rd subplot to go blank. Does anyone know how to make these areaseries red bands go transparent without disrupting the 3rd subplot?
Thanks!
You could try using fill or patch with the 'facealpha' property instead of the area command:
% x and y vals define the 4 corners of the rectangle
% (slightly different than "area")
x_vals=[datenum(time(4,1),1,1) datenum(time(8,1),1,1) ...
datenum(time(8,1),1,1) datenum(time(4,1),1,1)];
y_vals=[1.3*min(SA(:,2)) 1.3*min(SA(:,2)) ...
1.3*max(SA(:,2)) 1.3*max(SA(:,2))];
Plotha2 = fill(x_vals,y_vals,'red','edgecolor','none','facealpha',0.2);