MATLAB Answers

0

Plot text on line with angle

Asked by jacob Dyer on 10 Oct 2019
Latest activity Edited by Adam Danz
on 14 Oct 2019
I'm looking for the following in relation to plotting text,
1) I want to plot text on top of a line or curve for any given function.
2) I want the angle of the text to match the angle of the slope of the line or curve at a given point (i.e. line overlaps (text height)/2 for the entire length of the text).
3) The text "wipes out" or hides the line where the text is located. (Can you add a fill behind the text? Not sure if this is possible
4) if a "wipe out" isn't possible, I would like to plot the text above the line
5) I would Still like the text angle to match the angle of the line/curve slope at a given point.
6) For ease, lets just say the text is any given input, I can extrapolate from there.
7) Bonus points for a separate assistance for curving the text along a curve, but the former items should satisfy my needs.
Any help is greatly appreciated.

  6 Comments

yeah you'll probably want that. Here you are. I've inserted the code in the previous comment here such that you can just copy and paste the script from this comment and discard the previous script.
p_psi = 14.48; % See Site Specific ASHRAE Climate Data
%% Constants and Conversions
a1 = -1.021416462e4;
a2 = -4.89350301;
a3 = -5.37657944e-3;
a4 = 1.92023769e-7;
a5 = 3.55758316e-10;
a6 = -9.03446886e-14;
a7 = 4.1635019;
a8 = -1.044039708e4;
a9 = -1.12946496e1;
a10 = -2.7022355e-2;
a11 = 1.289036e-5;
a12 = -2.478068e-9;
a13 = 6.5459673;
p_atm = p_psi*2.036021;
%%%%%%%%%%%%% RELATIVE HUMIDITY GRAPH %%%%%%%%%%%%%%
for n=1:10
RH=10*n;
for i=1:121
Tdb(n,i)=i-1;
t(n,i)=Tdb(n,i)+459.67;
if Tdb(n,i) < 32
p_sat(n,i) = exp(a1/t(n,i)+a2+a3*t(n,i)+a4*t(n,i)^2+a5*t(n,i)^3+a6
*t(n,i)^4+a7*log(t(n,i)));
else
p_sat(n,i) = exp(a8/t(n,i)+a9+a10*t(n,i)+a11*t(n,i)^2+a12*t(n,i)^3+a13
*log(t(n,i)));
end
p_sat(n,i)=p_sat(n,i)*2.036021;
p_part(n,i)=(RH*p_sat(n,i))/100;
w(n,i)=0.62198*(p_part(n,i)/(p_atm-p_part(n,i)));
end
Tx=80;
Tx1=Tx-1;
Tx2=Tx+1;
slope=(w(n,Tx2)-w(n,Tx1))/(Tx2-Tx1);
pi=3.14;
txt_angle=zeros(10,121);
txt_angle=atand(slope);
plot(Tdb(n,:), w(n,:),'Color',[0.6350 0.0780 0.1840],'LineWidth',.5)
txt=text(Tdb(n,Tx),w(n,Tx),'TEST','HorizontalAlignment','center')
%dir=[1 0 0]
%rotate(txt,dir,txt_angle)
set(txt,'Rotation',txt_angle)
hold on
end
hold on
axis([32 120 0 .03])
xlabel('Dry-Bulb Temperature (degF)')
ylabel('Humidity Ratio (lb_w/lb_a)')
title('Psychrometric Chart')
darova
on 10 Oct 2019
It's because of scaling X = 0 .. 120; Y = 0 .. 0.03
img1.png
Try
slope=(w(n,Tx2)-w(n,Tx1))/(Tx2-Tx1) * 120/0.03;
Adam Danz
on 11 Oct 2019
See my updated answer. The slope calculation needs to account for the difference in x and y axis scales (as Darova mentioned).
Remember that 1 unit of slope describes the amount of rise along the y axis for every unit of lateral movement along the x axis. So, if the x and y axes have different scales, you've got to adjust the slope.
Since the slope depends on axis scaling, the axis dimensions need set prior to plotting and they cannot change ("hold on").

Sign in to comment.

1 Answer

Answer by Adam Danz
on 10 Oct 2019
Edited by Adam Danz
on 11 Oct 2019

"I'm looking for the following in relation to plotting text,"
1) I want to plot text on top of a line or curve for any given function.
2) I want the angle of the text to match the angle of the slope of the line or curve at a given point (i.e. line overlaps (text height)/2 for the entire length of the text).
Assuming you want the text centered above point (x,y) and you know the slope of point (x,y), compute the angle from the slope and use the angle to set the rotation property of the text. Then set the HorizontalAlignment and VerticalAlignment properties to 'center' and 'bottom'.
3) The text "wipes out" or hides the line where the text is located. (Can you add a fill behind the text? Not sure if this is possible
4) if a "wipe out" isn't possible, I would like to plot the text above the line
Set the BackgrondColor property to white; or, better yet, set the BackgroundColor to the axis color: get(gca, 'color'). Note that the background extent is a bit larger than the actual text size so it may not appear aesthetically pleasing.
"7) Bonus points for a separate assistance for curving the text along a curve, but the former items should satisfy my needs."
See comment below!
[update after your recent comment under the question]
Here are the changes you need to make to your code:
  1. Move the axis definition to before the loops at the start of "Relative Humidity Graph" section. : axis([32 120 0 .03])
  2. Place the hold on immediately after the axis() definition and remove all other hold on's.
  3. Compute your slope as the line below. It computes the slope at the point where the text is located and it accounts for the difference in axis limits.
  4. Why pi=3.14? Matlab's built in pi is much more precise.
  5. Remove the rotate() function and assign the 'rotation' property and the 'VerticalAlignment' property direction to text(); see line below.
%Slope line
slope= (diff(w(n,Tx+[-1,0])) / diff(Tdb(n,Tx+[-1,0]))) / (range(ylim(gca))/range(xlim(gca)));
% Text line
txt=text(Tdb(n,Tx),w(n,Tx),'TEST','HorizontalAlignment','center','VerticalAlignment', 'bottom','rotation',txt_angle)
191011 083226-Figure 1.png

  1 Comment

Adam Danz
on 10 Oct 2019
"7) Bonus points for a separate assistance for curving the text along a curve, but the former items should satisfy my needs."
This demo below shows that it's possible but messy (at least when done quickly). I doubt the added complexity is worth the hassle and potential problems. For example, if the curve asymptotes it may get ugly.
This quickly written, poorly thought-out demo comes with some limiting assumptions.
It is assumed that you have the function of the line. It is assumed that the axes are linear and it requires that the aspect ratio is equal. Nevertheless, the text curves with the line. Surely improvements can be made to make this more generalizable. For example, the linear axes assumption can be replaced with appropriate scaling of the text positions. The requirement to have the equation of the line will be tough to eliminate but interpolation could come in handy. These additions would further increase the complexity which would further tip the cost-benefit scale IMO.
Note that Matlab already has internal processes to wrap text along curved lines. For example, see the contour function. However, these processes aren't applicable to text objects (yet?).
% Create figure and data
figure()
eq = @(x)x.^4; % Equation for the line
x = 0:.01:1;
y = eq(x);
plot(x,y)
hold on
%Choose a point along the line
p = 90; % index value
% Plot the curve
plot(x(p),y(p),'k*')
% This quick demo requires equal aspect ratio but it could be
% adapted to scale
axis equal %important for this demo
% Plot the text label horizontally for now.
% We'll use this to measure its dimensions
% I recommend using a monospace font such as consolas or monospaced
% since letters have various widths in other fonts.
h = text(x(p), y(p), 'Text label','HorizontalAlignment','center',...
'VerticalAlignment','Bottom','FontName','consolas','FontSize',9);
% Get approximate angle of slope at point p (radians)
% There are better ways to get this: see gradient()
pAng = atan((y(p)-y(p-1)) / (x(p)-x(p-1)));
xExt = cos(pAng) * h.Extent(3); %this is the x-extent after the text is rotated
%Compute width per char (assuming str is just 1 line); in x-axis units
nchar = numel(h.String); %number of characters
wpch = xExt/nchar;
% wpch = h.Extent(3)/nchar; %alternative
%Compute x&y coordinates along the line for each character,
% We'll compute an additional coordinate in order to compute slope later
% Assumes linear X and Y axes !
charPosX = linspace(x(p)-wpch*(ceil(nchar/2)+1), x(p)+wpch*floor(nchar/2), nchar+1);
charPosY = eq(charPosX); %Use equation of the line
% Get slope|angle at each coordinate (quick and dirty way)
slope = diff(charPosY)./diff(charPosX);
% Compute the angle of the text
ang = atan(-1./slope)*180/pi +90;
% Write the letters individually using monospaced font, again
hh = text(charPosX(2:end), charPosY(2:end), num2cell(h.String), 'HorizontalAlignment','center','VerticalAlignment','Bottom',...
'FontName','consolas','FontSize',9);
% Rotate each letter
set(hh, {'Rotation'}, num2cell(ang'))
% Remove initial text
delete(h)
191010 152241-Figure 3.png

Sign in to comment.