Related
I have a matrix of points named start_coord containing their x and y coordinates, as well as a column denoting their classification (1-5). I.e. the first row looks like [75, 100, 4].
I've calculated a voronoi diagram of this data using the code below
[vc_x, vc_y] = voronoi(start_coord(:,1), start_coord(:,2));
How would I go about coloring the resulting polygons by the classification value of the point contained within each polygon, i.e. the third column in start_coord?
EDIT
For quick plotting of polygons by color reference the answer in the comments below, which helped inform this edit. For getting the voronoi polygons for thousands of points written to an array that can be saved as an image refer to this code:
new_map = zeros(sm_size(1), sm_size(2));
start_coord = readmatrix(char(join([csv_path, '/', run_types(run), common_name_csv], "")));
sc_size = size(start_coord);
dt = delaunayTriangulation(start_coord(:,1:2));
[V,R] = voronoiDiagram(dt);
for i = 1:sc_size(1)
A=V(R{i},:);
B=A(any(~isinf(A),2),:); % omit points at infinity
bw = poly2mask(B(:,1), B(:,2), sm_size(1), sm_size(2));
new_map(bw == 1) = color_map(start_coord(i,3));
end
new_map can then be saved as an array or converted to RGB and saved as an image.
Use voronoiDiagram to get the polygons.
dt = delaunayTriangulation(start_coord(:,1:2));
[V,R] = voronoiDiagram(dt);
Then R{i} will be the vertices of polygon from start_coord(i,:)
So set the color to start_coord(i,3)'s color and:
A=V(R{i},:);
B=A(any(~isinf(A),2),:); % omit points at infinity
plot(polyshape(B));
The only hiccup there is that the vertices at infinity get chopped off. But maybe that will get you close enough to what you want. If you need to fill to the edge, check out the VoronoiLimit function (which I have not tested).
e.g.:
X = [-1.5 3.2; 1.8 3.3; -3.7 1.5; -1.5 1.3; ...
0.8 1.2; 3.3 1.5; -4.0 -1.0;-2.3 -0.7; ...
0 -0.5; 2.0 -1.5; 3.7 -0.8; -3.5 -2.9; ...
-0.9 -3.9; 2.0 -3.5; 3.5 -2.25];
X(:,3) = [ 1 2 1 3 1 2 2 2 2 3 3 3 3 3 3]';
ccode = ["red","green","blue"];
dt = delaunayTriangulation(X(:,1:2));
[V,R] = voronoiDiagram(dt);
figure
voronoi(X(:,1),X(:,2))
hold on
for i = 1:size(X,1)
A=V(R{i},:);
B=A(any(~isinf(A),2),:);
if(size(B,1)>2)
plot(polyshape(B),'FaceColor',ccode(X(i,3)));
end
end
Result:
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.
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]);
Here is my model:
Solving this problem, I used GA in matlab
function F = sim_fit(q,k,m)
%retailer
a(1,1)=3;a(2,1)=2;a(3,1)=3;a(1,2)=1;a(2,2)=1.1;a(3,2)=9;
d(1,1)=1850;d(2,1)=2000;d(3,1)=3000;d(1,2)=2100;d(2,2)=1300;d(3,2)=900;
hr(1,1)=2.4;hr(2,1)=1.3;hr(3,1)=38;hr(1,2)=4.5;hr(2,2)=3.6;hr(3,2)=45;
so(1,1)=3.5;so(2,1)=1.5;so(3,1)=2.5;so(1,2)=0.3;so(2,2)=0.6;so(3,2)=6.3;
t(1,1)=1;t(2,1)=1;t(3,1)=3;t(1,2)=1;t(2,2)=1;t(3,2)=3;
E(1,1)=2;E(2,1)=2;E(3,1)=10;E(1,2)=2;E(2,2)=2;E(3,2)=10;
Y(1,1)=3;Y(2,1)=3;Y(3,1)=11;Y(1,2)=3;Y(2,2)=3;Y(3,2)=11;
%vendor
S=100;
hv(1)=3.5;hv(2)=4;
C(1)=10; C(2)=50;
Cv(1)=2.4; Cv(2)=3;
Cf(1)=3; Cf(2)=1.2;
s(1)=0.3; s(2)=0.1;
the(1)=0.01; the(2)=0.03;
dv(1)=sum(d(1,1)+d(1,2));dv(2)=sum(d(2,1)+d(2,2));
Q(1)=sum(q(1,1)+q(1,2));Q(2)=sum(q(2,1)+q(2,2));
P(1)=10000; P(2)=8000;
%function
for j=1:2
for i=1:2
F= S*dv(i)/(Q(i)*m(i,j))+(hv(i)*Q(i)*((m(i)-1)*(1-dv(i)/P(i))+dv(i)/P(i)))/2+...
dv(i)*(m(i)*C(i)+m(i)*Q(i)*Cv(i)+Cf(i))+m(i)*s(i)*dv(i)*Q(i)*the(i)/2+...
a(i,j).*d(i,j)./q(i,j)+(hr(i,j).*((1-k(i,j)).^2).*q(i,j))./2+...
k(i,j).^2.*so(i,j).*q(i,j)./2+(m(i)*t(i,j).*d(i,j))./q(i,j)+(m(i)*E(i,j).*d(i,j))./q(i,j)+...
Y(i,j).*d(i,j);
end
end
end
function [C, ceq] = sim_constraint(q,k,m)
B(:,1)=200;B(:,2)=300;
W(:,1)=100;W(:,2)=100;
b(1)=10; b(2)=14;
w(1)=1; w(2)=1.5;
P(1)=10000; P(2)=8000;
C=[(m(1).*q(1,1).*b(1)+m(2).*q(2,1).*b(2))-B(:,1);
(m(1).*q(1,2).*b(1)+m(2).*q(2,2).*b(2))-B(:,2);
(m(1).*q(1,1).*w(1)+m(2).*q(2,1).*w(2))-W(:,1);
(m(1).*q(1,2).*w(1)+m(2).*q(2,2).*w(2))-W(:,2);
m(1)*Q(1)-P(1);m(2)*Q(2)-P(2)
k(1,1)-1;k(1,2)-1;k(2,1)-1;k(2,2)-1];
ceq=[d(1,1)+d(1,2)-dv(1);(d(2,1)+d(2,2))-dv(2);
(q(1,1)+q(1,2))-Q(1);(q(2,1)+q(2,2))-Q(2)];
end
First, I don't know how to input Xij which is binary variable in sim_fitness function.
Second, in order to solve this problem, I use Optimization Toolbox.
Error message said "need more input variable."
How can I fix it?
This is not an answer to your question. But please, please start using matlab as it was intended:) If it was this cumbersome, then people would not be using it.
The net happiness of the human race will increase if you change your existing code to something like this:
function F = sim_fit(q,k,m)
%retailer
a=[3 2 3; 1 1.1 9].'; %or a=[3 1; 2 1.1; 3 9];
d=[1850 2000 3000; 2100 1300 900].';
hr=[2.4 1.3 38; 4.5 3.6 45].';
so=[3.5 1.5 2.5; 0.3 0.6 6.3].';
t=[1 1 3; 1 1 3].';
E=[2 2 10; 2 2 10].';
Y=[3 3 11; 3 3 11].';
%vendor
S=100;
hv=[3.5 4];
C=[10 50];
Cv=[2.4 3];
Cf=[3 1.2];
s=[0.3 0.1];
the=[0.01 0.03];
dv=sum(d(1:2,:),2).'; %row vector like the earlier ones
Q=sum(q(1:2,:),2).';
P=[10000 8000];
%function
for j=1:2
for i=1:2
F= S*dv(i)/(Q(i)*m(i,j))+(hv(i)*Q(i)*((m(i)-1)*(1-dv(i)/P(i))+dv(i)/P(i)))/2+...
dv(i)*(m(i)*C(i)+m(i)*Q(i)*Cv(i)+Cf(i))+m(i)*s(i)*dv(i)*Q(i)*the(i)/2+...
a(i,j).*d(i,j)./q(i,j)+(hr(i,j).*((1-k(i,j)).^2).*q(i,j))./2+...
k(i,j).^2.*so(i,j).*q(i,j)./2+(m(i)*t(i,j).*d(i,j))./q(i,j)+(m(i)*E(i,j).*d(i,j))./q(i,j)+...
Y(i,j).*d(i,j);
end
end
end
function [C, ceq] = sim_constraint(q,k,m)
B=[200 300];
W=[100 100];
b=[10 14];
w=[1 1.5];
P=[10000 8000];
mtmp=reshape(m(1:2),1,[]); %since I don't know its size, be on the safe side
qtmp=q(1:2,1:2); %same thing here
%WHAT IS Q?
%WHAT IS d?
%WHAT IS dv?
C=[((mtmp.*b)*qtmp - B).';
((mtmp.*w)*qtmp - W).';
(mtmp.*Q-P).'; %assuming Q is of size [1, 2]
reshape(k(1:2,1:2).',4,1)-1];
ceq=[sum(d(1:2,1:2),2)-dv.';
sum(q(1:2,1:2),2)-Q.']; %assuming Q is of size [1, 2]
end
Sorry, I didn't have it in me to decrypt your expression for F. I strongly suggest getting familiar with the basic array syntax of matlab, and checking for yourself whether I made any mistakes during the conversion of your code. If you learn how to work with matrices and vectors, expressions like what you have for F can be radically simplified.
Also, the definition of the variables Q, d and dv seem to be missing from your second function. Those aren't globals, are they?
How to perform a TukeyHSD post-hoc test after the Anova in Matlab, and get a table with the sorted grouped pairs using letters?
Example:
X has 3 treatments (columns) obtained in 4 replications (rows):
x=[9 1 3.1
5 2 3.2
7 1.1 3
8 1.2 3]
The one-way ANOVA:
[p,a,s] = anova1(x)
And the multcompare result:
[c,m,h,nms] = multcompare(s)
How to get a result like this?
treatment mean Tukey_group
1 7.2500 a
2 1.3250 b
3 3.0750 b
Please see a similar example in R:
https://stats.stackexchange.com/questions/31547/how-to-obtain-the-results-of-a-tukey-hsd-post-hoc-test-in-a-table-showing-groupe
I think I have a solution. I developed a Matlab function for this:
Example:
x=[9.0 1.0 3.1
5.0 2.0 3.2
7.0 1.1 3.0
8.0 1.2 3.0];
Sorting x in crescent order
[me or]=sort(mean(x),2);
xo=x(:,or);
ANOVA
[p,a,s] = anova1(xo);
Multcompare using HSD Tukey at 5% significance:
[c,m,h,nms] = multcompare(s,'alpha',0.05,'ctype','hsd');
Post-hoc grouping using the developed function:
phg = phgroup(xo,c);
The developed function phgroup:
function phg = phgroup(xo,c)
%
% Input:
% x: data matrix with treatments in rows and observations in columns
% c: matrix of pairwise comparison results from multcompare test
%
% WARNING: is indispensable that the means of x matrix are sorted in crescent order.
%
% Getting significant pairwise comparisons
gr=1;
for i=1:size(c,1)
if c(i,3)>0&&c(i,5)>0||c(i,3)<0&&c(i,5)<0
tt(c(i,2),c(i,1))=0;
gr=gr+1;
else
tt(c(i,1),c(i,1))=gr;
tt(c(i,2),c(i,1))=gr;
end
end
% Setting groups if all non-significant
if isempty(find(tt>0))==1
for i=1:size(tt,1)
gr=gr+1;
tt(i,i)=gr;
end
end
% Setting groups if some non-significant
for i=1:size(tt,1)
if isempty(find(tt(i,:)>0))==1
tt(i,i)=gr+1;
gr=gr+1;
end
end
% Correcting repeated groups
for i=1:size(tt,2)-1
if max(find(tt(:,i+1)>0))==max(find(tt(:,i)>0))
tt(find(tt(:,i+1)>0),i+1)=tt(i,i);
end
end
mx=max(tt);
for i=1:size(tt,2)-1
if max(tt(:,i+1))==mx(i)
tt(find(tt(:,i+1)>0),i+1)=0;
end
end
% Setting sequential groups
[B,IX] = sort(nonzeros(max(tt))');
for l=1:size(tt,1)
for c=1:size(tt,2)
if tt(l,c)>0
for u=1:size(B,2)
if tt(l,c)==B(u)
tt(l,c)=IX(u);
end
end
end
end
end
% Assigning letters to groups
gn=['a';'b';'c';'d';'e';'f';'g';'h';'i';'j';'k';'l';'m';'n';'o';'p';'q';'r';'t';'u';'v';'w';'x';'y';'z'];
for i=1:size(tt,1)
tg=[];
ttu=nonzeros(unique(tt(i,:)))';
for j=1:size(ttu,2)
tg=[tg gn(ttu(1,j))];
TG{i,1}=tg;
end
end
% Getting output table
m1=[mean(xo);std(xo)]';
m1=[num2cell(m1) TG];
me1=['mean';m1(:,1)];
st=['std';m1(:,2)];
gr=['group';m1(:,3)];
phg=[me1 st gr];