Is there any way to access and set plot marker property in Matlab?
In some case especially when user defined Marker is used (like the image below), it is necessary to set NodeLabel's position, font and color, to make it distinct in the figure.
g_obj = graph(sources, targets);
gp = plot(g_obj);
gp is a Matlab GraphPlot object and even though gp.NodeLabel is located in above layer, but has visual interference with user-defined markers' black lines and for example AL1, NAL1 and S6R2 are not readable.
Is there any way to set the Marker's font and position, using the gp itself?
I tried this solution which gives some flexibility, just copied the position and labels then used text instead of NodeLabel with more flexibility in color, font and etc.
%%---
gp = plot(graph_object,'Layout','layered');
labels = gp.NodeLabel;
gp.NodeLabel = [];
gp.LineStyle = 'none'; gp.Marker = 'none';
for i=1:length(labels)
text(gp.XData(i)+2, gp.YData(i)-5,labels(i),...
'fontsize', 8,'FontName', 'Arial', 'Color',[0 0.25 0],...
'FontWeight', 'bold');
end
Related
The preceding figure was produced by the following code:
hold on;
plot([1,2,3,4],[1,2,3,4]);
plot([1,2,3,4],[4,3,2,1]);
legend('foo', 'bar', 'location', 'eastoutside');
Re-scaling the width of the figure window causes the legend to maintain it's dimensions, while automatically scaling the plot's width to take up the extent of the remaining space:
When editing the position properties of the legend, the location property is changed to 'none', losing its unique scaling behavior.
Is there any way to reproduce the scaling behavior in such a way that I could resize/re-position the legend and/or use it for a non axis-legend relationship?
You can get the position of the axes and set the position of the legend relative to them. Here is an example:
x = -10:10;
fig = figure(1);
plot(x,x.^2,x,x.^3);
hL = legend('foo','bar');
% setting the position to the bottom right corner of the axes:
ax = gca;
hL.Position(1:2) = [sum(ax.Position([1 3]))-hL.Position(3) ax.Position(2)];
To keep the position updated upon resizing of the figure you can assign the position set to the SizeChangedFcn property of the figure:
fig.SizeChangedFcn = ...
'hL.Position(1:2) = [sum(ax.Position([1 3]))-hL.Position(3) ax.Position(2)];';
any resize of the figure will update the legend position.
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 noticed that sometimes, when I plot the bars using the functions bar() or hist(), the bars plotted have no border. They are a little bit less nice to see, and I would prefer the border or a little bit of space between them.
The figure shows what I got now, plotting three different datasets. The third graph is zoomed in order to show the lack of space between bars.
I get there this has something to do with the 'histc' parameters in bar function. Without the histc parameters the bars have some space between each others, but then the bar will be centered on the edges values, whereas I want the edges values to be, well, EDGES of each bar.
This is (the relevant part of) the code I used:
[...]
if edges==0
%these following lines are used to take the min and max of the three dataset
maxx=max(cellfun(#max, reshape(data,1,size(data,1)*size(data,2))));
minn=min(cellfun(#min, reshape(data,1,size(data,1)*size(data,2))));
edges=minn:binW:maxx+binW;
end
[...]
y{k}=histc(data{r,c}, edges);
bar(edges,y{k} , 'histc');
[...]
I think if you change the color of your bar plots you'll see that there actually is a border it just doesn't show up very well. You can also change the width of the bars so that they are more distinct.
% something to plot
data = 100*rand(1000,1);
edges = 1:100;
hData = histc(data,edges);
figure
subplot(2,1,1)
h1 = bar(edges,hData,'histc');
% change colors
set(h1,'FaceColor','m')
set(h1,'EdgeColor','b')
% Change width
subplot(2,1,2)
h1 = bar(edges,hData,0.4,'histc');
The EdgeColor and LineWidth properties of the Barseries object control the bar outlines. Try using the code and playing with the red, green, blue, and width values to get a better result.
red = 1;
green = 1;
blue = 1;
width = 3;
h = bar(edges,y{k} , 'histc');
set(h,'EdgeColor',[red green blue],'LineWidth',width);
I'm displaying a 3D scatterplot, but label on the z-axis is getting overlapped by the color bar. How can I shift the color bar a desired number of pixels to the right or left?
You can use findobjto get an handle to the colorbar, query its current position via get and then modify according to your needs and change it using set:
h = findobj('tag', 'Colorbar');
pos = get(h, 'position')
% modify pos according to your needs
set(h, 'position', pos)
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...