add tabs (spaces) to strings in plots for Octave / Matlab - matlab

How can I add tabs (spaces) to strings for plots in Octave see code below. It doesn't create a tab (There should be a tab between Signal and Max Freq in the plot)
Also it produces warning messages
warning: text_renderer: skipping missing glyph for character '9'
warning: called from
annotation>update_textbox at line 1080 column 11
annotation at line 248 column 7
clf
plot(0:0)
var=456
t1='Signal ';
t2=[char(9), 'Max Freq'];
t3=[char(10), 'nextline',num2str(var)];
str=strcat(t1,t2,t3);
annotation('textbox',...
[0.15 0.65 0.3 0.15],...
'String',{str},...
'FontSize',14,...
'FontName','Arial',...
'LineStyle','--',...
'EdgeColor',[1 1 0],...
'LineWidth',2,...
'BackgroundColor',[0.9 0.9 0.9],...
'Color',[0.84 0.16 0]);
Ps: I'm using Octave 4.2.2 on Ubuntu 18.04 64bit

I added t4 for blanks...doesn't look very nice. Also note I am using Matlab, not Octave so I didn't get your error. Not sure about that.
clf
plot(0:0)
var=456
t1='Signal ';
t4 = blanks(5);
t2=[char(9),t4, 'Max Freq'];
t3=[char(10), 'nextline',num2str(var)];
str=strcat(t1,t2,t3);
annotation('textbox',...
[0.15 0.65 0.3 0.15],...
'String',{str},...
'FontSize',14,...
'FontName','Arial',...
'LineStyle','--',...
'EdgeColor',[1 1 0],...
'LineWidth',2,...
'BackgroundColor',[0.9 0.9 0.9],...
'Color',[0.84 0.16 0]);

Related

Gnuplot: categorised data - match color to data add range lines

Given a set of values fitting into a category, I'd like to
a) plot the data values as dots (y axis) according to category (x axis)
b) match dot color to category
c) add a line ranging from minimum to maximum of each set
What I did, was using this code:
set terminal png
set output 'animals.png'
set ytics nomirror
unset key
set xrange [-0.5:5.5]
plot for [i=2:5] 'cat.dat' using i:xtic(1)
show xrange
That successfully labels by category on the x-axis, but colors are set according to column (not row) and I would not know how to add the range bars (note: not errorbars or percentiles, but the full min->max range)- especially since the data is called columnwise but would then need to be analysed rowwise. AFAIK gnuplot does columns only, though.
Any ideas?
Output with above code:
Example data (tab-delimited):
cat 0.26 0.4 0.23 0.16
dog 0.317 0.264 0.25 0.26
bat 0.33 0.42 0.32 0.48
rat 0.59 0.62 0.57 0.56
foo 0.59 0.67 0.71 0.70
bar 0.664 0.75 0.68 0.6
As you noticed, gnuplot doesn't like rows and unfortunately does not (yet?) offer a transpose function. In your solution, you are using Unix system calls/tools and sed, which are not necessarily platform independent. Furthermore, you are plotting points and separate arrows to connect, I guess you can simplify this by linespoints if you don't insist on a horizontal bar at the minimum and maximum values.
Let me show some "simplified" platform-independent gnuplot-only code.
General Procedure:
load file to datablock
transpose datablock
plot columns with linespoints
Datafile TAB-separated without header: Animals.dat
cat 0.26 0.4 0.23 0.16
dog 0.317 0.264 0.25 0.26
bat 0.33 0.42 0.32 0.48
rat 0.59 0.62 0.57 0.56
foo 0.59 0.67 0.71 0.70
bar 0.664 0.75 0.68 0.6
The code below requires a FileToDatablock routine and a DatablockTranspose routine.
Procedure to load file into datablock: FileToDatablock.gpp
### Load datafile "as is" into datablock for different platforms
# ARG1 = input filename
# ARG2 = output datablock
if (GPVAL_SYSNAME[:7] eq "Windows") { # "Windows_NT-6.1" is shown on a Win7 system
load '< echo '.ARG2.' ^<^<EOD & type "'.ARG1.'"'
}
if (GPVAL_SYSNAME eq "Linux") { # that's shown on a Raspberry
load '< echo "\$Data << EOD" & cat "'.ARG1.'"'
}
if (GPVAL_SYSNAME eq "Darwin") { # this was shown on a MacOS Sierra 10.12.6
load '< echo "\$Data << EOD" & cat "'.ARG1.'"' # identical to Linux
}
### end of code
gnuplot procedure for transposing a datablock: DatablockTranspose.gpp
### transpose datablock (requires whitespace as separator)
# ARG1 = Input datablock
# ARG2 = Output datablock
set print #ARG2
do for [DBT_i=1:words(#ARG1[1])] {
DBT_Line = ""
do for [DBT_j=1:|#ARG1|] {
DBT_Line = DBT_Line.word(#ARG1[DBT_j],DBT_i).\
(DBT_j < |#ARG1| ? "\t" : "")
}
print DBT_Line
}
set print
undefine DBT_*
### end of code
The actual code:
### plotting rows
reset session
# load file to datablock
call "FileToDatablock" "Animals.dat" "$Data"
# transpose datablock by gnuplot procedure
call "DatablockTranspose.gpp" "$Data" "$DataTransposed"
set palette defined ( 0 'purple', 1 'blue', 2 'green', \
3 'yellow', 4 'orange', 5 'red' , 6 'black' )
unset colorbox
set xrange[0.5:|$Data|+0.5]
plot for [i=1:|$Data|] $DataTransposed u (i):i:(i):xtic(columnhead(i)) w lp pt 7 ps 1.5 lc palette not
### end of code
The result:
This takes a few more steps, above all, each category is given a unique index number, and the data is transposed:
(I'll refer to GNU unix shell commands here)
$cat -n data_orig.dat | datamash transpose > data_trans.dat
$cat data_trans.dat #added spaces for readability
1 2 3 4 5 6
cat dog bat rat foo bar
0.26 0.317 0.33 0.59 0.59 0.664
0.4 0.264 0.42 0.62 0.67 0.75
0.23 0.25 0.32 0.57 0.71 0.68
0.16 0.26 0.48 0.56 0.70 0.6
Now the data can be properly analyzed in columns and colors be defined according to the index number.
The bars are made with arrows, where minimum and maximum are taken from the statistical analysis of each column.
The xticlabels are read into a 1D word array (this is an internal gnuplot function) with a system call and the array indices are made to match the unique indices of the data columns.
The script with very detailed explanations to better support new gnuplot users:
#output and style settings: make png-file, name it 'animals.png',
# yaxis tics on both sides, no legend
set terminal png
set output 'animals.png'
set ytics mirror
unset key
#data indices are integers from 1 to 6, a bit of space for the looks
set xrange [0.5:6.5]
#define color scheme for each data series
set palette defined ( 0 'purple', 1 'blue', 2 'green', \
3 'yellow', 4 'orange', 5 'red' , 6 'black' )
#hide color gradient bar of palette
unset colorbox
#define array names using word function:
# read in 2nd line of data by system call and run through words
# each space-delimited word is now an array element of names
names(n) = word( system("sed -n '2p' cat.dat_t" ) , n )
#create min->max bars
#loop over all data sets to create bars
do for [i=1:6] {
#among others this gives minimum and maximum values of the data set
#using i -> only handle column i in statistics
#every ::3 start with row 3 for statistical analysis
stats 'data_trans.dat' using i every ::3
#use min/max values for arrow y positions, index i for x positions
#heads = arrow head on both sides
#size 0.1,90 = 0.1 line lengths for arrow head
# and 90° arrow head line angles = T bar style
#lc palette cb i = use line color (lc) from palette value matching
# color bar (cb) value of index i
set arrow from i,STATS_min to i,STATS_max heads size 0.1,90 lc palette cb i
}
#plotting:
# for [i=1:6] loop over all 6 columns, use i as loop variable
# every ::3 start with row 3 for data plotting
# using (i):i:(i):xtic(names(i))
# syntax of using
# x-value:y-value:z-value:label_x_axis [:label_y_axis:label_z_axis]
# (i) -> literal value of i for x and z, z is used as color definition
# i -> y-values from column i
# xtic(names(i)) get element i of array names for xtic label
# lc palette -> coloring according to defined palette
# pt 7 ps 1.5 -> point style and size definition
plot for [i=1:6] 'data_trans.dat' every ::3 using (i):i:(i):xtic(names(i)) lc palette pt 7 ps 1.5
References:
coloring based on x-values
array from word function
Result:
EDIT:
As shown in #theozh 's answer, linespoints are far more practicable for showing the range. This allows skipping the whole bar/arrow creation block by just adding w lp in the plotting command line.

Printing Outputs Like table in Matlab

disp('iteration xl xu xr £a(%)');
xu=10;
xl=0;
xrpv=0;er=0;
f=#(x)(5*exp(0.5*x)+10-x^3.5);
for i=1:1:200;
xr=(xl+xu)/2;
fxr=f(xr);
er=((xr-xrpv)/xr)*100;
xrpv=xr;
if abs(er)<10^-6
disp(abs(er));
break
end
if (f(xl)*f(xr)>0)
xl=xr;
else
xu=xr;
end
fprintf('&d %f %f %f %f',i,xl,xu,xr,er)
end
i am trying the make table from outputs in for loop like;
xl xr xu ea%
0 5 10 100
1 * * *
2 * * *
An easy way to plot aligned text in the command window is to use tabs.
I recommend using fprintf for the header too.
I changed the first and 20th line:
fprintf('it. \t xl \t xu \t xr \t ea%%\n');
xu=10;
xl=0;
xrpv=0;er=0;
f=#(x)(5*exp(0.5*x)+10-x^3.5);
for i=1:1:200
xr=(xl+xu)/2;
fxr=f(xr);
er=((xr-xrpv)/xr)*100;
xrpv=xr;
if abs(er)<10^-6
disp(abs(er));
break
end
if (f(xl)*f(xr)>0)
xl=xr;
else
xu=xr;
end
fprintf('%3d \t%.1f \t%.1f \t%.1f \t%.1f\n',i,xl,xu,xr,er)
end
And the result is this:
it. xl xu xr ea%
1 0.0 5.0 5.0 100.0
2 2.5 5.0 2.5 -100.0
3 2.5 3.8 3.8 33.3
4 2.5 3.1 3.1 -20.0
5 2.5 2.8 2.8 -11.1
...
A similar result could be obtained by saving i,xl,xu,xr,er on each line of a matrix that could be displayed as a table.
You could also use a table variable as a storage variable that could be displayed as you asked but this depends on how you are using the data in the following code.

Collapse/mean data in Matlab with respect to a different set of data

I have two sets of data, but the sets have a different sizes.
Each set contains the measurements itself (MeasA and MeasB, both double) and the time point (TimeA and TimeB, datenum or julian date) when the measuring happened.
Now I want to match the smaller data set to the bigger one, and to do this, I want to mean the data points of the bigger set around the data resp. time points of the smaller set, to finally do some correlation analysis.
Edit:
Small Example how the data would look like:
MeasA = [2.7694 -1.3499 3.0349 0.7254 -0.0631];
TimeA = [0.2 0.4 0.7 0.8 1.3];
MeasB = [0.7147 -0.2050 -0.1241 1.4897 1.4090 1.4172 0.6715 -1.2075 0.7172 1.6302];
TimeB = [0.1 0.2 0.3 0.6 0.65 0.68 0.73 0.85 1.2 1.4];
And now I want to collapse MeasB and TimeB so that I get the mean of the measurement close to the timepoints in TimeA, so for example TimeB should look like this:
TimeB = [mean([0.1 0.2]) mean([0.3 0.6]) mean([0.65 0.68 0.73]) mean([0.85]) mean([1.2 1.4])]
TimeB = [0.15 0.4 0.69 0.85 1.3]
And then collapse MeasB like this too:
MeasB = [mean([0.7147 -0.2050]) mean([-0.1241 1.4897]) mean([1.4090 1.4172 0.6715]) mean([-1.2075]) mean([0.7172 1.6302])];
MeasB = [0.2549 0.6828 1.1659 -1.2075 1.1737]
The function interp1 is your friend.
You can get a new set of measurement for your set B, at the same time than set A by using:
newMeasB = interp1( TimeB , MeasB , TimeA ) ;
The first 2 parameters are your original Time and Measurements of the set you want to re interpolate, the last parameter is the new x axis (time in your example) on which you want the interpolated values to be calculated.
This way you do not end up with different sets of time between your 2 sets of measurements, you can compare them point by point.
Check the documentation of interp1 for more explanations and for options about the interpolation or any potential extrapolation.
edit:
Matlab doc used to have a great illustration of the function but I can't find it online so here goes:
So with the linear method, if the value is interpolated exactly between 2 points, the function will return the exact mean. If the interpolation is done closer to one point than another, the value returned will be proportionally closer to the value of the closest point.
The NaN can appear on the sides (beginning or end of returned vector) if the TimeA was not completely overlapped by timeB. The function cannot "interpolate" because there is no anchor point. However, the different options of interp1 allow you to "extrapolate" outside of the input range, or to assign another default value instead of the NaNs.

How to read data from file and store into matrix

I have two txt files that are 1.txt and 2.txt. It stores data such as
1.txt:
P_e = [-0.1 0.71 0.88;-0.09 0.59 0.839;-0.08 0.55 0.816;-0.07 0.546 0.811;-0.06 0.46 0.769]
and data in 2.txt is
P_e = [-0.1 0.5 0.6;-0.09 0.1 0.2;-0.08 0.3 0.4;-0.07 0 01;-0.06 0 0]
I want to cacluate sum of P_e variables column by column,except column 1 in 1.txt and 2.txt and store it into P_e_sum variable.
-0.1 0.71+0.5 0.88+0.6
-0.09 0.59+0.1 0.839+0.2
-0.08 0.55+0.3 0.816+0.4
-0.07 0.546+0 0.811+0
-0.06 0.46+0 0.769+0
So the result is
Pe_sum=[ -0.1 1.21 1.48;
-0.09 0.69 1.039;
-0.08 0.85 1.216
-0.07 0.546 0.811;
-0.06 0.46 0.769]
Could you help me to implement it by matlab? Thank you so much
Its going to be hard to read those in as text. But the contents of those text files are basically formatted as matlab scripts anyway. Rename them to .m then you can just do this:
run ('1.m')
p1 = P_e;
run ('2.m')
p2 = P_e;
pSum = [p1(:, 1), (p1(:, 2:end) + p2(:, 2:end))];
Will do what you want.
As a side note, consider not naming these files just 1.txt Matlab doesn't agree with numeric first file names.

Starting the graph lines at the same place

I'm trying to get the green line in the following Matlab code to start from the same point as the other two ones WITHOUT shifting the whole figure to the left, i.e the starting point shouldn't
be attached to the y axis. But I cannot figure out how to. If anyone could help explain how to do it, I'd greatly appreciate the help. :)
all_local = [ 1.0001 1.0001 1.0001 1.0001];
mix_diff_paragraphs = [ 0.59 0.93 0.97 1.0001];
mix_same_paragraphs = [ 0.35 0.55 0.80 1.0001];
axis manual
axis([1,4,0,2]);
y=[1 2 3 4];
h = plot(y+1,all_local,'-om',...
y+1,mix_diff_paragraphs,'-xb',...
y,mix_same_paragraphs,'-+g','LineWidth',2,'MarkerSize',8);
set(gca,'xtick', [1 2 3 4 5]);
set(gca,'XTickLabel',{0,300,500,1000,1500});
set(gca,'ytick', 0:0.2:1.2);
set(gca,'yticklabel', {'0', '0.2', '0.4', '0.6', '0.8','1',''});
legend('Location','BEST','Local users only','Local/Remote users alternate on Pargs.','Local/Remote users modify the same Parg.')
ylabel('Responsiveness');
xlabel('Thinking Period(msec)')
grid on;
That's quite a messy way to do what you did (I don't see why you'd want to change the tick labels without changing the actual x values), but this aside, just add (+1) to the green line:
h = plot(...
...
y+1 ...,'LineWidth',2,'MarkerSize',8);
and in the end add: xlim([1,5]);
If I understood correctly what you were trying to do...