I use the function rose2 in my script in order to plot a rose plot. I am working with Matlab 2016a and thus still use the rose function. I use rose2 in order to be able to set the maximum value for the r axis and fill the triangles.
I use "findall" in order to rotate the location of the R-axis labels.
This works very well:
maxHistogramValue = 100;
f=figure;
clf
% Set the max value to maxHistogramValue:
polar(0, maxHistogramValue,'-k')
% Set the location of the R-axis labels in degrees.
% Extract all of the 'Text' objects from the polar plot.
ax = findall(f.Children, 'Type', 'Axes');
% Filter the 'Text' objects by the 'HorizontalAlignment' property.
% PLEASE NOTE: This may not generalize to other versions of MATLAB
% where the default 'HorizontalAlignment' value for R-axis labels is not
% set to 'left'.
labels = findall(ax, 'Type', 'Text', 'HorizontalAlignment', 'left');
% Set the degrees of the R-axis Labels.
degrees = 285;
% Update the position of each R-axis label.
for label = labels'
currentX = label.Position(1);
currentY = label.Position(2);
radius = sqrt(currentX^2 + currentY^2);
newX = cos(degtorad(degrees)) * radius;
newY = sin(degtorad(degrees)) * radius;
label.Position = [newX, newY];
end
hold on;
% Now use rose2:
rose2(inp, theta_rad)
%make transparent
alpha(0.5)
view(-90,90)
And I figured out how to change the font size with:
labels = findall(ax, 'Type', 'Text');
for label = labels'
label.FontSize = 16;
end
But I want to display the angles with the degree symbol.
I tried to add it to the loop, but first, weired numbers are displayed and second, it also changes the r Axis, which I dont want of course.
labels = findall(ax, 'Type', 'Text');
for label = labels'
label.FontSize = 16;
label.String=label.String+char(176);
end
Can anyone help please???
Thank you!
If you look at labels you will see that it contains more labels. You only want to modify labels(1:12):
labels = findall(ax, 'Type', 'Text');
for label = labels(1:12)'
label.String=[label.String char(176)];
end
Also, your label.String=label.String+char(176); is not matlab syntax.
Try alpha(0.5), either in the rose2 function or at the bottom of your script to get the transparency you want.
Also, try polaraxes to define the font size.
ax = polaraxes;
ax.FontSize = 25;
Related
I am trying to get the location of axis TickValues from a MATLAB figure. For example, I have a figure as follows:
I am trying to find the location of axis TickValues after I save the figure as an image (shown in figure) [Note: The bounding boxes are handcrafted. Ignore any error]
Here is the code I generated so far:
h = plot(1:10);
hFrame = getframe(h.Parent.Parent);
hImage = hFrame.cdata;
set(h.Parent,'Units','pixel');
I am trying to get bounding boxes for x-axis TickValues and y-axis TickValues on hImage from the position of h.Parent.
Let me know if the question is not clear yet. I will edit to make it clearer.
As #suever suggested in comments, the Position property of the axes will be the simplest way to do that:
h = plot(1:10);
pos = h.Parent.Position; % get the axes position
m = 3; % width and hight multiplyer
xth = h.Parent.XAxis.TickLength(2); % get x-axis tick hight
dimx = [pos(1)-xth pos(2)-xth*m pos(3)+xth*2 xth*m];
annotation('rectangle',dimx,'color','r') % for demonstration
yth = h.Parent.YAxis.TickLength(2); % get y-axis tick hight
dimy = [pos(1)-yth*(m-1) pos(2)-yth yth*(m-1) pos(4)+yth*2];
annotation('rectangle',dimy,'color','r') % for demonstration
Demonstration:
and you can change m to be sure that all the tick values are within the bounding box.
EDIT:
Option 2:
Option 3:
I want to add a marker/special tick mark in my MATLAB colorbar. For example, lets say I have a colorbar scale from -2 to 3 and my critical value is -1.8, how can I add a marker of the value by symbol/marker?
One way to do this is to fetch the colorbar position, compute the location where you want your marker, and place an annotation object (like an arrow) there:
% Plot sample data, displaying color bar and getting its limits:
data = peaks();
imagesc(data);
hBar = colorbar();
cLimits = caxis();
hold on;
% Select and plot a point of interest:
point = [31 15];
value = data(point(1), point(2));
plot(point(2), point(1), 'r+');
% Compute location of color bar pointer and make annotation:
barPos = get(hBar, 'Position');
xArrow = barPos(1)+barPos(3)/2+[0.05 0];
yArrow = barPos(2)+barPos(4)*(value-cLimits(1))/diff(cLimits)+[0 0];
hArrow = annotation('textarrow', xArrow, yArrow, ...
'String', num2str(value, '%.2f'), 'Color', 'r');
If the figure is resized, the position of the annotation object may shift with respect to the color bar. One way to avoid this is to tweak the axes and color bar resize behavior with the following code:
axesPos = get(gca, 'Position');
set(hBar, 'Location', 'manual');
set(gca, 'Position', axesPos);
This should allow the annotation object to stay fixed to the proper spot over the color bar.
Here is yet another option - just add/change the tick label at the specific value:
MarkTxt = '<-Mark';
imagesc(rand(10)-2) % something to plot
colormap('jet')
CB = colorbar;
% in case you DON'T want the value to appear:
value = -1.8;
t = find(CB.Ticks==value);
if ~isempty(t)
CB.TickLabels{t} = MarkTxt;
else
[CB.Ticks,ord] = sort([CB.Ticks value],'ascend');
t = CB.Ticks==value;
CB.TickLabels{t} = MarkTxt;
end
%% OR - in case you want the value to appear:
value = -1.24;
t = find(CB.Ticks==value);
if ~isempty(t)
CB.TickLabels{t} = [CB.TickLabels{t} MarkTxt];
else
[CB.Ticks,ord] = sort([CB.Ticks value],'ascend');
t = CB.Ticks==value;
CB.TickLabels{t} = [CB.TickLabels{t} MarkTxt];
end
Without the value:
With the value:
You can simply add text outside the plotting area and use that for your marker:
A = rand(15);
f=figure;
imagesc(A);
text(7,7,'X','Color','red') % Put a red X in the middle
text(17.5,size(A,1)*(1-A(7,7)),'<marker'); % Set a marker on the colour bar for the middle point
colorbar
Which results in:
I haven't found a way yet to plot a marker over the colour bar, as the colour bar is not one of the plot children which I can use in uistack for some reason.
I am trying to basically copy this graph for practice for my final coming up but I don't understand how to change the font,size or labeling the axis. Simply put, I need to replicate this graph exactly from my code. I need the font to be times new roman and size 18 with a marker size of 8. How would I format my code into this?
This is my code:
clear
clc
x = linspace(0,2);
y1 = sin(2*pi*x);
y2 = exp(-0.5*2*pi*x).*sin(2*pi*x);
figure
subplot(2,1,1);
hPlot1 = plot(x,y1,'rs');
ylabel('f(t)')
set(gca,'YLim',[-1 2],'YTick',-1:1:2,'XTick',0:.5:2)
subplot(2,1,2);
hPlot2 = plot(x,y2,'k*');
xlabel('Time(s)')
ylabel('g(t)')
set(gca,'YLim',[-0.2,0.6],'YTick',[-0.2,0,0.2,0.4,0.6],'XTick',0:.5:2)
The code below:
%// x = linspace(0,2); %// changed that to respect where the markers are on your example figure
x = 0:0.1:2 ;
y1 = sin(2*pi*x);
y2 = exp(-0.5*2*pi*x).*sin(2*pi*x);
figure
h.axtop = subplot(2,1,1) ;
h.plottop = plot(x,y1,'LineStyle','-','Color','r', ...
'Marker','s', ...
'MarkerEdgeColor','k', ...
'MarkerFaceColor','none', ...
'MarkerSize',8) ;
set(gca,'YLim',[-1 2],'YTick',-1:1:2,'XTick',0:.5:2)
h.ylbl(1) = ylabel('\itf(t)') ; %// label is set in "italic" mode with the '\it' tag at the beginning
h.axbot = subplot(2,1,2);
h.plotbot = plot(x,y2,'-ks', ...
'Marker','*', ...
'MarkerEdgeColor','r', ...
'MarkerSize',8) ;
set(gca,'YLim',[-0.2,0.6],'YTick',[-0.2,0,0.2,0.4,0.6],'XTick',0:.5:2)
h.xlbl(1) = xlabel('Time(s)') ;
h.ylbl(2) = ylabel('\itg(t)') ; %// label is set in "italic" mode with the '\it' tag at the beginning
%// create the "text" annotations
h.txttop = text(0.5,1.5, 'Harmonic force \itf(t)=sin(\omegat)' , 'Parent',h.axtop ) ; %// note the 'parent' property set to the TOP axes
h.txtbot = text(0.5,0.3, 'Forced response \itg(t)=e^{\zeta\omegat} sin(\omegat)' , 'Parent',h.axbot ) ; %// note the 'parent' property set to the BOTTOM axes
%// set the common properties for all text objects in one go
set( [h.xlbl h.ylbl h.txttop h.txtbot] , 'FontName','Times New Roman' , 'FontSize',18)
will produce the following figure:
note how the handle of the graphic object were saved and re-used to set properties later on. If multiple graphic object (even different) have the same property, it is possible to assign this property to all the graphic object in one go.
Look at the Matlab text function documentation for more detail on how to place annotations on your figure.
Replace xlabel('Time(s)') by:
xlabel('Time(s)','FontName','TimesNewRoman','FontSize',18)
and do the same for ylabel.
For the marker size, replace hPlot1 = plot(x,y1,'rs'); by
hPlot1 = plot(x,y1,'r-',x(1:5:end),y1(1:5:end),'ks','MarkerSize',8);
and the same for the other plot.
Finally, you can add text to the figure using the text function, e.g.:
text(0.5,1.5,'Harmonic force f(t) = sin(\omega t)')
Again, you can change the font size and font name, as with xlabel and ylabel.
I have an X Y Z dataset.
X and Y are the 2D coordinates and Z is the intensity.
I plot the data using the scatter function:
markerSize=100;
scatter(x,y,markerSize,z,'s','fill');
I use the options 's' and 'fill' to get filled squares.
My problem is the markerSize value corresponds to the area of the marker, and its unit is points (1/72 of one inch).
The marker size is constant, even if I resize the figure plot. So that the gap between the data points increases when I increase the figure size.
What I would like is a constant marker size which is a constant of the axis unit. For instance, the marker size should be 5x5 (5 in X axis and 5 in Y axis).
Thanks for your help.
You want to make the size of markers proportional to the figure size.
The size of markers is controlled by SizeData parameter of the scattergroup object. The size of figure is stored in Position parameter of the figure object. The difficult part is to interactively resize the marker when the figure size is changed. So you need to use ResizeFcn callback and call setmarkersize function that you define.
function [ ] = setmarkersize( src, evnt )
% # get position of the figure (pos = [x, y, width, height])
pos = get(src, 'Position');
% # get the scattergroup object
h = get(get(src,'children'),'children');
% # resize the marker
relativesize = 0.5;
set(h,'SizeData', pos(3)*relativesize);
end
================================================
% # attach the callback to figure
f = figure('ResizeFcn', #setmarkersize);
h = scatter(x,y,markerSize,z,'s','fill');
You will have to set the marker size manually according to the actual figure size on screen. Using axes property Position you can convert data units to relative figure units. In the next step this size can be converted to the absolute size in points on screen. With that information you can set the marker size accordingly. In the following code snippet I've set the x/y axis limits and width/height of the axis to identical values, because the square marker area can only be calculated reasonably if the marker width is equal to the marker height.
Set marker size relative to data units
% test data
x = [25*rand(1,10) 2.5];
y = [25*rand(1,10) 2.5];
z = [rand(1,10) 0.5];
% relative marker size in squared normalized figure units
marker_rel = 5;
%% Set relative marker size (approximately)
scatter(x,y,100,z,'s','fill');
% Set identical x/y limits and set axes height=widht, so that markers
% really represent squares in data units
xlim([0 25]);
ylim([0 25]);
set(gca, 'Units', 'Points');
axpos_pt = get(gca, 'Position');
axpos_pt = [axpos_pt(1) axpos_pt(2) min(axpos(3:4)) min(axpos(3:4))];
set(gca, 'Position', axpos_pt);
grid on;
grid minor;
% Set marker size relative to data units
markerSize = (marker_rel * axpos_pt(3) / diff(xlim))^2;
set(get(gca, 'children'), 'sizedata', markerSize);
As it turns out, the displayed marker size is slightly smaller than expected. Obviously, there's some bounding box of unknown (at least to me) size, see here.
An alternative approach is to plot rectangles "manually" as shown in the following code snippet (same test data is used). When the figure is resized, the rectangles are resized as well without any special callback function being needed.
Draw rectangles manually
%% Use rectangles (exact)
figure;
axes;
cmp = colormap;
z_range = max(z) - min(z);
line_style = 'none'; % set to '-' to make the edges visible
for k = 1:length(x)
x_pos = x(k) - marker_rel/2;
y_pos = y(k) - marker_rel/2;
w = marker_rel;
h = marker_rel;
color = cmp( round(((z(k) - min(z))/z_range)*(length(cmp) - 1)) + 1, : );
rectangle('Position', [x_pos y_pos w h], 'FaceColor', color,...
'LineStyle', line_style);
end
grid on;
grid minor;
The above code produces the desired marker size:
In general, these are no squares. They can (and will) only be squares if xlim = ylim and absolute height of axis = absolute width of axis. I have shown in my first code snippet how to achieve this.
I found an answer on the Matlab central forum which does not use the useful dsxy2figxy function. Here is the link to it (link)
The code is the following:
x = rand(1,50);
y = rand(1,50);
s = 5; %Marker width in units of X
h = scatter(x,y); % Create a scatter plot and return a handle to the 'hggroup' object
%Obtain the axes size (in axpos) in Points
currentunits = get(gca,'Units');
set(gca, 'Units', 'Points');
axpos = get(gca,'Position');
set(gca, 'Units', currentunits);
markerWidth = s/diff(xlim)*axpos(3); % Calculate Marker width in points
set(h, 'SizeData', markerWidth^2)
The answer by ysakamoto doesn't work in Matlab 2014, where Mathworks changed figure handles from double to object. The following modification makes it work again:
function [ ] = setmarkersize( src, ~ )
% get position of the figure (pos = [x, y, width, height])
pos = get(src, 'Position');
% marker size
relativesize = 0.01;
% axes is not necessarily the only child of figure (e.g. colorbar may be first)
for i = 1:numel(src.Children)
if strcmpi(src.Children(i).Type, 'axes')
% make marker size depend on figure width
src.Children(i).Children.SizeData = pos(3) * relativesize;
break
end
end
end
Also, when creating the figure it will not set the marker size to the correct value until resized. So call setmarkersize explicitly:
f = figure('ResizeFcn', #setmarkersize);
...
setmarkersize(f)
Consider abandoning 'markers' and drawing directly on the axis using rectangles or circles. The 'rectangle' command with 'curvature' set to [1 1] is essentially an open circle. Units are in plot units, so each rectangle can be scaled:
rectangle('position', [rectCentX rectCentY widthInPlotUnits, heightInPlotUnits],'curvature',[1 1])
I'm using subplot which contains three different plots. Each plot has its own labels and title.
The problem is that I have to maximize the plot when I save it. Otherwise, the texts will overlap each other.
When I maximize it, the subplot's label text will appear little blurry in the image, even if I use ESP format or any vector format.
How can I resolve this issue?
For the title overlap issues, you can produce multiple lines of title text use a cell array of strings as the input parameter of title():
title_text = {'first line', 'second line', 'third line'};
title(title_text);
And it works for label text too.
In addition to Da Kuang's answer, if you would like to keep your titles and labels on the same line, you could change the font size
a = axes;
t = title('My Really Long Title');
l = xlabel('My Really Long x label')
set(t, 'FontSize', 8)
set(l, 'FontSize', 8)
I'm not sure why your labels are blurry, but I can help with the overlap.
I never use subplot when I want to save images (eg. for a paper). What I do instead is create each axes individually, which allows a lot more control over each of them.
Below is a rather general example, which illustrates how to generate an arbitrary grid of axes with much finer control over their placement than subplot allows. Of course, with only 3 axes, you don't really need the loop, but I'm sure you can adapt this to fit your needs.
% first create the figure
figPos = [200 200 800 500];
figure('Color', 'w', 'Position', figPos)
% next, determine how much padding you want on each side of the axes, and in
% between axes. I usually play around with these, and the figure size until
% the layout looks correct.
leftPadding = 50/figPos(3); % the space at the left of the figure
rightPadding = 25/figPos(3); % the space at the right of the figure
horizPadding = 80/figPos(3); % the space between axes (horizontally)
topPadding = 30/figPos(4); % the space at the top of the figure
bottomPadding = 50/figPos(4); % the space at the bottom of the figure
vertPadding = 120/figPos(4); % the space between axes (vertically)
% set up the grid size
nHorizAxes = 2;
nVertAxes = 3;
% figure out how big each axes should be
horizPlotSpace = 1-leftPadding-rightPadding-(nHorizAxes-1)*horizPadding;
vertPlotSpace = 1-topPadding-bottomPadding-(nVertAxes-1)*vertPadding;
width = horizPlotSpace/nHorizAxes;
height = vertPlotSpace/nVertAxes;
myAxes = zeros(nVertAxes, nHorizAxes);
% create some sample data to plot for illustrative purposes
x = linspace(0, 2*pi);
y = sin(x);
for iRow = 1:nVertAxes
for iCol = 1:nHorizAxes
% calculate the position
left = leftPadding+(iCol-1)*(width+horizPadding);
bottom = bottomPadding+(iRow-1)*(height+vertPadding);
position = [left bottom width height];
myAxes(iRow, iCol) = axes('Position', position);
plot(x, y)
xlabel('Test Label')
ylabel('Test Label')
title(sprintf('axes(%d, %d)', iRow, iCol))
end
end
Those answers should help but here are some other things to try, depending on the cause of the overlapping text:
Change the figure's size so there's room for the text. For example:
set(gcf, 'PaperSize', [5 7])
Change the size of the subplots.
s = get(gca, 'Position');
set(gca, 'Position', [s(1), s(2), s(3), s(4) * 0.5])
MATLAB (R2021b) appears to stop updating the size of subplots after the axes function is used to set the current axes. The following code causes the title to be cut off.
sp1 = subplot(2, 1, 1);
sp2 = subplot(2, 1, 2);
axes(sp1) % Set the current axes to the first subplot.
title(sprintf('Hello\nCruel\nWorld'))
On the other hand, if title is called immediately after the first subplot is opened, without using axes, then the title has sufficient space to be completely visible.
sp1 = subplot(2, 1, 1);
title(sprintf('Hello\nCruel\nWorld'))
sp2 = subplot(2, 1, 2);
As a workaround, if you need to set the values for a prior subplot, you can simply pass sp1 as the first argument of the desired function.
sp1 = subplot(2, 1, 1);
sp2 = subplot(2, 1, 2);
title(sp1, sprintf('Hello\nCruel\nWorld'))
Simple you can use below function :
plt.tight_layout()
description: The tight_layout() function in pyplot module of matplotlib library is used to automatically adjust subplot parameters to give specified padding.
note : always use this function before plt.show() function.