merge?
@@ -27,7 +27,7 @@ classdef Signal
|
||||
|
||||
[~,obj.gitSHA] = system('git rev-parse HEAD');
|
||||
[~,obj.gitStatus] = system('git status --porcelain');
|
||||
[~,obj.gitPatch] = system('git diff');
|
||||
% [~,obj.gitPatch] = system('git diff');
|
||||
|
||||
%%% Stuff for Logbook %%%
|
||||
SignalType = [];
|
||||
@@ -379,7 +379,7 @@ classdef Signal
|
||||
%xlim([-obj.fs/2 obj.fs/2].*1e-9)
|
||||
edgetick = 2^(nextpow2(obj.fs*1e-9));
|
||||
xticks([-edgetick:16:edgetick]);
|
||||
xlim([100*round( min(w.*1e-9)/100,1)-10,100*round( max(w.*1e-9)/100,1)+10])
|
||||
xlim([100*round( min(w)/100,1)-10,100*round( max(w)/100,1)+10])
|
||||
else
|
||||
xlabel("Normalized Frequency");
|
||||
xlim([-pi, pi]);
|
||||
@@ -510,7 +510,7 @@ classdef Signal
|
||||
end
|
||||
|
||||
%%
|
||||
function [obj,S] = tsynch(obj,options)
|
||||
function [obj,S,isFlipped] = tsynch(obj,options)
|
||||
% time sync and cut
|
||||
arguments
|
||||
obj Signal
|
||||
@@ -525,14 +525,16 @@ classdef Signal
|
||||
q = obj.fs/options.fs_ref;
|
||||
b = options.reference.resample("fs_in",options.fs_ref,"fs_out",obj.fs).normalize("mode","oneone").signal;
|
||||
|
||||
max_occurences = floor(length(a)/length(b));
|
||||
|
||||
%estimate delay between signals
|
||||
[co,lags] = xcorr(a,b);
|
||||
[~,pos] = max(co);
|
||||
[~,pos] = max(abs(co));
|
||||
D = lags(pos);
|
||||
|
||||
%estimate start pos of signal
|
||||
maxpeaknum = floor(length(a)/length(b));
|
||||
[pks,pkpos] = findpeaks(co./max(co),'MinPeakDistance',length(b)/2,'MinPeakHeight',0.2,'NPeaks',maxpeaknum);
|
||||
[pks,pkpos] = findpeaks(abs(co./max(co)),'MinPeakDistance',length(b)/2,'MinPeakHeight',0.2,'NPeaks',maxpeaknum);
|
||||
shifts = lags(pkpos);
|
||||
|
||||
%Cut occurences of ref signal from signal (only positive shifts)
|
||||
@@ -543,9 +545,19 @@ classdef Signal
|
||||
S{end+1,1} = sig;
|
||||
end
|
||||
|
||||
%
|
||||
isFlipped=0;
|
||||
if all(sign(co(pkpos)))
|
||||
isFlipped = 1;
|
||||
end
|
||||
|
||||
%return/keep the sinal with the highest correlation (only within positive shifts)
|
||||
[~,idx]=max(pks(shifts>0));
|
||||
obj.signal = S{idx}.signal;
|
||||
%put signal with highest corr. to first index in S array
|
||||
swap = S{1};
|
||||
S{1} = S{idx};
|
||||
S{idx} = swap;
|
||||
|
||||
for c = 1:numel(shifts(shifts>0))
|
||||
S{c}.logbook = [];
|
||||
|
||||
@@ -202,19 +202,19 @@ classdef ChannelFreqResp < handle
|
||||
function plot(obj)
|
||||
|
||||
figure(55);
|
||||
clf;
|
||||
%clf;
|
||||
|
||||
Havg = obj.H;
|
||||
|
||||
%1)
|
||||
subplot(2,1,1);hold all;box on;title('Magnitude Freq. Response');
|
||||
subplot(2,1,1);hold on;box on;title('Magnitude Freq. Response');
|
||||
plot(obj.faxis/1e9, 20*log10(abs(obj.H_all)),'linewidth',0.1,'LineStyle','-','Color','#808080') ;
|
||||
xlim([0.2 .5*max(obj.faxis)*1e-9]);
|
||||
plot(obj.faxis/1e9, 20*log10(abs(Havg)),'LineWidth',2);
|
||||
grid on;
|
||||
|
||||
%2)
|
||||
subplot(2,1,2); hold all; box on; title('Phase Freq. Response');
|
||||
subplot(2,1,2); hold on; box on; title('Phase Freq. Response');
|
||||
plot(obj.faxis/1e9, angle(obj.H_all),'linewidth',0.1,'LineStyle','-','Color','#808080') ;
|
||||
plot(obj.faxis/1e9, unwrap(angle(Havg)),'LineWidth',2) ;
|
||||
xlim([0.2 .5*max(obj.faxis)*1e-9]);
|
||||
@@ -228,7 +228,7 @@ classdef ChannelFreqResp < handle
|
||||
Havg = Havg./mean(Havg(2:10));
|
||||
|
||||
%3)
|
||||
subplot(2,1,1); hold all; box on; title('Inverse Magnitude Freq. Response');
|
||||
subplot(2,1,1); hold on; box on; title('Inverse Magnitude Freq. Response');
|
||||
plot(obj.faxis/1e9, 20*log10(abs(1./Havg)),"LineWidth",2,"Color",[0.3467 0.5360 0.6907]) ;
|
||||
xlim([0.2 .5*max(obj.faxis)*1e-9]); grid on;
|
||||
ylim([-1 15]);
|
||||
@@ -236,15 +236,17 @@ classdef ChannelFreqResp < handle
|
||||
yline(3,'LineWidth',2,'LineStyle','--');
|
||||
|
||||
%4)
|
||||
subplot(2,1,2); hold all; box on; title('Inverse Phase Freq. Response');
|
||||
subplot(2,1,2); hold on; box on; title('Inverse Phase Freq. Response');
|
||||
plot(obj.faxis/1e9, unwrap(angle(1./Havg)),"LineWidth",2,"Color",[0.3467 0.5360 0.6907]) ;
|
||||
xlim([0.2 .5*max(obj.faxis)*1e-9]); grid on;
|
||||
|
||||
%%% plot for publication
|
||||
figure(98989);hold all;box on;title('Magnitude Freq. Response');
|
||||
xlim([0.2 .5*max(obj.faxis)*1e-9]);
|
||||
ylim([-20, 2]);
|
||||
plot(obj.faxis/1e9, 20*log10(abs(Havg)),'LineWidth',2);
|
||||
figure(30);hold on;box on;title('Magnitude Freq. Response');
|
||||
% xlim([0 max(obj.faxis)*1e-9]);
|
||||
% ylim([-20, 10]);
|
||||
fax = obj.faxis - obj.f_ref/2;
|
||||
Havg = Havg ./ max(abs(Havg));
|
||||
plot(fax/1e9, 20*log10(abs(fftshift(Havg)))+7,'LineWidth',2);
|
||||
grid on;
|
||||
|
||||
|
||||
@@ -360,7 +362,7 @@ classdef ChannelFreqResp < handle
|
||||
|
||||
end
|
||||
|
||||
fprintf('Frequency response information successfully loaded from %s\n', fullFileName);
|
||||
% fprintf('Frequency response information successfully loaded from %s\n', fullFileName);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -77,9 +77,42 @@ classdef PAMsource
|
||||
bitpattern=[];
|
||||
|
||||
if obj.useprbs
|
||||
for i = 1:log2(obj.M)
|
||||
[bitpattern(:,i),seed] = prbs(O,N,seed);
|
||||
% for i = 1:log2(obj.M)
|
||||
% [bitpattern(:,i),seed] = prbs(O,N,seed);
|
||||
% end
|
||||
|
||||
%%%%% MOVE-IT PRMS %%%%
|
||||
|
||||
state = struct();
|
||||
|
||||
para = struct();
|
||||
|
||||
if obj.M == 6
|
||||
para.bl = 2^(obj.order-2);
|
||||
para.dimension = 5;
|
||||
else
|
||||
para.bl = 2^(obj.order-1);
|
||||
para.dimension = log2(obj.M); %2.5bits/sym -> 2 bit/sym
|
||||
end
|
||||
|
||||
para.rand = 0;
|
||||
|
||||
para.order = floor(obj.order / log2(obj.M));
|
||||
para.skip =0;
|
||||
para.bruijn = 0;
|
||||
para.reset_prms = 0;
|
||||
para.method = 1;
|
||||
|
||||
data_in = [];
|
||||
global loop;
|
||||
loop = 0;
|
||||
[data_out,state_] = prms(data_in, state, para);
|
||||
loop = 1;
|
||||
[data_out,state_out] = prms(data_in, state_, para);
|
||||
bitpattern = data_out';
|
||||
|
||||
%%%%% END MOVE-IT %%%%%%%
|
||||
|
||||
else
|
||||
s = RandStream('twister','Seed',obj.randkey);
|
||||
for i = 1:log2(obj.M)
|
||||
@@ -88,7 +121,7 @@ classdef PAMsource
|
||||
end
|
||||
|
||||
if obj.M == 6
|
||||
bitpattern = reshape(bitpattern,[],1);
|
||||
bitpattern = reshape(bitpattern',[],1);
|
||||
bitpattern = bitpattern(1:end-mod(length(bitpattern),5));
|
||||
end
|
||||
|
||||
@@ -108,7 +141,7 @@ classdef PAMsource
|
||||
end
|
||||
|
||||
% figure(12);hold on;histogram(symbols.signal,'Normalization','probability');
|
||||
|
||||
|
||||
if obj.mrds_code
|
||||
symbols = MRDS_coding("blocklength",obj.mrds_blocklength).encode(symbols);
|
||||
end
|
||||
@@ -128,7 +161,7 @@ classdef PAMsource
|
||||
%%%%% Re-sample to f DAC %%%%%%
|
||||
digi_sig = digi_sig.resample("fs_in",digi_sig.fs,"fs_out",obj.fs_out,"n",10,"beta",5);
|
||||
|
||||
% digi_sig.spectrum("fignum",111,"displayname","after pulseforming");
|
||||
% digi_sig.spectrum("fignum",111,"displayname","after pulseforming");
|
||||
|
||||
%%%%% Hard clip digital signal to PAM range before DAC %%%%%%
|
||||
if obj.applyclipping
|
||||
|
||||
@@ -164,11 +164,11 @@ classdef Duobinary
|
||||
elseif I == 11
|
||||
%todo
|
||||
data = data .* sqrt(5.8);
|
||||
warning('Check if PAM16 implementation, mapping and scaling is correct!')
|
||||
warning('Check db decode implementation, mapping and scaling is correct!')
|
||||
elseif I == 15
|
||||
data = data .* sqrt(10.5);
|
||||
elseif I == 16
|
||||
warning('Check if PAM16 implementation, mapping and scaling is correct!')
|
||||
warning('Check db decode implementation, mapping and scaling is correct!')
|
||||
end
|
||||
|
||||
data = round(data);
|
||||
|
||||
@@ -7,11 +7,12 @@ classdef Awg2Scope
|
||||
Scope
|
||||
|
||||
mapping;
|
||||
waitUntilClick
|
||||
|
||||
end
|
||||
|
||||
methods (Access=public)
|
||||
function obj = Awg2Scope(Awg,Scope,mapping)
|
||||
function obj = Awg2Scope(Awg,Scope,mapping,options)
|
||||
%Simple class to call the Awg and Scope and map the signals
|
||||
%accordingly in the correct formats with correct l
|
||||
% ogbook
|
||||
@@ -21,16 +22,19 @@ classdef Awg2Scope
|
||||
Awg
|
||||
Scope
|
||||
mapping
|
||||
|
||||
options.waitUntilClick = 0;
|
||||
end
|
||||
|
||||
obj.Awg = Awg;
|
||||
obj.Scope = Scope;
|
||||
|
||||
obj.mapping = mapping; % AWG CH [1,2,3,4] -> Scope CH [0,0,0,1]
|
||||
obj.waitUntilClick = options.waitUntilClick;
|
||||
|
||||
end
|
||||
|
||||
function [S1,S2,S3,S4] = process(obj,channels)
|
||||
function [S1,S2,S3,S4] = process(obj,channels, options)
|
||||
|
||||
arguments
|
||||
obj
|
||||
@@ -41,15 +45,33 @@ classdef Awg2Scope
|
||||
channels.signal4 Informationsignal = Informationsignal([])
|
||||
|
||||
% add new optional arguments here
|
||||
options.waitUntilClick = obj.waitUntilClick;
|
||||
end
|
||||
|
||||
|
||||
|
||||
%%% UPLOAD TO AWG %%%
|
||||
|
||||
[S1,S2,S3,S4]=obj.Awg.upload("signal1",channels.signal1,...
|
||||
"signal2",channels.signal2,...
|
||||
"signal3",channels.signal3,...
|
||||
"signal4",channels.signal4...
|
||||
);
|
||||
|
||||
%%% UPLOAD TO AWG %%%
|
||||
|
||||
scpe_sig_cell = obj.Scope.read();
|
||||
|
||||
|
||||
%%% READ FROM SCOPE %%%
|
||||
|
||||
scpe_sig_cell = obj.Scope.read("waitUntilClick",options.waitUntilClick);
|
||||
|
||||
%%% READ FROM SCOPE %%%
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
% Map Scope measurement to output signal
|
||||
% mapping index is the AWG chanel and mapping number is the
|
||||
|
||||
@@ -176,7 +176,11 @@ classdef AwgKeysight
|
||||
% The waveform granularity is e.g. 128. This means that the waveform length must be a multiple of this granularity. The minimum waveform length is 128 samples.
|
||||
if rem(length(signal{s}),obj.waveformGranularity) ~= 0
|
||||
signal{s} = [signal{s} signal{s}(:,1:(obj.waveformGranularity-rem(length(signal{s}),obj.waveformGranularity)))];
|
||||
warning(['data should have a length multiple of ',num2str(obj.waveformGranularity),'!']);
|
||||
|
||||
debug = 0;
|
||||
if debug
|
||||
warning(['data should have a length multiple of ',num2str(obj.waveformGranularity),'!']);
|
||||
end
|
||||
end
|
||||
|
||||
% Digitally apply skews to the signals
|
||||
|
||||
@@ -51,90 +51,90 @@ classdef DC_supply < handle
|
||||
|
||||
success = [0,0];
|
||||
|
||||
try
|
||||
% %connect to device
|
||||
% if exist('v','var')
|
||||
% %v = visadev("GPIB1::19::INSTR");
|
||||
% v = obj.connectDevice();
|
||||
% else
|
||||
%
|
||||
% end
|
||||
% %connect to device
|
||||
% if exist('v','var')
|
||||
% %v = visadev("GPIB1::19::INSTR");
|
||||
% v = obj.connectDevice();
|
||||
% else
|
||||
%
|
||||
% end
|
||||
|
||||
v = visadev("GPIB1::19::INSTR");
|
||||
v = visadev("GPIB1::19::INSTR");
|
||||
|
||||
debug = 0;
|
||||
if debug
|
||||
disp(['Connected to Instrument: ',char(v.Vendor),' ',char(v.Model),' SerNo:',char(v.SerialNumber)]);
|
||||
end
|
||||
debug = 0;
|
||||
if debug
|
||||
disp(['Connected to Instrument: ',char(v.Vendor),' ',char(v.Model),' SerNo:',char(v.SerialNumber)]);
|
||||
end
|
||||
|
||||
cmd = 'INST:SEL?';
|
||||
cmd = 'INST:SEL?';
|
||||
writeline(v, cmd);
|
||||
prev_selected_channel = readline(v);
|
||||
|
||||
for ch = 1:2
|
||||
|
||||
% choose channel
|
||||
cmd = ['INST:SEL OUT',num2str(ch)];
|
||||
writeline(v, cmd);
|
||||
prev_selected_channel = readline(v);
|
||||
|
||||
for ch = 1:2
|
||||
% get current voltage level
|
||||
cmd = 'VOLT?';
|
||||
writeline(v, cmd);
|
||||
act_volt = str2num(readline(v));
|
||||
|
||||
% choose channel
|
||||
cmd = ['INST:SEL OUT',num2str(ch)];
|
||||
writeline(v, cmd);
|
||||
% desired voltage (round to two digits after comma)
|
||||
des_volt = round(options.voltage(ch),2);
|
||||
|
||||
cnt = 0;
|
||||
while abs(act_volt-des_volt) > 0
|
||||
|
||||
selected_channel = ['OUT',num2str(ch)];
|
||||
|
||||
% get current voltage level
|
||||
cmd = 'VOLT?';
|
||||
writeline(v, cmd);
|
||||
act_volt = str2num(readline(v));
|
||||
|
||||
% desired voltage (round to two digits after comma)
|
||||
des_volt = round(options.voltage(ch),2);
|
||||
% difference
|
||||
diff_volt = act_volt-des_volt;
|
||||
|
||||
cnt = 0;
|
||||
while abs(act_volt-des_volt) > 0
|
||||
|
||||
selected_channel = ['OUT',num2str(ch)];
|
||||
|
||||
% get current voltage level
|
||||
cmd = 'VOLT?';
|
||||
writeline(v, cmd);
|
||||
act_volt = str2num(readline(v));
|
||||
|
||||
% difference
|
||||
diff_volt = act_volt-des_volt;
|
||||
|
||||
% set new voltage
|
||||
increment_voltage = -0.01* sign(diff_volt) ;
|
||||
cmd = ['VOLT ',num2str(act_volt+increment_voltage)];
|
||||
writeline(v, cmd);
|
||||
|
||||
cnt = cnt+1;
|
||||
if mod(cnt,100) == 0
|
||||
wait(1);
|
||||
end
|
||||
|
||||
% get current voltage level
|
||||
cmd = 'VOLT?';
|
||||
writeline(v, cmd);
|
||||
act_volt = str2num(readline(v));
|
||||
% set new voltage
|
||||
increment_voltage = -0.01* sign(diff_volt) ;
|
||||
cmd = ['VOLT ',num2str(act_volt+increment_voltage)];
|
||||
writeline(v, cmd);
|
||||
|
||||
cnt = cnt+1;
|
||||
if mod(cnt,100) == 0
|
||||
pause(1);
|
||||
end
|
||||
|
||||
% check if voltage is set
|
||||
if act_volt ~= des_volt
|
||||
hMsgBox = msgbox('An error occurred in dc supply module. Check if voltage is set correctly.');
|
||||
uiwait(hMsgBox);
|
||||
else
|
||||
success(ch) = 1;
|
||||
end
|
||||
% get current voltage level
|
||||
cmd = 'VOLT?';
|
||||
writeline(v, cmd);
|
||||
act_volt = str2num(readline(v));
|
||||
|
||||
end
|
||||
|
||||
% choose channel
|
||||
cmd = ['INST:SEL ',char(strtrim(prev_selected_channel))];
|
||||
writeline(v, cmd);
|
||||
% check if voltage is set
|
||||
if act_volt ~= des_volt
|
||||
hMsgBox = msgbox('An error occurred in dc supply module. Check if voltage is set correctly.');
|
||||
uiwait(hMsgBox);
|
||||
else
|
||||
success(ch) = 1;
|
||||
end
|
||||
|
||||
%disconnect
|
||||
delete(v);
|
||||
|
||||
catch
|
||||
|
||||
end
|
||||
|
||||
% choose channel
|
||||
cmd = ['INST:SEL ',char(strtrim(prev_selected_channel))];
|
||||
writeline(v, cmd);
|
||||
|
||||
%disconnect
|
||||
delete(v);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
function [voltage,current] = readVals(obj)
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
classdef Exfo_laser
|
||||
classdef Exfo_laser < handle
|
||||
|
||||
properties(Access=private)
|
||||
serialport_number
|
||||
mainframe_channel
|
||||
end
|
||||
properties(Access=public)
|
||||
wavelength
|
||||
power
|
||||
cur_state
|
||||
cur_wavelength
|
||||
cur_power
|
||||
safety_mode
|
||||
end
|
||||
|
||||
methods (Access=public)
|
||||
@@ -11,8 +17,9 @@ classdef Exfo_laser
|
||||
|
||||
|
||||
arguments
|
||||
options.wavelength = 1310; %dbm
|
||||
options.power = -10; %dbm
|
||||
options.safety_mode = 1;
|
||||
options.serialport_number = 'COM8';
|
||||
options.mainframe_channel = 1;
|
||||
end
|
||||
|
||||
%
|
||||
@@ -23,52 +30,330 @@ classdef Exfo_laser
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function success = set(obj,options)
|
||||
|
||||
|
||||
arguments
|
||||
obj
|
||||
options.wavelength = obj.wavelength; %dbm
|
||||
options.power = obj.power; %dbm
|
||||
end
|
||||
|
||||
% Connect to the laser
|
||||
o = serialport("COM8", 9600);
|
||||
configureTerminator(o, "CR"); % Set the terminator to carriage return (CR)
|
||||
o = serialport(obj.serialport_number, 9600);
|
||||
configureTerminator(o, "CR", "CR"); % Set the terminator to carriage return (CR)
|
||||
flush(o);
|
||||
writeline(o, "*IDN?");
|
||||
pause(1);
|
||||
if o.NumBytesAvailable ~= 0
|
||||
disp(['Laser Mainframe: ', readline(o)]);
|
||||
answ = readline(o);
|
||||
|
||||
if obj.safety_mode
|
||||
disp(['Yay! We can talk to Instrument: ',char(answ)]);
|
||||
end
|
||||
|
||||
% Read states the first time
|
||||
obj.cur_state = obj.getLaserStatus_(o,obj.mainframe_channel);
|
||||
obj.cur_wavelength = obj.getLaserWavelength_(o,obj.mainframe_channel);
|
||||
obj.cur_power = obj.getLaserPower_(o,obj.mainframe_channel);
|
||||
|
||||
clear o;
|
||||
|
||||
if obj.safety_mode
|
||||
warning("Safety_mode ON: Display all information. Ask when switching laser. Turn safety_mode off in class instance or during initialization Exfo_laser(...,'safety_mode',0)");
|
||||
else
|
||||
error('No connection to the mainframe');
|
||||
clear o;
|
||||
warning("safety_mode OFF: EVERYTHING IS EXECUTED WITHOUT ASKING :-) BE SURE WHAT YOU DO");
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function [isEnabled,power,lambda] = getLaserInfo(obj)
|
||||
|
||||
o = obj.connectLaser_();
|
||||
|
||||
isEnabled = obj.getLaserStatus_(o,obj.mainframe_channel);
|
||||
|
||||
power = obj.getLaserPower_(o,obj.mainframe_channel);
|
||||
|
||||
lambda = obj.getLaserWavelength_(o,obj.mainframe_channel);
|
||||
|
||||
end
|
||||
|
||||
|
||||
function success = enableLaser(obj)
|
||||
success = 0;
|
||||
o = obj.connectLaser_();
|
||||
|
||||
if obj.safety_mode
|
||||
% Prompt the user to enable the laser
|
||||
choice = questdlg('Do you want to enable the laser?', ...
|
||||
'Enable Laser', ...
|
||||
'Yes', 'No', 'No');
|
||||
else
|
||||
choice = 'Yes';
|
||||
end
|
||||
|
||||
% Handle the response
|
||||
switch choice
|
||||
case 'Yes'
|
||||
% Enable the laser on channel 1
|
||||
success = obj.enableLaser_(o,obj.mainframe_channel);
|
||||
disp('Laser enabled.');
|
||||
case 'No'
|
||||
% Abort the operation
|
||||
disp('Operation aborted. Laser remains disabled.');
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
% Function to set the wavelength of the laser
|
||||
function setLaserWavelength(~,serialObj, channel, wavelength)
|
||||
command = ['CH', num2str(channel), ':L=', num2str(wavelength)];
|
||||
writeline(serialObj, command);
|
||||
pause(0.5); % Allow time for the wavelength to change
|
||||
|
||||
function success = disableLaser(obj)
|
||||
success = 0;
|
||||
o = obj.connectLaser_();
|
||||
|
||||
if obj.safety_mode
|
||||
% Prompt the user to enable the laser
|
||||
choice = questdlg('Do you want to disable the laser?', ...
|
||||
'Enable Laser', ...
|
||||
'Yes', 'No', 'No');
|
||||
else
|
||||
choice = 'Yes';
|
||||
end
|
||||
|
||||
% Handle the response
|
||||
switch choice
|
||||
case 'Yes'
|
||||
% Enable the laser on channel 1
|
||||
success = obj.disableLaser_(o,obj.mainframe_channel);
|
||||
case 'No'
|
||||
% Abort the operation
|
||||
disp('Operation aborted. Laser remains enabled.');
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
function success = setPower(obj,desiredPower)
|
||||
success = 0;
|
||||
o = obj.connectLaser_();
|
||||
|
||||
if obj.safety_mode
|
||||
% Prompt the user to enable the laser
|
||||
choice = questdlg(['Do you want to set the laser to ', num2str(desiredPower) ,' dBm?'], ...
|
||||
'SET POWER', ...
|
||||
'Yes', 'No', 'No');
|
||||
else
|
||||
choice = 'Yes';
|
||||
end
|
||||
|
||||
% Handle the response
|
||||
switch choice
|
||||
case 'Yes'
|
||||
% Enable the laser on channel 1
|
||||
success = obj.setLaserPower_(o,obj.mainframe_channel,desiredPower);
|
||||
case 'No'
|
||||
% Abort the operation
|
||||
disp('Operation aborted. Laser remains at power.');
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
function success = setWavelength(obj,desriedLambda)
|
||||
success = 0;
|
||||
o = obj.connectLaser_();
|
||||
|
||||
if obj.safety_mode
|
||||
% Prompt the user to enable the laser
|
||||
choice = questdlg(['Do you want to set the laser wavelength to ', num2str(desriedLambda) ,' nm?'], ...
|
||||
'SET WAVELENGTH', ...
|
||||
'Yes', 'No', 'No');
|
||||
else
|
||||
choice = 'Yes';
|
||||
end
|
||||
|
||||
% Handle the response
|
||||
switch choice
|
||||
case 'Yes'
|
||||
% Enable the laser on channel 1
|
||||
success = obj.setLaserWavelength_(o,obj.mainframe_channel,desriedLambda);
|
||||
case 'No'
|
||||
% Abort the operation
|
||||
disp('Operation aborted. Laser remains at wavelength.');
|
||||
end
|
||||
end
|
||||
|
||||
end %public mehtods
|
||||
methods (Access=private)
|
||||
|
||||
function serialobj = connectLaser_(obj)
|
||||
% Connect to the laser
|
||||
serialobj = serialport(obj.serialport_number, 9600);
|
||||
configureTerminator(serialobj, "CR", "CR"); % Set the terminator to carriage return (CR)
|
||||
flush(serialobj);
|
||||
writeline(serialobj, "*IDN?");
|
||||
answ = readline(serialobj);
|
||||
|
||||
if obj.safety_mode
|
||||
disp(['Yay! We can talk to Instrument: ',char(answ)]);
|
||||
end
|
||||
end
|
||||
|
||||
% Function to GET the STATE of the laser
|
||||
function isEnabled = getLaserStatus_(obj,serialObj, channel)
|
||||
|
||||
writeline(serialObj, ['CH', num2str(channel), ':ENABLE?']); % Query current wavelength
|
||||
|
||||
manual_flush = 1;
|
||||
while manual_flush
|
||||
response = readline(serialObj);
|
||||
manual_flush = contains(response, {'OK'});
|
||||
end
|
||||
|
||||
isEnabled = 0;
|
||||
isEnabled = contains(response, {'ENABLED'});
|
||||
|
||||
isDisabled = 0;
|
||||
isDisabled = contains(response, {'DISABLED'});
|
||||
|
||||
if isEnabled && ~isDisabled
|
||||
obj.cur_state = isEnabled;
|
||||
elseif ~isEnabled && isDisabled
|
||||
obj.cur_state = isEnabled;
|
||||
else
|
||||
error(['Unknown Laser State ->', char(response)]);
|
||||
end
|
||||
|
||||
if obj.safety_mode
|
||||
if isEnabled
|
||||
disp(['Laser ', num2str(channel) ,' is currently ON -> ', char(response)]);
|
||||
elseif isDisabled
|
||||
disp(['Laser ', num2str(channel) ,' is currently OFF ->', char(response)]);
|
||||
else
|
||||
error(['Unknown Laser State ->', char(response)]);
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
% Function to GET the wavelength of the laser
|
||||
function current_wavelen = getLaserWavelength_(obj,serialObj, channel)
|
||||
|
||||
writeline(serialObj, ['CH', num2str(channel), ':L?']); % Query current wavelength
|
||||
current_wavelen = readline(serialObj);
|
||||
disp(['Current Wavelength: ', current_wavelen]);
|
||||
|
||||
response = readline(serialObj);
|
||||
current_wavelen = str2double(regexp(response, '\d+\.\d+', 'match', 'once'));
|
||||
|
||||
if obj.safety_mode
|
||||
disp(['Current Laser ', num2str(channel) ,' Wavelength: ', num2str(current_wavelen),' --> ',char(response)]);
|
||||
end
|
||||
|
||||
obj.cur_wavelength = current_wavelen;
|
||||
end
|
||||
|
||||
% Function to set the laser power
|
||||
function setLaserPower(~,serialObj, channel, power_dBm)
|
||||
command = ['CH', num2str(channel), ':P=', num2str(power_dBm)];
|
||||
writeline(serialObj, command);
|
||||
pause(0.2); % Allow time for power to adjust
|
||||
% Function to GET the laser power
|
||||
function powerValue = getLaserPower_(obj,serialObj, channel)
|
||||
|
||||
writeline(serialObj, ['CH', num2str(channel), ':P?']); % Query current power
|
||||
current_power = readline(serialObj);
|
||||
disp(['Current Power: ', current_power, ' dBm']);
|
||||
|
||||
response = readline(serialObj);
|
||||
|
||||
isDisabled = contains(response, 'Disabled');
|
||||
|
||||
if ~isDisabled
|
||||
powerValue = str2double(regexp(response, '\d+\.\d+', 'match', 'once'));
|
||||
else
|
||||
powerValue = -200;
|
||||
end
|
||||
|
||||
if obj.safety_mode
|
||||
disp(['Current Laser ', num2str(channel) ,' Power: ', num2str(powerValue), ' dBm --> ',char(response)]);
|
||||
end
|
||||
|
||||
obj.cur_power = powerValue;
|
||||
end
|
||||
|
||||
% Function to enable the laser
|
||||
function success = enableLaser_(obj,serialObj,channel)
|
||||
success = 0;
|
||||
isEnabled = obj.getLaserStatus_(serialObj,obj.mainframe_channel);
|
||||
|
||||
writeline(serialObj, ['CH',num2str(channel),':ENABLE']);
|
||||
response = readline(serialObj);
|
||||
isok = contains(response, {'OK'});
|
||||
|
||||
cnt=0;
|
||||
while ~isEnabled || cnt>10
|
||||
isEnabled = obj.getLaserStatus_(serialObj,obj.mainframe_channel);
|
||||
pause(0.2);
|
||||
cnt = cnt+1;
|
||||
end
|
||||
|
||||
if ~isEnabled
|
||||
error('Laser not enabled but command was send')
|
||||
else
|
||||
success = 1;
|
||||
end
|
||||
end
|
||||
|
||||
% Function to enable the laser
|
||||
function success = disableLaser_(obj,serialObj,channel)
|
||||
success = 0;
|
||||
isEnabled = obj.getLaserStatus_(serialObj,obj.mainframe_channel);
|
||||
|
||||
writeline(serialObj, ['CH',num2str(channel),':DISABLE']);
|
||||
response = readline(serialObj);
|
||||
isok = contains(response, {'OK'});
|
||||
|
||||
cnt=0;
|
||||
while isEnabled || cnt>10
|
||||
isEnabled = obj.getLaserStatus_(serialObj,obj.mainframe_channel);
|
||||
pause(0.2);
|
||||
cnt = cnt+1;
|
||||
end
|
||||
|
||||
if isEnabled
|
||||
error('Laser not enabled but command was send')
|
||||
else
|
||||
success = 1;
|
||||
end
|
||||
end
|
||||
|
||||
% Function to SET the wavelength of the laser
|
||||
function success = setLaserWavelength_(~,serialObj, channel, desiredWavelength_nm)
|
||||
success = 0;
|
||||
|
||||
writeline(serialObj, ['CH',num2str(channel),':NM?']);
|
||||
modeResponse = readline(serialObj);
|
||||
isNMMode = contains(modeResponse, ['CH',num2str(channel),':1']);
|
||||
|
||||
if ~isNMMode
|
||||
warning(['Laser is in GHz Mode, you requested to set Wavelength (nm) -> ',modeResponse])
|
||||
return
|
||||
end
|
||||
|
||||
command = ['CH', num2str(channel), ':L=', num2str(desiredWavelength_nm)];
|
||||
writeline(serialObj, command);
|
||||
|
||||
pause(0.2);
|
||||
|
||||
response = readline(serialObj);
|
||||
success = contains(response, 'OK');
|
||||
|
||||
end
|
||||
|
||||
% Function to SET the laser power
|
||||
function success = setLaserPower_(~,serialObj, channel, desiredPower_dBm)
|
||||
success = 0;
|
||||
|
||||
writeline(serialObj, ['CH',num2str(channel),':MW?']);
|
||||
modeResponse = readline(serialObj);
|
||||
isMWMode = contains(modeResponse, ['CH',num2str(channel),':1']);
|
||||
|
||||
if isMWMode
|
||||
warning('Laser is in MW Mode, you requested to set dBm power')
|
||||
return
|
||||
end
|
||||
|
||||
command = ['CH', num2str(channel), ':P=', num2str(desiredPower_dBm)];
|
||||
writeline(serialObj, command);
|
||||
|
||||
pause(0.2);
|
||||
|
||||
response = readline(serialObj);
|
||||
success = contains(response, 'OK');
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -53,8 +53,11 @@ classdef OptAtten < handle
|
||||
|
||||
try
|
||||
%connect to device
|
||||
|
||||
|
||||
v = visadev('TCPIP::134.245.243.248::INSTR');
|
||||
|
||||
|
||||
debug = 0;
|
||||
if debug
|
||||
disp(['Connected to Instrument: ',char(v.Vendor),' ',char(v.Model),' SerNo:',char(v.SerialNumber)]);
|
||||
@@ -193,8 +196,9 @@ classdef OptAtten < handle
|
||||
differ = abs(state.outputpower(i)-options.value(i));
|
||||
%create msgbox when necessary
|
||||
if differ >= 2
|
||||
hMsgBox = msgbox(['Output Power at attenuator slot ' num2str(2) ' differs by 2dB or more!']);
|
||||
uiwait(hMsgBox);
|
||||
warning(['Output Power at attenuator slot ' num2str(2) ' differs by ', num2str(differ), 'or more!'])
|
||||
% hMsgBox = msgbox(['Output Power at attenuator slot ' num2str(2) ' differs by 2dB or more!']);
|
||||
% uiwait(hMsgBox);
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -212,7 +216,7 @@ classdef OptAtten < handle
|
||||
ch_info_txt = ['OptAtten: ',num2str(i),' -> Attenuated by: ',num2str(options.value(i)),' dB; Cur Output: ',num2str(state.outputpower(i)),'dBm'];
|
||||
disp(ch_info_txt);
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -257,11 +261,6 @@ classdef OptAtten < handle
|
||||
answer = sscanf(line,'%f');
|
||||
obj.power_state(cnt) = answer;
|
||||
|
||||
writeline(v, [':READ' num2str(s) ':POW?']);
|
||||
line = readline(v);
|
||||
answer = sscanf(line,'%f');
|
||||
obj.power_state(cnt) = answer;
|
||||
|
||||
writeline(v, [':INP' num2str(s) ':ATT?']);
|
||||
line = readline(v);
|
||||
answer = sscanf(line,'%f');
|
||||
@@ -272,7 +271,7 @@ classdef OptAtten < handle
|
||||
answer = sscanf(line,'%f');
|
||||
obj.wavelength_state(cnt) = answer;
|
||||
|
||||
writeline(v, [':INP' num2str(s) ':WAV?']);
|
||||
writeline(v, [':INP' num2str(s) ':ATT:SPE?']);
|
||||
line = readline(v);
|
||||
answer = sscanf(line,'%f');
|
||||
obj.speed_state(cnt) = answer;
|
||||
@@ -293,6 +292,25 @@ classdef OptAtten < handle
|
||||
end
|
||||
end
|
||||
|
||||
function [p1,p2,p3,p4]=readPower(obj)
|
||||
|
||||
v = visadev('TCPIP::134.245.243.248::INSTR');
|
||||
cnt = 1;
|
||||
for s = 1:2:7
|
||||
writeline(v, [':READ' num2str(s) ':POW?']);
|
||||
line = readline(v);
|
||||
answer = sscanf(line,'%f');
|
||||
obj.power_state(cnt) = answer;
|
||||
|
||||
cnt = cnt+1;
|
||||
end
|
||||
p1 = obj.power_state(1);
|
||||
p2 = obj.power_state(2);
|
||||
p3 = obj.power_state(3);
|
||||
p4 = obj.power_state(4);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -12,6 +12,8 @@ classdef ScopeKeysight
|
||||
interpolate
|
||||
recordLen
|
||||
IPaddress
|
||||
|
||||
waitUntilClick
|
||||
end
|
||||
|
||||
methods (Access=public)
|
||||
@@ -30,6 +32,7 @@ classdef ScopeKeysight
|
||||
options.interpolate logical = 0;
|
||||
options.recordLen double = 1000000;
|
||||
options.IPaddress
|
||||
options.waitUntilClick = 0;
|
||||
end
|
||||
|
||||
%
|
||||
@@ -55,6 +58,7 @@ classdef ScopeKeysight
|
||||
arguments
|
||||
obj
|
||||
options.channel logical = obj.channel
|
||||
options.waitUntilClick = obj.waitUntilClick;
|
||||
end
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
@@ -79,7 +83,7 @@ classdef ScopeKeysight
|
||||
end
|
||||
end
|
||||
|
||||
debug = 1;
|
||||
debug = 0;
|
||||
if debug
|
||||
disp(['Connected to Instrument: ',char(v.Vendor),' ',char(v.Model),' SerNo:',char(v.SerialNumber)]);
|
||||
end
|
||||
@@ -119,14 +123,48 @@ classdef ScopeKeysight
|
||||
obj.writeNcheck(v,sprintf(':CHANnel%u:DISPlay ON',n));% display captured data trace
|
||||
end
|
||||
|
||||
set(v,'Timeout',150);
|
||||
if obj.autoScale
|
||||
obj.writeNcheck(v,':AUTOscale');
|
||||
for n = 1:4
|
||||
range = str2double(obj.writeReceiveCheck(v,sprintf(':CHANnel%u:RANGe?',n)));
|
||||
obj.writeNcheck(v,sprintf(':CHANnel%u:RANGe %.3f',n,range/1.2));
|
||||
|
||||
%use this to finetune autoscaling - VERY helpful
|
||||
% higher value leads to higher scaling
|
||||
fintunefactor = 1.5; % within [1,...,2]
|
||||
obj.writeNcheck(v,sprintf(':CHANnel%u:RANGe %.3f',n,range/fintunefactor));
|
||||
end
|
||||
else
|
||||
obj.writeNcheck(v,':SINGLE');
|
||||
%obj.writeNcheck(v,':SINGLE');
|
||||
end
|
||||
|
||||
% After Autoscale, let the user adjust the scope scaling...
|
||||
% "options.waitUntilClick" was a shit name but now this is it :-)
|
||||
if options.waitUntilClick
|
||||
|
||||
if 0
|
||||
% Create a dialog box with the desired text
|
||||
d = dialog('Name', 'Scale Scope then press continue', 'Position', [300, 300, 300, 180]);
|
||||
|
||||
% Add a text label with the instruction
|
||||
uicontrol('Parent', d, ...
|
||||
'Style', 'text', ...
|
||||
'Position', [20, 100, 260, 40], ...
|
||||
'String', 'Please adjust scope scaling now, then press continue', ...
|
||||
'HorizontalAlignment', 'center');
|
||||
|
||||
% Add a button to close the dialog and resume execution
|
||||
uicontrol('Parent', d, ...
|
||||
'Style', 'pushbutton', ...
|
||||
'Position', [100, 40, 100, 40], ...
|
||||
'String', 'Continue', ...
|
||||
'Callback', 'uiresume(gcbf); delete(gcbf)');
|
||||
|
||||
% Pause execution until the dialog box is closed
|
||||
uiwait(d);
|
||||
else
|
||||
holdAndShowValue
|
||||
end
|
||||
end
|
||||
|
||||
if obj.extRef
|
||||
|
||||
309
Classes/05_Lab/Thor_PDFA.m
Normal file
@@ -0,0 +1,309 @@
|
||||
classdef Thor_PDFA < handle
|
||||
|
||||
properties(Access= public)
|
||||
serialport_number
|
||||
safety_mode
|
||||
statusInfo
|
||||
|
||||
StatusRegisterValue
|
||||
Interlock
|
||||
TEC0_temp
|
||||
TEC1_temp
|
||||
Temp_stable
|
||||
Temp_fault
|
||||
LASER
|
||||
LOS_Status
|
||||
PumpLevel
|
||||
end
|
||||
|
||||
methods (Access=public)
|
||||
function obj = Thor_PDFA(options)
|
||||
|
||||
arguments
|
||||
options.serialport_number = 'COM12'
|
||||
options.safety_mode = 1;
|
||||
end
|
||||
|
||||
%
|
||||
fn = fieldnames(options);
|
||||
for n = 1:numel(fn)
|
||||
try
|
||||
obj.(fn{n}) = options.(fn{n});
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function o = connectSerial(obj)
|
||||
|
||||
% Connect to the PDFA
|
||||
o = serialport(obj.serialport_number, 9600);
|
||||
configureTerminator(o, "CR", "CR"); % Set the terminator to carriage return (CR)
|
||||
flush(o);
|
||||
|
||||
end
|
||||
|
||||
function getStatus(obj)
|
||||
|
||||
o = obj.connectSerial();
|
||||
obj.getStatus_(o);
|
||||
if obj.safety_mode
|
||||
obj
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function enablePDFA(obj)
|
||||
|
||||
o = obj.connectSerial();
|
||||
|
||||
if obj.safety_mode
|
||||
% Prompt the user to enable
|
||||
choice = questdlg('Do you want to enable the PDFA?', ...
|
||||
'TURN ON PUMP', ...
|
||||
'PUMP IT!', 'No', 'No');
|
||||
else
|
||||
choice = 'PUMP IT!';
|
||||
end
|
||||
|
||||
% Handle the response
|
||||
switch choice
|
||||
case 'PUMP IT!'
|
||||
% Enable the pump
|
||||
success = obj.enablePump_(o);
|
||||
disp('PDFA enabled.');
|
||||
case 'No'
|
||||
% Abort the operation
|
||||
disp('Operation aborted. Laser remains disabled.');
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
function disablePDFA(obj)
|
||||
|
||||
o = obj.connectSerial();
|
||||
|
||||
if obj.safety_mode
|
||||
% Prompt the user to disable
|
||||
choice = questdlg('Do you want to disable the PDFA?', ...
|
||||
'TURN OFF PUMP', ...
|
||||
'Turn off', 'No', 'No');
|
||||
else
|
||||
choice = 'Turn off';
|
||||
end
|
||||
|
||||
% Handle the response
|
||||
switch choice
|
||||
case 'Turn off'
|
||||
% Enable
|
||||
success = obj.disablePump_(o);
|
||||
disp('PDFA enabled.');
|
||||
case 'No'
|
||||
% Abort the operation
|
||||
disp('Operation aborted. Laser remains disabled.');
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
function success = setPumpLevel(obj,desiredPump)
|
||||
success = 0;
|
||||
o = obj.connectSerial();
|
||||
|
||||
obj.setPumpLevel_(o,desiredPump);
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
function cleanedResponse = cleanResponse(~,responseToClean)
|
||||
cleanedResponse = regexprep(responseToClean, '\x1B\[[0-9;]*[a-zA-Z]', '');
|
||||
end
|
||||
end
|
||||
|
||||
methods(Access= private)
|
||||
|
||||
function pumpLevel = readPumpLevel(obj,serialObj)
|
||||
writeline(serialObj, "gloc");
|
||||
pause(0.05);
|
||||
response = read(serialObj,serialObj.NumBytesAvailable,"char");
|
||||
cleanedResponse = obj.cleanResponse(response);
|
||||
currentPercentage = regexp(cleanedResponse, '([0-9]+\.[0-9]+)%', 'tokens', 'once');
|
||||
|
||||
obj.PumpLevel = str2double(currentPercentage{1});
|
||||
|
||||
pumpLevel = obj.PumpLevel;
|
||||
|
||||
end
|
||||
|
||||
function getStatus_(obj,o)
|
||||
|
||||
|
||||
writeline(o, "stat");
|
||||
pause(0.5);
|
||||
response = read(o,o.NumBytesAvailable,"char");
|
||||
cleanedResponse = obj.cleanResponse(response);
|
||||
|
||||
% Parse and convert values
|
||||
% Convert Status Register Value (hexadecimal to decimal)
|
||||
statusValueHex = regexp(cleanedResponse, 'Status Register Value = (0x[0-9A-F]+)', 'tokens', 'once');
|
||||
obj.StatusRegisterValue = hex2dec(statusValueHex{1});
|
||||
|
||||
% Convert Interlock status to logical (Closed = true, Open = false)
|
||||
interlockStatus = regexp(cleanedResponse, 'Interlock\s*:\s*(\w+)', 'tokens', 'once');
|
||||
obj.Interlock = strcmp(interlockStatus{1}, 'Closed');
|
||||
|
||||
% Convert TEC0 and TEC1 temp to logical (Good = true, Fault = false)
|
||||
tec0Temp = regexp(cleanedResponse, 'TEC0 temp\s*:\s*(\w+)', 'tokens', 'once');
|
||||
obj.TEC0_temp = strcmp(tec0Temp{1}, 'Good');
|
||||
|
||||
tec1Temp = regexp(cleanedResponse, 'TEC1 temp\s*:\s*(\w+)', 'tokens', 'once');
|
||||
obj.TEC1_temp = strcmp(tec1Temp{1}, 'Good');
|
||||
|
||||
% Convert Temp stable status to logical (Stable = true, Unstable = false)
|
||||
tempStable = regexp(cleanedResponse, 'Temp stable\s*:\s*(\w+)', 'tokens', 'once');
|
||||
obj.Temp_stable = strcmp(tempStable{1}, 'Stable');
|
||||
|
||||
% Convert Temp fault status to logical (No Fault = false, Fault = true)
|
||||
tempFault = regexp(cleanedResponse, 'Temp fault\s*:\s*(\w+)', 'tokens', 'once');
|
||||
obj.Temp_fault = strcmp(tempFault{1}, 'Fault');
|
||||
|
||||
% Convert LASER status to logical (OFF = false, ON = true)
|
||||
laserStatus = regexp(cleanedResponse, 'LASER\s*:\s*(\w+)', 'tokens', 'once');
|
||||
obj.LASER = strcmp(laserStatus{1}, 'ON');
|
||||
|
||||
% Convert LOS Status to logical (Good = true, Faulty = false)
|
||||
losStatus = regexp(cleanedResponse, 'LOS Status\s*:\s*(\w+)', 'tokens', 'once');
|
||||
obj.LOS_Status = strcmp(losStatus{1}, 'Good');
|
||||
|
||||
|
||||
writeline(o, "gloc");
|
||||
pause(0.5);
|
||||
response = read(o,o.NumBytesAvailable,"char");
|
||||
cleanedResponse = obj.cleanResponse(response);
|
||||
|
||||
% Use a regular expression to extract the operating current value in percentage
|
||||
currentPercentage = regexp(cleanedResponse, '([0-9]+\.[0-9]+)%', 'tokens', 'once');
|
||||
|
||||
% Convert the extracted percentage to a numeric value
|
||||
obj.PumpLevel = str2double(currentPercentage{1});
|
||||
|
||||
end
|
||||
|
||||
function success = enablePump_(obj,o)
|
||||
success = 0;
|
||||
|
||||
curPump = obj.readPumpLevel(o);
|
||||
|
||||
if curPump ~= 0
|
||||
cnt = 0;
|
||||
pumpSetToZero = 0;
|
||||
while ~pumpSetToZero
|
||||
pumpZero = 0;
|
||||
pumpSetToZero = obj.setPumpLevel_(o,pumpZero);
|
||||
cnt = cnt+1;
|
||||
end
|
||||
end
|
||||
|
||||
% set pump on
|
||||
writeline(o, 'le');
|
||||
pause(0.5);
|
||||
response = read(o,o.NumBytesAvailable,"char");
|
||||
cleanedResponse = obj.cleanResponse(response);
|
||||
|
||||
isEnabled = contains(cleanedResponse, {'ENABLE LASER'});
|
||||
|
||||
pause(5);
|
||||
|
||||
obj.getStatus_(o);
|
||||
|
||||
if isEnabled && obj.LASER
|
||||
success = 1;
|
||||
else
|
||||
error('Could not enable the pump....');
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function success = disablePump_(obj,o)
|
||||
success = 0;
|
||||
|
||||
curPump = obj.readPumpLevel(o);
|
||||
|
||||
if curPump ~= 0
|
||||
cnt = 0;
|
||||
pumpSetToZero = 0;
|
||||
while ~pumpSetToZero
|
||||
pumpZero = 0;
|
||||
pumpSetToZero = obj.setPumpLevel_(o,pumpZero);
|
||||
cnt = cnt+1;
|
||||
end
|
||||
end
|
||||
|
||||
% set pump on
|
||||
writeline(o, 'ld');
|
||||
pause(0.5);
|
||||
response = read(o,o.NumBytesAvailable,"char");
|
||||
cleanedResponse = obj.cleanResponse(response);
|
||||
|
||||
isDisabled = contains(cleanedResponse, {'DISABLE LASER'});
|
||||
|
||||
pause(5);
|
||||
|
||||
obj.getStatus_(o);
|
||||
|
||||
if isDisabled && ~obj.LASER
|
||||
success = 1;
|
||||
else
|
||||
error('Could not disable the pump....');
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function success = setPumpLevel_(obj,o,desiredPump)
|
||||
|
||||
success = 0;
|
||||
|
||||
curPump = obj.readPumpLevel(o);
|
||||
|
||||
while abs(curPump-desiredPump) > 0
|
||||
|
||||
% difference
|
||||
diff_pump = curPump-desiredPump;
|
||||
|
||||
% set new pump
|
||||
increment_pump = -1 * sign(diff_pump) ;
|
||||
|
||||
% set new incr. pump
|
||||
writeline(o, ['sloc ',num2str(curPump+increment_pump)]);
|
||||
|
||||
if increment_pump < 0
|
||||
pause(0.1);
|
||||
else
|
||||
pause(0.3);
|
||||
end
|
||||
|
||||
|
||||
response = read(o,o.NumBytesAvailable,"char");
|
||||
cleanedResponse = obj.cleanResponse(response);
|
||||
curPump = str2double(regexp(cleanedResponse, '([0-9]+\.[0-9]+)%', 'tokens', 'once'));
|
||||
|
||||
end
|
||||
|
||||
curPump = obj.readPumpLevel(o);
|
||||
|
||||
if obj.PumpLevel == desiredPump
|
||||
success = 1;
|
||||
else
|
||||
warning('Pump nicht richtig?')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,246 +0,0 @@
|
||||
classdef DataStorage < handle
|
||||
%DATASTORAGE Summary of this class goes here
|
||||
% Detailed explanation goes here
|
||||
|
||||
properties
|
||||
inputParams = struct;
|
||||
parameter = struct;
|
||||
fn = [];
|
||||
dim = [];
|
||||
sto = {};
|
||||
% getPhysForIndex = struct;
|
||||
% getIndexForPhys = struct;
|
||||
end
|
||||
|
||||
methods
|
||||
|
||||
function obj = DataStorage(inputParams)
|
||||
%DATASTORAGE Construct an instance of this class
|
||||
% Detailed explanation goes here
|
||||
|
||||
% scheiß Variablenname
|
||||
obj.inputParams = inputParams;
|
||||
|
||||
% Field Names
|
||||
obj.fn = string(fieldnames(inputParams));
|
||||
|
||||
% _______________
|
||||
% Two dicts that map between physical and array index :-)
|
||||
% Dictionary: 10 km -> 3
|
||||
% obj.getIndexForPhys = obj.buildIndexDict();
|
||||
|
||||
% Dictionary: 3 -> 10Km
|
||||
% obj.getPhysForIndex = obj.buildPhysDict();
|
||||
|
||||
% _______________
|
||||
% This is the 2nd Idea -> ecery given Param will be a class
|
||||
% instance of "Parameter", therin user can access the dicts and
|
||||
% informations... Have not decided which way is best..
|
||||
obj = obj.buildParameter();
|
||||
|
||||
% get dimension of dataStorage
|
||||
% e.g. if we have L = [1,2,10,80] and D=[8, 17, 21], we would
|
||||
% need an array with dimesion [4,3].
|
||||
obj.dim = obj.getDimension();
|
||||
|
||||
% finally, create the main storage as cell array
|
||||
obj.sto = struct;
|
||||
|
||||
end
|
||||
|
||||
function save(obj,path)
|
||||
try
|
||||
save(path,"obj");
|
||||
catch
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function showInfo(obj)
|
||||
disp("Data Structure with fields:");
|
||||
fprintf('%-12s', 'Name'); fprintf('%1s', '| '); fprintf('%0s ', 'Dimension'); fprintf('%4s', '| '); fprintf('%0s ', 'Physical Values'); fprintf('\n');
|
||||
disp('----------------------------------------------------------------');
|
||||
for i = 1:numel(obj.fn)
|
||||
|
||||
fprintf('%-12s', char(obj.fn(i))); fprintf('%1s', '| '); fprintf('%8.1i ', obj.dim(i)); fprintf('%5s', '| '); fprintf('%-7s ', string(obj.parameter.(obj.fn(i)).values) ); fprintf('\n');
|
||||
|
||||
end
|
||||
disp('----------------------------------------------------------------');
|
||||
|
||||
stofn = string(fieldnames(obj.sto));
|
||||
for s = 1:numel(stofn)
|
||||
nonempty = numel(find(~cellfun(@isempty,obj.sto.(stofn(s)))));
|
||||
overall = numel(obj.sto.(stofn(s)));
|
||||
fprintf('%-8s', 'Storage '); fprintf('%-10s', char(stofn(s))); fprintf('%4s', 'filled with '); fprintf('%-5s', num2str(nonempty)); fprintf('%-1s', ' entries -> '); fprintf('%-5s', num2str(nonempty/overall*100)); fprintf('%-1s', '% filled'); fprintf('\n');
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function dim = getDimension(obj)
|
||||
dim = zeros(1,numel(obj.fn));
|
||||
for p = 1:numel(obj.fn)
|
||||
%loop all parameter names and add their length :-)
|
||||
dim(p)=obj.parameter.(obj.fn(p)).length;
|
||||
end
|
||||
end
|
||||
|
||||
function obj = buildParameter(obj)
|
||||
|
||||
for p = 1:numel(obj.fn)
|
||||
name = obj.fn(p);
|
||||
values = obj.inputParams.(name);
|
||||
obj.parameter.(name) = Parameter(name,values);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function addStorage(obj,varName)
|
||||
% add a storage
|
||||
|
||||
storage = cell(obj.dim);
|
||||
|
||||
obj.sto.(string(varName)) = storage;
|
||||
|
||||
end
|
||||
|
||||
function addValueToStorage(obj, valueToStore ,storageVarName, varargin)
|
||||
|
||||
if nargin-3 == numel(obj.fn)
|
||||
lin_idx = obj.getIndicesByPhys(varargin);
|
||||
obj.sto.(storageVarName){lin_idx} = valueToStore;
|
||||
else
|
||||
error('Specify all the indices to access the right place in storage!')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
% Access Value(s)
|
||||
function value = getStoValue(obj,storageVarName, varargin)
|
||||
|
||||
if nargin-2 == numel(obj.fn)
|
||||
%es wurden aausreichend argumente übergeben :-)
|
||||
%es gibt jedoch erstmal keinen Check ob die Reihenfolge
|
||||
%richtig ist
|
||||
value = [];
|
||||
lin_idx = obj.getIndicesByPhys(varargin);
|
||||
errcnt = 0;
|
||||
for i=1:numel(lin_idx)
|
||||
% try
|
||||
tmp = obj.sto.(storageVarName){lin_idx(i)};
|
||||
if ~isempty(tmp)
|
||||
if isa(tmp,'Signal')
|
||||
if i == 1
|
||||
value = {};
|
||||
end
|
||||
value{i} = tmp ;
|
||||
elseif isa(tmp,'cell')
|
||||
if isa(tmp{1},'Signal')
|
||||
if i == 1
|
||||
value = {};
|
||||
end
|
||||
value{i} = tmp{1} ;
|
||||
end
|
||||
else
|
||||
value(i,:) = tmp ;
|
||||
end
|
||||
else
|
||||
errcnt = errcnt+1;
|
||||
value(i,:) = NaN ;
|
||||
if errcnt < 3
|
||||
%get back the n-dimensional subiondices...
|
||||
% [sub{1:length(size(obj.sto.(storageVarName)))}] = ind2sub(size(obj.sto.(storageVarName)),lin_idx(i));
|
||||
|
||||
%get back the physical representaion
|
||||
% word = [];
|
||||
% for phys_idx = 1:numel(obj.fn)
|
||||
% parametername = obj.fn(phys_idx);
|
||||
% word = [word,char(parametername),': ', num2str(obj.parameter.(parametername).getPhysForIndex(sub{phys_idx})),' ;'];
|
||||
% end
|
||||
% warning(['Requested Data is not in Warehouse ', word]);
|
||||
elseif errcnt == 3
|
||||
% warning(['... ', word]);
|
||||
end
|
||||
|
||||
end
|
||||
if errcnt > 2
|
||||
% warning([num2str(errcnt),' requested datapoint(s) not in warehouse.']);
|
||||
end
|
||||
|
||||
% catch
|
||||
% error('Error in Datastorage: Something happened while looking up in warehouse.')
|
||||
% end
|
||||
end
|
||||
else
|
||||
error('Wrong Request using ExampleWarehouse.getStoValue(*parameter set*). Give me all the Parameters! Please!')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
% Mapping for several Indices (calls the mapping for single index)
|
||||
function lin_idx = getIndicesByPhys(obj,varargin)
|
||||
%map _all_ phys. to indices - several calls of single mapping
|
||||
|
||||
inputsz = cellfun(@size,varargin{1},'UniformOutput',false);
|
||||
inputmax = cell2mat(cellfun(@max,inputsz,'UniformOutput',false));
|
||||
|
||||
% I wrote this method for a single query, then refined it for vectorial
|
||||
% inputs (which work fine), but lastly recognized that I
|
||||
% destroyed single query... however, this if / else will fix it!
|
||||
if sum(inputmax)==length(inputmax)
|
||||
vecQuery = 1; %set any value to one
|
||||
else
|
||||
vecQuery = find(inputmax~=1); %position of vectorial queries
|
||||
end
|
||||
|
||||
q={};
|
||||
for i = 1:numel(vecQuery)
|
||||
q{i} = varargin{1,1}{vecQuery(i)}; %the two vectors
|
||||
end
|
||||
|
||||
combination = combvec(q{:}); %combine all possible combinations
|
||||
|
||||
for c = 1:length(combination)
|
||||
%loop over all possible combinations
|
||||
|
||||
indices = {};
|
||||
str = [];
|
||||
|
||||
for r = 1:numel(vecQuery)
|
||||
%replace varargin with current query (could have been renamed... however it works)
|
||||
varargin{1}{vecQuery(r)} = combination(r,c);
|
||||
end
|
||||
|
||||
for p = 1:numel(obj.fn)
|
||||
|
||||
curPhysQuery = varargin{1}{p}; %can be: a) single value // b) range
|
||||
|
||||
curParameterName = obj.fn(p);
|
||||
|
||||
indices{end+1} = obj.getIndexByPhys(curParameterName,curPhysQuery);
|
||||
|
||||
% str = [str, ',indices{', num2str(p), '}'];
|
||||
|
||||
end
|
||||
|
||||
%append to index list :-)
|
||||
fn_=fieldnames(obj.sto);
|
||||
n_ = fn_{1};
|
||||
lin_idx(c,:) = sub2ind(size(obj.sto.(n_)),indices{:});
|
||||
% lin_idx(c,:) = eval(['sub2ind(size(obj.sto.',n_,')',str,');']);
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
% Mapping for single Index
|
||||
function idx = getIndexByPhys(obj,fieldname,phys)
|
||||
%map single phys to index
|
||||
idx = obj.parameter.(fieldname).getIndexForPhys(phys);
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
24
Functions/calcWavelengthPlan.m
Normal file
@@ -0,0 +1,24 @@
|
||||
function channelplan_nm = calcWavelengthPlan(N, df_hz, center_nm)
|
||||
|
||||
vec = [N:-1:1]-(N/2+0.5);
|
||||
|
||||
channelplan_hz = nm2hz(center_nm) + (vec * df_hz) ;
|
||||
|
||||
channelplan_nm = hz2nm(channelplan_hz);
|
||||
|
||||
% dfft = 1.367053998632946e+07; %hz
|
||||
% a = diff(channelplan_hz)./2./dfft;
|
||||
|
||||
end
|
||||
|
||||
function hz = nm2hz(nm)
|
||||
wavelen_in_m = nm.* 1e-9;
|
||||
hz = (299792458 ./ wavelen_in_m); %frequency in Terahertz
|
||||
end
|
||||
|
||||
function nm = hz2nm(hz)
|
||||
m = (299792458 ./ hz); %wavelength in meter
|
||||
nm = m .* 10^9;
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Copyright 2016 Bastian Bechtold
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Violin Plots for Matlab
|
||||
|
||||
A violin plot is an easy to read substitute for a box plot that
|
||||
replaces the box shape with a kernel density estimate of the data, and
|
||||
optionally overlays the data points itself. The original boxplot shape
|
||||
is still included as a grey box/line in the center of the violin.
|
||||
|
||||
Violin plots are a superset of box plots, and give a much richer
|
||||
understanding of the data distribution, while not taking more space.
|
||||
You will be able to instantly spot too-sparse data, or multi-modal
|
||||
distributions, which could go unnoticed in boxplots.
|
||||
|
||||
`violinplot` is meant as a direct substitute for `boxplot` (excluding
|
||||
named arguments). Additional constructor parameters include the width
|
||||
of the plot, the bandwidth of the kernel density estimation, and the
|
||||
X-axis position of the violin plot.
|
||||
|
||||
For more information about violin plots, read "[Violin plots: a box
|
||||
plot-density trace synergism](http://www.stat.cmu.edu/~rnugent/PCMI2016/papers/ViolinPlots.pdf)"
|
||||
by J. L. Hintze and R. D. Nelson in The American Statistician, vol.
|
||||
52, no. 2, pp. 181-184, 1998 (DOI: 10.2307/2685478).
|
||||
|
||||
For a simple call:
|
||||
|
||||
```matlab
|
||||
load carbig MPG Origin
|
||||
Origin = cellstr(Origin);
|
||||
figure
|
||||
vs = violinplot(MPG, Origin);
|
||||
ylabel('Fuel Economy in MPG');
|
||||
xlim([0.5, 7.5]);
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
You can also play around with the different options, and tune your violin plots to your liking.
|
||||
|
||||
```matlab
|
||||
grouporder={'England','Sweden','Japan','Italy','Germany','France','USA'};
|
||||
vs = Violin({MPG(strcmp(Origin, grouporder{pos}))},...
|
||||
position,...
|
||||
'HalfViolin','right',...% left, full
|
||||
'QuartileStyle','shadow',... % boxplot, none
|
||||
'DataStyle', 'histogram',... % scatter, none
|
||||
'ShowNotches', false,...
|
||||
'ShowMean', false,...
|
||||
'ShowMedian', true,...
|
||||
'ViolinColor', color);
|
||||
```
|
||||

|
||||
|
||||
## Citation
|
||||
|
||||
[](https://zenodo.org/badge/latestdoi/60771923)
|
||||
|
||||
If you want to cite this repository, use
|
||||
|
||||
> Bechtold, Bastian, 2016. Violin Plots for Matlab, Github Project
|
||||
> https://github.com/bastibe/Violinplot-Matlab, DOI: 10.5281/zenodo.4559847
|
||||
@@ -0,0 +1,713 @@
|
||||
classdef Violin < handle
|
||||
% Violin creates violin plots for some data
|
||||
% A violin plot is an easy to read substitute for a box plot
|
||||
% that replaces the box shape with a kernel density estimate of
|
||||
% the data, and optionally overlays the data points itself.
|
||||
% It is also possible to provide two sets of data which are supposed
|
||||
% to be compared by plotting each column of the two datasets together
|
||||
% on each side of the violin.
|
||||
%
|
||||
% Additional constructor parameters include the width of the
|
||||
% plot, the bandwidth of the kernel density estimation, the
|
||||
% X-axis position of the violin plot, and the categories.
|
||||
%
|
||||
% Use <a href="matlab:help('violinplot')">violinplot</a> for a
|
||||
% <a href="matlab:help('boxplot')">boxplot</a>-like wrapper for
|
||||
% interactive plotting.
|
||||
%
|
||||
% See for more information on Violin Plots:
|
||||
% J. L. Hintze and R. D. Nelson, "Violin plots: a box
|
||||
% plot-density trace synergism," The American Statistician, vol.
|
||||
% 52, no. 2, pp. 181-184, 1998.
|
||||
%
|
||||
% Violin Properties:
|
||||
% ViolinColor - Fill color of the violin area and data points.
|
||||
% Can be either a matrix nx3 or an array of up to two
|
||||
% cells containing nx3 matrices.
|
||||
% Defaults to the next default color cycle.
|
||||
% ViolinAlpha - Transparency of the violin area and data points.
|
||||
% Can be either a single scalar value or an array of
|
||||
% up to two cells containing scalar values.
|
||||
% Defaults to 0.3.
|
||||
% EdgeColor - Color of the violin area outline.
|
||||
% Defaults to [0.5 0.5 0.5]
|
||||
% BoxColor - Color of the box, whiskers, and the outlines of
|
||||
% the median point and the notch indicators.
|
||||
% Defaults to [0.5 0.5 0.5]
|
||||
% MedianColor - Fill color of the median and notch indicators.
|
||||
% Defaults to [1 1 1]
|
||||
% ShowData - Whether to show data points.
|
||||
% Defaults to true
|
||||
% ShowNotches - Whether to show notch indicators.
|
||||
% Defaults to false
|
||||
% ShowMean - Whether to show mean indicator.
|
||||
% Defaults to false
|
||||
% ShowBox - Whether to show the box.
|
||||
% Defaults to true
|
||||
% ShowMedian - Whether to show the median indicator.
|
||||
% Defaults to true
|
||||
% ShowWhiskers - Whether to show the whiskers
|
||||
% Defaults to true
|
||||
% HalfViolin - Whether to do a half violin(left, right side) or
|
||||
% full. Defaults to full.
|
||||
% QuartileStyle - Option on how to display quartiles, with a
|
||||
% boxplot, shadow or none. Defaults to boxplot.
|
||||
% DataStyle - Defines the style to show the data points. Opts:
|
||||
% 'scatter', 'histogram' or 'none'. Default is 'scatter'.
|
||||
%
|
||||
%
|
||||
% Violin Children:
|
||||
% ScatterPlot - <a href="matlab:help('scatter')">scatter</a> plot of the data points
|
||||
% ScatterPlot2 - <a href="matlab:help('scatter')">scatter</a> second plot of the data points
|
||||
% ViolinPlot - <a href="matlab:help('fill')">fill</a> plot of the kernel density estimate
|
||||
% ViolinPlot2 - <a href="matlab:help('fill')">fill</a> second plot of the kernel density estimate
|
||||
% BoxPlot - <a href="matlab:help('fill')">fill</a> plot of the box between the quartiles
|
||||
% WhiskerPlot - line <a href="matlab:help('plot')">plot</a> between the whisker ends
|
||||
% MedianPlot - <a href="matlab:help('scatter')">scatter</a> plot of the median (one point)
|
||||
% NotchPlots - <a href="matlab:help('scatter')">scatter</a> plots for the notch indicators
|
||||
% MeanPlot - line <a href="matlab:help('plot')">plot</a> at mean value
|
||||
|
||||
|
||||
% Copyright (c) 2016, Bastian Bechtold
|
||||
% This code is released under the terms of the BSD 3-clause license
|
||||
|
||||
properties (Access=public)
|
||||
ScatterPlot % scatter plot of the data points
|
||||
ScatterPlot2 % comparison scatter plot of the data points
|
||||
ViolinPlot % fill plot of the kernel density estimate
|
||||
ViolinPlot2 % comparison fill plot of the kernel density estimate
|
||||
BoxPlot % fill plot of the box between the quartiles
|
||||
WhiskerPlot % line plot between the whisker ends
|
||||
MedianPlot % scatter plot of the median (one point)
|
||||
NotchPlots % scatter plots for the notch indicators
|
||||
MeanPlot % line plot of the mean (horizontal line)
|
||||
HistogramPlot % histogram of the data
|
||||
ViolinPlotQ % fill plot of the Quartiles as shadow
|
||||
end
|
||||
|
||||
properties (Dependent=true)
|
||||
ViolinColor % fill color of the violin area and data points
|
||||
ViolinAlpha % transparency of the violin area and data points
|
||||
MarkerSize % marker size for the data dots
|
||||
MedianMarkerSize % marker size for the median dot
|
||||
LineWidth % linewidth of the median plot
|
||||
EdgeColor % color of the violin area outline
|
||||
BoxColor % color of box, whiskers, and median/notch edges
|
||||
BoxWidth % width of box between the quartiles in axis space (default 10% of Violin plot width, 0.03)
|
||||
MedianColor % fill color of median and notches
|
||||
ShowData % whether to show data points
|
||||
ShowNotches % whether to show notch indicators
|
||||
ShowMean % whether to show mean indicator
|
||||
ShowBox % whether to show the box
|
||||
ShowMedian % whether to show the median line
|
||||
ShowWhiskers % whether to show the whiskers
|
||||
HalfViolin % whether to do a half violin(left, right side) or full
|
||||
end
|
||||
|
||||
methods
|
||||
function obj = Violin(data, pos, varargin)
|
||||
%Violin plots a violin plot of some data at pos
|
||||
% VIOLIN(DATA, POS) plots a violin at x-position POS for
|
||||
% a vector of DATA points.
|
||||
%
|
||||
% VIOLIN(..., 'PARAM1', val1, 'PARAM2', val2, ...)
|
||||
% specifies optional name/value pairs:
|
||||
% 'Width' Width of the violin in axis space.
|
||||
% Defaults to 0.3
|
||||
% 'Bandwidth' Bandwidth of the kernel density
|
||||
% estimate. Should be between 10% and
|
||||
% 40% of the data range.
|
||||
% 'ViolinColor' Fill color of the violin area
|
||||
% and data points.Can be either a matrix
|
||||
% nx3 or an array of up to two cells
|
||||
% containing nx3 matrices.
|
||||
% 'ViolinAlpha' Transparency of the violin area and data
|
||||
% points. Can be either a single scalar
|
||||
% value or an array of up to two cells
|
||||
% containing scalar values. Defaults to 0.3.
|
||||
% 'MarkerSize' Size of the data points, if shown.
|
||||
% Defaults to 24
|
||||
% 'MedianMarkerSize' Size of the median indicator, if shown.
|
||||
% Defaults to 36
|
||||
% 'EdgeColor' Color of the violin area outline.
|
||||
% Defaults to [0.5 0.5 0.5]
|
||||
% 'BoxColor' Color of the box, whiskers, and the
|
||||
% outlines of the median point and the
|
||||
% notch indicators. Defaults to
|
||||
% [0.5 0.5 0.5]
|
||||
% 'MedianColor' Fill color of the median and notch
|
||||
% indicators. Defaults to [1 1 1]
|
||||
% 'ShowData' Whether to show data points.
|
||||
% Defaults to true
|
||||
% 'ShowNotches' Whether to show notch indicators.
|
||||
% Defaults to false
|
||||
% 'ShowMean' Whether to show mean indicator.
|
||||
% Defaults to false
|
||||
% 'ShowBox' Whether to show the box
|
||||
% Defaults to true
|
||||
% 'ShowMedian' Whether to show the median line
|
||||
% Defaults to true
|
||||
% 'ShowWhiskers' Whether to show the whiskers
|
||||
% Defaults to true
|
||||
% 'HalfViolin' Whether to do a half violin(left, right side) or
|
||||
% full. Defaults to full.
|
||||
% 'QuartileStyle' Option on how to display quartiles, with a
|
||||
% boxplot or as a shadow. Defaults to boxplot.
|
||||
% 'DataStyle' Defines the style to show the data points. Opts:
|
||||
% 'scatter', 'histogram' or 'none'. Default is 'Scatter'.
|
||||
|
||||
st = dbstack; % get the calling function for reporting errors
|
||||
namefun = st.name;
|
||||
args = obj.checkInputs(data, pos, varargin{:});
|
||||
|
||||
if length(data)==1
|
||||
data2 = [];
|
||||
data = data{1};
|
||||
|
||||
else
|
||||
data2 = data{2};
|
||||
data = data{1};
|
||||
end
|
||||
|
||||
if isempty(args.ViolinColor)
|
||||
Release= strsplit(version('-release'), {'a','b'}); %Check release
|
||||
if str2num(Release{1})> 2019 || strcmp(version('-release'), '2019b')
|
||||
C = colororder;
|
||||
else
|
||||
C = lines;
|
||||
end
|
||||
|
||||
if pos > length(C)
|
||||
C = lines;
|
||||
end
|
||||
args.ViolinColor = {repmat(C,ceil(size(data,2)/length(C)),1)};
|
||||
end
|
||||
|
||||
data = data(not(isnan(data)));
|
||||
data2 = data2(not(isnan(data2)));
|
||||
if numel(data) == 1
|
||||
obj.MedianPlot = scatter(pos, data, 'filled');
|
||||
obj.MedianColor = args.MedianColor;
|
||||
obj.MedianPlot.MarkerEdgeColor = args.EdgeColor;
|
||||
return
|
||||
end
|
||||
|
||||
hold('on');
|
||||
|
||||
|
||||
%% Calculate kernel density estimation for the violin
|
||||
[density, value, width] = obj.calcKernelDensity(data, args.Bandwidth, args.Width);
|
||||
|
||||
% also calculate the kernel density of the comparison data if
|
||||
% provided
|
||||
if ~isempty(data2)
|
||||
[densityC, valueC, widthC] = obj.calcKernelDensity(data2, args.Bandwidth, args.Width);
|
||||
end
|
||||
|
||||
%% Plot the data points within the violin area
|
||||
if length(density) > 1
|
||||
[~, unique_idx] = unique(value);
|
||||
jitterstrength = interp1(value(unique_idx), density(unique_idx)*width, data, 'linear','extrap');
|
||||
else % all data is identical:
|
||||
jitterstrength = density*width;
|
||||
end
|
||||
if isempty(data2) % if no comparison data
|
||||
jitter = 2*(rand(size(data))-0.5); % both sides
|
||||
else
|
||||
jitter = rand(size(data)); % only right side
|
||||
end
|
||||
switch args.HalfViolin % this is more modular
|
||||
case 'left'
|
||||
jitter = -1*(rand(size(data))); %left
|
||||
case 'right'
|
||||
jitter = 1*(rand(size(data))); %right
|
||||
case 'full'
|
||||
jitter = 2*(rand(size(data))-0.5);
|
||||
end
|
||||
% Make scatter plot
|
||||
switch args.DataStyle
|
||||
case 'scatter'
|
||||
if ~isempty(data2)
|
||||
jitter = 1*(rand(size(data))); %right
|
||||
obj.ScatterPlot = ...
|
||||
scatter(pos + jitter.*jitterstrength, data, args.MarkerSize, 'filled');
|
||||
% plot the data points within the violin area
|
||||
if length(densityC) > 1
|
||||
jitterstrength = interp1(valueC, densityC*widthC, data2);
|
||||
else % all data is identical:
|
||||
jitterstrength = densityC*widthC;
|
||||
end
|
||||
jitter = -1*rand(size(data2));% left
|
||||
obj.ScatterPlot2 = ...
|
||||
scatter(pos + jitter.*jitterstrength, data2, args.MarkerSize, 'filled');
|
||||
else
|
||||
obj.ScatterPlot = ...
|
||||
scatter(pos + jitter.*jitterstrength, data, args.MarkerSize, 'filled');
|
||||
|
||||
end
|
||||
case 'histogram'
|
||||
[counts,edges] = histcounts(data, size(unique(data),1));
|
||||
switch args.HalfViolin
|
||||
case 'right'
|
||||
obj.HistogramPlot= plot([pos-((counts')/max(counts))*max(jitterstrength)*2, pos*ones(size(counts,2),1)]',...
|
||||
[edges(1:end-1)+max(diff(edges))/2; edges(1:end-1)+max(diff(edges))/2],'-','LineWidth',1, 'Color', 'k');
|
||||
case 'left'
|
||||
obj.HistogramPlot= plot([pos*ones(size(counts,2),1), pos+((counts')/max(counts))*max(jitterstrength)*2]',...
|
||||
[edges(1:end-1)+max(diff(edges))/2; edges(1:end-1)+max(diff(edges))/2],'-','LineWidth',1, 'Color', 'k');
|
||||
otherwise
|
||||
fprintf([namefun, ' No histogram/bar plot option available for full violins, as it would look overcrowded.\n'])
|
||||
end
|
||||
case 'none'
|
||||
end
|
||||
|
||||
%% Plot the violin
|
||||
halfViol= ones(1, size(density,2));
|
||||
if isempty(data2) % if no comparison data
|
||||
switch args.HalfViolin
|
||||
case 'right'
|
||||
obj.ViolinPlot = ... % plot color will be overwritten later
|
||||
fill([pos+density*width halfViol*pos], ...
|
||||
[value value(end:-1:1)], [1 1 1],'LineWidth',1);
|
||||
case 'left'
|
||||
obj.ViolinPlot = ... % plot color will be overwritten later
|
||||
fill([halfViol*pos pos-density(end:-1:1)*width], ...
|
||||
[value value(end:-1:1)], [1 1 1],'LineWidth',1);
|
||||
case 'full'
|
||||
obj.ViolinPlot = ... % plot color will be overwritten later
|
||||
fill([pos+density*width pos-density(end:-1:1)*width], ...
|
||||
[value value(end:-1:1)], [1 1 1],'LineWidth',1);
|
||||
end
|
||||
else
|
||||
% plot right half of the violin
|
||||
obj.ViolinPlot = ...
|
||||
fill([pos+density*width pos-density(1)*width], ...
|
||||
[value value(1)], [1 1 1],'LineWidth',1);
|
||||
% plot left half of the violin
|
||||
obj.ViolinPlot2 = ...
|
||||
fill([pos-densityC(end)*widthC pos-densityC(end:-1:1)*widthC], ...
|
||||
[valueC(end) valueC(end:-1:1)], [1 1 1],'LineWidth',1);
|
||||
end
|
||||
|
||||
%% Plot the quartiles within the violin
|
||||
quartiles = quantile(data, [0.25, 0.5, 0.75]);
|
||||
flat= [halfViol*pos halfViol*pos];
|
||||
switch args.QuartileStyle
|
||||
case 'shadow'
|
||||
switch args.HalfViolin
|
||||
case 'right'
|
||||
w = [pos+density*width halfViol*pos];
|
||||
h= [value value(end:-1:1)];
|
||||
case 'left'
|
||||
w = [halfViol*pos pos-density(end:-1:1)*width];
|
||||
h= [value value(end:-1:1)];
|
||||
case 'full'
|
||||
w = [pos+density*width pos-density(end:-1:1)*width];
|
||||
h= [value value(end:-1:1)];
|
||||
end
|
||||
w(h<quartiles(1))=flat(h<quartiles(1));
|
||||
w(h>quartiles(3))=flat((h>quartiles(3)));
|
||||
obj.ViolinPlotQ = ... % plot color will be overwritten later
|
||||
fill(w, ...
|
||||
h, [1 1 1]);
|
||||
case 'boxplot'
|
||||
obj.BoxPlot = ... % plot color will be overwritten later
|
||||
fill(pos+[-1,1,1,-1]*args.BoxWidth, ...
|
||||
[quartiles(1) quartiles(1) quartiles(3) quartiles(3)], ...
|
||||
[1 1 1]);
|
||||
case 'none'
|
||||
end
|
||||
|
||||
%% Plot the data mean
|
||||
meanValue = mean(data);
|
||||
if length(density) > 1
|
||||
[~, unique_idx] = unique(value);
|
||||
meanDensityWidth = interp1(value(unique_idx), density(unique_idx), meanValue, 'linear','extrap')*width;
|
||||
else % all data is identical:
|
||||
meanDensityWidth = density*width;
|
||||
end
|
||||
if meanDensityWidth<args.BoxWidth/2
|
||||
meanDensityWidth=args.BoxWidth/2;
|
||||
end
|
||||
switch args.HalfViolin
|
||||
case 'right'
|
||||
obj.MeanPlot = plot(pos+[0,1].*meanDensityWidth, ...
|
||||
[meanValue, meanValue]);
|
||||
case 'left'
|
||||
obj.MeanPlot = plot(pos+[-1,0].*meanDensityWidth, ...
|
||||
[meanValue, meanValue]);
|
||||
case 'full'
|
||||
obj.MeanPlot = plot(pos+[-1,1].*meanDensityWidth, ...
|
||||
[meanValue, meanValue]);
|
||||
end
|
||||
obj.MeanPlot.LineWidth = 1;
|
||||
|
||||
%% Plot the median, notch, and whiskers
|
||||
IQR = quartiles(3) - quartiles(1);
|
||||
lowhisker = quartiles(1) - 1.5*IQR;
|
||||
lowhisker = max(lowhisker, min(data(data > lowhisker)));
|
||||
hiwhisker = quartiles(3) + 1.5*IQR;
|
||||
hiwhisker = min(hiwhisker, max(data(data < hiwhisker)));
|
||||
if ~isempty(lowhisker) && ~isempty(hiwhisker)
|
||||
obj.WhiskerPlot = plot([pos pos], [lowhisker hiwhisker]);
|
||||
end
|
||||
|
||||
% Median
|
||||
obj.MedianPlot = scatter(pos, quartiles(2), args.MedianMarkerSize, [1 1 1], 'filled');
|
||||
|
||||
% Notches
|
||||
obj.NotchPlots = ...
|
||||
scatter(pos, quartiles(2)-1.57*IQR/sqrt(length(data)), ...
|
||||
[], [1 1 1], 'filled', '^');
|
||||
obj.NotchPlots(2) = ...
|
||||
scatter(pos, quartiles(2)+1.57*IQR/sqrt(length(data)), ...
|
||||
[], [1 1 1], 'filled', 'v');
|
||||
|
||||
%% Set graphical preferences
|
||||
obj.EdgeColor = args.EdgeColor;
|
||||
obj.MedianPlot.LineWidth = args.LineWidth;
|
||||
obj.BoxColor = args.BoxColor;
|
||||
obj.BoxWidth = args.BoxWidth;
|
||||
obj.MedianColor = args.MedianColor;
|
||||
obj.ShowData = args.ShowData;
|
||||
obj.ShowNotches = args.ShowNotches;
|
||||
obj.ShowMean = args.ShowMean;
|
||||
obj.ShowBox = args.ShowBox;
|
||||
obj.ShowMedian = args.ShowMedian;
|
||||
obj.ShowWhiskers = args.ShowWhiskers;
|
||||
|
||||
if not(isempty(args.ViolinColor))
|
||||
if size(args.ViolinColor{1},1) > 1
|
||||
ViolinColor{1} = args.ViolinColor{1}(pos,:);
|
||||
else
|
||||
ViolinColor{1} = args.ViolinColor{1};
|
||||
end
|
||||
if length(args.ViolinColor)==2
|
||||
if size(args.ViolinColor{2},1) > 1
|
||||
ViolinColor{2} = args.ViolinColor{2}(pos,:);
|
||||
else
|
||||
ViolinColor{2} = args.ViolinColor{2};
|
||||
end
|
||||
else
|
||||
ViolinColor{2} = ViolinColor{1};
|
||||
end
|
||||
else
|
||||
% defaults
|
||||
if args.scpltBool
|
||||
ViolinColor{1} = obj.ScatterPlot.CData;
|
||||
else
|
||||
ViolinColor{1} = [0 0 0];
|
||||
end
|
||||
ViolinColor{2} = [0 0 0];
|
||||
end
|
||||
obj.ViolinColor = ViolinColor;
|
||||
|
||||
|
||||
if not(isempty(args.ViolinAlpha))
|
||||
if length(args.ViolinAlpha{1})>1
|
||||
error('Only scalar values are accepted for the alpha color channel');
|
||||
else
|
||||
ViolinAlpha{1} = args.ViolinAlpha{1};
|
||||
end
|
||||
if length(args.ViolinAlpha)==2
|
||||
if length(args.ViolinAlpha{2})>1
|
||||
error('Only scalar values are accepted for the alpha color channel');
|
||||
else
|
||||
ViolinAlpha{2} = args.ViolinAlpha{2};
|
||||
end
|
||||
else
|
||||
ViolinAlpha{2} = ViolinAlpha{1}/2; % default unless specified
|
||||
end
|
||||
else
|
||||
% default
|
||||
ViolinAlpha = {1,1};
|
||||
end
|
||||
obj.ViolinAlpha = ViolinAlpha;
|
||||
|
||||
|
||||
end
|
||||
|
||||
%% SET METHODS
|
||||
function set.EdgeColor(obj, color)
|
||||
if ~isempty(obj.ViolinPlot)
|
||||
obj.ViolinPlot.EdgeColor = color;
|
||||
obj.ViolinPlotQ.EdgeColor = color;
|
||||
if ~isempty(obj.ViolinPlot2)
|
||||
obj.ViolinPlot2.EdgeColor = color;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function color = get.EdgeColor(obj)
|
||||
if ~isempty(obj.ViolinPlot)
|
||||
color = obj.ViolinPlot.EdgeColor;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function set.MedianColor(obj, color)
|
||||
obj.MedianPlot.MarkerFaceColor = color;
|
||||
if ~isempty(obj.NotchPlots)
|
||||
obj.NotchPlots(1).MarkerFaceColor = color;
|
||||
obj.NotchPlots(2).MarkerFaceColor = color;
|
||||
end
|
||||
end
|
||||
|
||||
function color = get.MedianColor(obj)
|
||||
color = obj.MedianPlot.MarkerFaceColor;
|
||||
end
|
||||
|
||||
|
||||
function set.BoxColor(obj, color)
|
||||
if ~isempty(obj.BoxPlot)
|
||||
obj.BoxPlot.FaceColor = color;
|
||||
obj.BoxPlot.EdgeColor = color;
|
||||
obj.WhiskerPlot.Color = color;
|
||||
obj.MedianPlot.MarkerEdgeColor = color;
|
||||
obj.NotchPlots(1).MarkerFaceColor = color;
|
||||
obj.NotchPlots(2).MarkerFaceColor = color;
|
||||
elseif ~isempty(obj.ViolinPlotQ)
|
||||
obj.WhiskerPlot.Color = color;
|
||||
obj.MedianPlot.MarkerEdgeColor = color;
|
||||
obj.NotchPlots(1).MarkerFaceColor = color;
|
||||
obj.NotchPlots(2).MarkerFaceColor = color;
|
||||
end
|
||||
end
|
||||
|
||||
function color = get.BoxColor(obj)
|
||||
if ~isempty(obj.BoxPlot)
|
||||
color = obj.BoxPlot.FaceColor;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function set.BoxWidth(obj,width)
|
||||
if ~isempty(obj.BoxPlot)
|
||||
pos=mean(obj.BoxPlot.XData);
|
||||
obj.BoxPlot.XData=pos+[-1,1,1,-1]*width;
|
||||
end
|
||||
end
|
||||
|
||||
function width = get.BoxWidth(obj)
|
||||
width=max(obj.BoxPlot.XData)-min(obj.BoxPlot.XData);
|
||||
end
|
||||
|
||||
|
||||
function set.ViolinColor(obj, color)
|
||||
obj.ViolinPlot.FaceColor = color{1};
|
||||
obj.ScatterPlot.MarkerFaceColor = color{1};
|
||||
obj.MeanPlot.Color = color{1};
|
||||
if ~isempty(obj.ViolinPlot2)
|
||||
obj.ViolinPlot2.FaceColor = color{2};
|
||||
obj.ScatterPlot2.MarkerFaceColor = color{2};
|
||||
end
|
||||
if ~isempty(obj.ViolinPlotQ)
|
||||
obj.ViolinPlotQ.FaceColor = color{1};
|
||||
end
|
||||
for idx = 1: size(obj.HistogramPlot,1)
|
||||
obj.HistogramPlot(idx).Color = color{1};
|
||||
end
|
||||
end
|
||||
|
||||
function color = get.ViolinColor(obj)
|
||||
color{1} = obj.ViolinPlot.FaceColor;
|
||||
if ~isempty(obj.ViolinPlot2)
|
||||
color{2} = obj.ViolinPlot2.FaceColor;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function set.ViolinAlpha(obj, alpha)
|
||||
obj.ViolinPlotQ.FaceAlpha = .65;
|
||||
obj.ViolinPlot.FaceAlpha = alpha{1};
|
||||
obj.ScatterPlot.MarkerFaceAlpha = 1;
|
||||
if ~isempty(obj.ViolinPlot2)
|
||||
obj.ViolinPlot2.FaceAlpha = alpha{2};
|
||||
obj.ScatterPlot2.MarkerFaceAlpha = 1;
|
||||
end
|
||||
end
|
||||
|
||||
function alpha = get.ViolinAlpha(obj)
|
||||
alpha{1} = obj.ViolinPlot.FaceAlpha;
|
||||
if ~isempty(obj.ViolinPlot2)
|
||||
alpha{2} = obj.ViolinPlot2.FaceAlpha;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function set.ShowData(obj, yesno)
|
||||
if yesno
|
||||
obj.ScatterPlot.Visible = 'on';
|
||||
for idx = 1: size(obj.HistogramPlot,1)
|
||||
obj.HistogramPlot(idx).Visible = 'on';
|
||||
end
|
||||
else
|
||||
obj.ScatterPlot.Visible = 'off';
|
||||
for idx = 1: size(obj.HistogramPlot,1)
|
||||
obj.HistogramPlot(idx).Visible = 'off';
|
||||
end
|
||||
end
|
||||
if ~isempty(obj.ScatterPlot2)
|
||||
obj.ScatterPlot2.Visible = obj.ScatterPlot.Visible;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function yesno = get.ShowData(obj)
|
||||
if ~isempty(obj.ScatterPlot)
|
||||
yesno = strcmp(obj.ScatterPlot.Visible, 'on');
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function set.ShowNotches(obj, yesno)
|
||||
if ~isempty(obj.NotchPlots)
|
||||
if yesno
|
||||
obj.NotchPlots(1).Visible = 'on';
|
||||
obj.NotchPlots(2).Visible = 'on';
|
||||
else
|
||||
obj.NotchPlots(1).Visible = 'off';
|
||||
obj.NotchPlots(2).Visible = 'off';
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function yesno = get.ShowNotches(obj)
|
||||
if ~isempty(obj.NotchPlots)
|
||||
yesno = strcmp(obj.NotchPlots(1).Visible, 'on');
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function set.ShowMean(obj, yesno)
|
||||
if ~isempty(obj.MeanPlot)
|
||||
if yesno
|
||||
obj.MeanPlot.Visible = 'on';
|
||||
else
|
||||
obj.MeanPlot.Visible = 'off';
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function yesno = get.ShowMean(obj)
|
||||
if ~isempty(obj.BoxPlot)
|
||||
yesno = strcmp(obj.BoxPlot.Visible, 'on');
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function set.ShowBox(obj, yesno)
|
||||
if ~isempty(obj.BoxPlot)
|
||||
if yesno
|
||||
obj.BoxPlot.Visible = 'on';
|
||||
else
|
||||
obj.BoxPlot.Visible = 'off';
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function yesno = get.ShowBox(obj)
|
||||
if ~isempty(obj.BoxPlot)
|
||||
yesno = strcmp(obj.BoxPlot.Visible, 'on');
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function set.ShowMedian(obj, yesno)
|
||||
if ~isempty(obj.MedianPlot)
|
||||
if yesno
|
||||
obj.MedianPlot.Visible = 'on';
|
||||
else
|
||||
obj.MedianPlot.Visible = 'off';
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function yesno = get.ShowMedian(obj)
|
||||
if ~isempty(obj.MedianPlot)
|
||||
yesno = strcmp(obj.MedianPlot.Visible, 'on');
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function set.ShowWhiskers(obj, yesno)
|
||||
if ~isempty(obj.WhiskerPlot)
|
||||
if yesno
|
||||
obj.WhiskerPlot.Visible = 'on';
|
||||
else
|
||||
obj.WhiskerPlot.Visible = 'off';
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function yesno = get.ShowWhiskers(obj)
|
||||
if ~isempty(obj.WhiskerPlot)
|
||||
yesno = strcmp(obj.WhiskerPlot.Visible, 'on');
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
methods (Access=private)
|
||||
function results = checkInputs(~, data, pos, varargin)
|
||||
isscalarnumber = @(x) (isnumeric(x) & isscalar(x));
|
||||
p = inputParser();
|
||||
p.addRequired('Data', @(x)isnumeric(vertcat(x{:})));
|
||||
p.addRequired('Pos', isscalarnumber);
|
||||
p.addParameter('Width', 0.3, isscalarnumber);
|
||||
p.addParameter('Bandwidth', [], isscalarnumber);
|
||||
iscolor = @(x) (isnumeric(x) & size(x,2) == 3);
|
||||
p.addParameter('ViolinColor', [], @(x)iscolor(vertcat(x{:})));
|
||||
p.addParameter('MarkerSize', 24, @isnumeric);
|
||||
p.addParameter('MedianMarkerSize', 36, @isnumeric);
|
||||
p.addParameter('LineWidth', 0.75, @isnumeric);
|
||||
p.addParameter('BoxColor', [0.5 0.5 0.5], iscolor);
|
||||
p.addParameter('BoxWidth', 0.01, isscalarnumber);
|
||||
p.addParameter('EdgeColor', [0.5 0.5 0.5], iscolor);
|
||||
p.addParameter('MedianColor', [1 1 1], iscolor);
|
||||
p.addParameter('ViolinAlpha', {0.3,0.15}, @(x)isnumeric(vertcat(x{:})));
|
||||
isscalarlogical = @(x) (islogical(x) & isscalar(x));
|
||||
p.addParameter('ShowData', true, isscalarlogical);
|
||||
p.addParameter('ShowNotches', false, isscalarlogical);
|
||||
p.addParameter('ShowMean', false, isscalarlogical);
|
||||
p.addParameter('ShowBox', true, isscalarlogical);
|
||||
p.addParameter('ShowMedian', true, isscalarlogical);
|
||||
p.addParameter('ShowWhiskers', true, isscalarlogical);
|
||||
validSides={'full', 'right', 'left'};
|
||||
checkSide = @(x) any(validatestring(x, validSides));
|
||||
p.addParameter('HalfViolin', 'full', checkSide);
|
||||
validQuartileStyles={'boxplot', 'shadow', 'none'};
|
||||
checkQuartile = @(x)any(validatestring(x, validQuartileStyles));
|
||||
p.addParameter('QuartileStyle', 'boxplot', checkQuartile);
|
||||
validDataStyles = {'scatter', 'histogram', 'none'};
|
||||
checkStyle = @(x)any(validatestring(x, validDataStyles));
|
||||
p.addParameter('DataStyle', 'scatter', checkStyle);
|
||||
|
||||
p.parse(data, pos, varargin{:});
|
||||
results = p.Results;
|
||||
end
|
||||
end
|
||||
|
||||
methods (Static)
|
||||
function [density, value, width] = calcKernelDensity(data, bandwidth, width)
|
||||
if isempty(data)
|
||||
error('Empty input data');
|
||||
end
|
||||
[density, value] = ksdensity(data, 'bandwidth', bandwidth);
|
||||
density = density(value >= min(data) & value <= max(data));
|
||||
value = value(value >= min(data) & value <= max(data));
|
||||
value(1) = min(data);
|
||||
value(end) = max(data);
|
||||
value = [value(1)*(1-1E-5), value, value(end)*(1+1E-5)];
|
||||
density = [0, density, 0];
|
||||
|
||||
% all data is identical
|
||||
if min(data) == max(data)
|
||||
density = 1;
|
||||
value= mean(value);
|
||||
end
|
||||
|
||||
width = width/max(density);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1,87 @@
|
||||
function testviolinplot()
|
||||
figure();
|
||||
% One could use tiled layout for better plotting them but it would be
|
||||
% incompatible with older versions
|
||||
subplot(2,4,1);
|
||||
|
||||
% TEST CASE 1
|
||||
disp('Test 1: Violin plot default options');
|
||||
load carbig MPG Origin
|
||||
Origin = cellstr(Origin);
|
||||
vs = violinplot(MPG, Origin);
|
||||
plotdetails(1);
|
||||
|
||||
% TEST CASE 2
|
||||
disp('Test 2: Test the plot ordering option');
|
||||
grouporder={'USA','Sweden','Japan','Italy','Germany','France','England'};
|
||||
|
||||
subplot(2,4,2);
|
||||
vs2 = violinplot(MPG,Origin,'GroupOrder',grouporder);
|
||||
plotdetails(2);
|
||||
|
||||
% TEST CASE 3
|
||||
disp('Test 3: Test the numeric input construction mode');
|
||||
subplot(2,4,3);
|
||||
cats = categorical(Origin);
|
||||
catnames = (unique(cats)); % this ignores categories without any data
|
||||
catnames_labels = {};
|
||||
thisData = NaN(length(MPG),length(catnames));
|
||||
for n = 1:length(catnames)
|
||||
thisCat = catnames(n);
|
||||
catnames_labels{n} = char(thisCat);
|
||||
thisData(1:length(MPG(cats == thisCat)),n) = MPG(cats == thisCat);
|
||||
end
|
||||
vs3 = violinplot(thisData,catnames_labels);
|
||||
plotdetails(3);
|
||||
|
||||
% TEST CASE 4
|
||||
disp('Test 4: Test two sided violin plots. Japan is being compared.');
|
||||
subplot(2,4,4);
|
||||
C = colororder;
|
||||
vs4 = violinplot({thisData,repmat(thisData(:,5),1,7)},catnames_labels,'ViolinColor',{C,C(5,:)},'ViolinAlpha',{0.3 0.3}, 'ShowMean', true, 'MarkerSize',8);
|
||||
plotdetails(4);
|
||||
|
||||
% TEST CASE 5
|
||||
disp('Test 5: Test shadow for quartiles.');
|
||||
subplot(2,4,5);
|
||||
vs5 = violinplot(MPG, Origin, 'QuartileStyle','shadow');
|
||||
plotdetails(5);
|
||||
|
||||
% TEST CASE 6
|
||||
disp('Test 6: Test plotting only right side & histogram plot, with quartiles as boxplot.');
|
||||
subplot(2,4,6);
|
||||
vs5 = violinplot(MPG, Origin, 'QuartileStyle','boxplot', 'HalfViolin','right',...
|
||||
'DataStyle', 'histogram');
|
||||
plotdetails(6);
|
||||
|
||||
% TEST CASE 7
|
||||
disp('Test 7: Test plotting only left side & histogram plot, and quartiles as shadow.');
|
||||
subplot(2,4,7);
|
||||
vs5 = violinplot(MPG, Origin, 'QuartileStyle','shadow', 'HalfViolin','left',...
|
||||
'DataStyle', 'histogram', 'ShowMean', true);
|
||||
plotdetails(7);
|
||||
|
||||
|
||||
% TEST CASE 8
|
||||
disp('Test 8: Same as previous one, just removing the data of half of the violins afterwards.');
|
||||
subplot(2,4,8);
|
||||
vs5 = violinplot([MPG; 5;5;5;5;5], [Origin; 'test';'test';'test';'test';'test'], 'QuartileStyle','shadow', 'HalfViolin','full',...
|
||||
'DataStyle', 'scatter', 'ShowMean', false);
|
||||
plotdetails(8);
|
||||
for n= 1:round(length(vs5)/2)
|
||||
vs5(1,n).ShowData = 0;
|
||||
end
|
||||
xlim([0, 9]);
|
||||
%other test cases could be added here
|
||||
|
||||
end
|
||||
|
||||
function plotdetails(n)
|
||||
title(sprintf('Test %02.0f \n',n));
|
||||
ylabel('Fuel Economy in MPG ');
|
||||
xlim([0, 8]); grid minor;
|
||||
set(gca, 'color', 'none');
|
||||
xtickangle(-30);
|
||||
fprintf('Test %02.0f passed ok! \n ',n);
|
||||
end
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
function violins = violinplot(data, cats, varargin)
|
||||
%Violinplots plots violin plots of some data and categories
|
||||
% VIOLINPLOT(DATA) plots a violin of a double vector DATA
|
||||
%
|
||||
% VIOLINPLOT(DATAMATRIX) plots violins for each column in
|
||||
% DATAMATRIX.
|
||||
%
|
||||
% VIOLINPLOT(DATAMATRIX, CATEGORYNAMES) plots violins for each
|
||||
% column in DATAMATRIX and labels them according to the names in the
|
||||
% cell-of-strings CATEGORYNAMES.
|
||||
%
|
||||
% In the cases above DATA and DATAMATRIX can be a vector or a matrix,
|
||||
% respectively, either as is or wrapped in a cell.
|
||||
% To produce violins which have one distribution on one half and another
|
||||
% one on the other half, DATA and DATAMATRIX have to be cell arrays
|
||||
% with two elements, each containing a vector or a matrix. The number of
|
||||
% columns of the two data sets has to be the same.
|
||||
%
|
||||
% VIOLINPLOT(DATA, CATEGORIES) where double vector DATA and vector
|
||||
% CATEGORIES are of equal length; plots violins for each category in
|
||||
% DATA.
|
||||
%
|
||||
% VIOLINPLOT(TABLE), VIOLINPLOT(STRUCT), VIOLINPLOT(DATASET)
|
||||
% plots violins for each column in TABLE, each field in STRUCT, and
|
||||
% each variable in DATASET. The violins are labeled according to
|
||||
% the table/dataset variable name or the struct field name.
|
||||
%
|
||||
% violins = VIOLINPLOT(...) returns an object array of
|
||||
% <a href="matlab:help('Violin')">Violin</a> objects.
|
||||
%
|
||||
% VIOLINPLOT(..., 'PARAM1', val1, 'PARAM2', val2, ...)
|
||||
% specifies optional name/value pairs for all violins:
|
||||
% 'Width' Width of the violin in axis space.
|
||||
% Defaults to 0.3
|
||||
% 'Bandwidth' Bandwidth of the kernel density estimate.
|
||||
% Should be between 10% and 40% of the data range.
|
||||
% 'ViolinColor' Fill color of the violin area and data points. Accepts
|
||||
% 1x3 color vector or nx3 color vector where n = num
|
||||
% groups. In case of two data sets being compared it can
|
||||
% be an array of up to two cells containing nx3
|
||||
% matrices.
|
||||
% Defaults to the next default color cycle.
|
||||
% 'ViolinAlpha' Transparency of the violin area and data points.
|
||||
% Can be either a single scalar value or an array of
|
||||
% up to two cells containing scalar values.
|
||||
% Defaults to 0.3.
|
||||
% 'MarkerSize' Size of the data points, if shown.
|
||||
% Defaults to 24
|
||||
% 'MedianMarkerSize' Size of the median indicator, if shown.
|
||||
% Defaults to 36
|
||||
% 'EdgeColor' Color of the violin area outline.
|
||||
% Defaults to [0.5 0.5 0.5]
|
||||
% 'BoxColor' Color of the box, whiskers, and the outlines of
|
||||
% the median point and the notch indicators.
|
||||
% Defaults to [0.5 0.5 0.5]
|
||||
% 'MedianColor' Fill color of the median and notch indicators.
|
||||
% Defaults to [1 1 1]
|
||||
% 'ShowData' Whether to show data points.
|
||||
% Defaults to true
|
||||
% 'ShowNotches' Whether to show notch indicators.
|
||||
% Defaults to false
|
||||
% 'ShowMean' Whether to show mean indicator
|
||||
% Defaults to false
|
||||
% 'ShowBox' Whether to show the box.
|
||||
% Defaults to true
|
||||
% 'ShowMedian' Whether to show the median indicator.
|
||||
% Defaults to true
|
||||
% 'ShowWhiskers' Whether to show the whiskers
|
||||
% Defaults to true
|
||||
% 'GroupOrder' Cell of category names in order to be plotted.
|
||||
% Defaults to alphabetical ordering
|
||||
|
||||
% Copyright (c) 2016, Bastian Bechtold
|
||||
% This code is released under the terms of the BSD 3-clause license
|
||||
|
||||
hascategories = exist('cats','var') && not(isempty(cats));
|
||||
|
||||
%parse the optional grouporder argument
|
||||
%if it exists parse the categories order
|
||||
% but also delete it from the arguments passed to Violin
|
||||
grouporder = {};
|
||||
idx=find(strcmp(varargin, 'GroupOrder'));
|
||||
if ~isempty(idx) && numel(varargin)>idx
|
||||
if iscell(varargin{idx+1})
|
||||
grouporder = varargin{idx+1};
|
||||
varargin(idx:idx+1)=[];
|
||||
else
|
||||
error('Second argument of ''GroupOrder'' optional arg must be a cell of category names')
|
||||
end
|
||||
end
|
||||
|
||||
% check and correct the structure of ViolinColor input
|
||||
idx=find(strcmp(varargin, 'ViolinColor'));
|
||||
if ~isempty(idx) && iscell(varargin{idx+1})
|
||||
if length(varargin{idx+1}(:))>2
|
||||
error('ViolinColor input can be at most a two element cell array');
|
||||
end
|
||||
elseif ~isempty(idx) && isnumeric(varargin{idx+1})
|
||||
varargin{idx+1} = varargin(idx+1);
|
||||
end
|
||||
|
||||
% check and correct the structure of ViolinAlpha input
|
||||
idx=find(strcmp(varargin, 'ViolinAlpha'));
|
||||
if ~isempty(idx) && iscell(varargin{idx+1})
|
||||
if length(varargin{idx+1}(:))>2
|
||||
error('ViolinAlpha input can be at most a two element cell array');
|
||||
end
|
||||
elseif ~isempty(idx) && isnumeric(varargin{idx+1})
|
||||
varargin{idx+1} = varargin(idx+1);
|
||||
end
|
||||
|
||||
% tabular data
|
||||
if isa(data, 'dataset') || isstruct(data) || istable(data)
|
||||
if isa(data, 'dataset')
|
||||
colnames = data.Properties.VarNames;
|
||||
elseif istable(data)
|
||||
colnames = data.Properties.VariableNames;
|
||||
elseif isstruct(data)
|
||||
colnames = fieldnames(data);
|
||||
end
|
||||
catnames = {};
|
||||
if isempty(grouporder)
|
||||
for n=1:length(colnames)
|
||||
if isnumeric(data.(colnames{n}))
|
||||
catnames = [catnames colnames{n}]; %#ok<*AGROW>
|
||||
end
|
||||
end
|
||||
catnames = sort(catnames);
|
||||
else
|
||||
for n=1:length(grouporder)
|
||||
if isnumeric(data.(grouporder{n}))
|
||||
catnames = [catnames grouporder{n}];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for n=1:length(catnames)
|
||||
thisData = data.(catnames{n});
|
||||
violins(n) = Violin({thisData}, n, varargin{:});
|
||||
end
|
||||
set(gca, 'XTick', 1:length(catnames), 'XTickLabels', catnames);
|
||||
set(gca,'Box','on');
|
||||
return
|
||||
elseif iscell(data) && length(data(:))==2 % cell input
|
||||
if not(size(data{1},2)==size(data{2},2))
|
||||
error('The two input data matrices have to have the same number of columns');
|
||||
end
|
||||
elseif iscell(data) && length(data(:))>2 % cell input
|
||||
error('Up to two datasets can be compared');
|
||||
elseif isnumeric(data) % numeric input
|
||||
% 1D data, one category for each data point
|
||||
if hascategories && numel(data) == numel(cats)
|
||||
if isempty(grouporder)
|
||||
cats = categorical(cats);
|
||||
else
|
||||
cats = categorical(cats, grouporder);
|
||||
end
|
||||
|
||||
catnames = (unique(cats)); % this ignores categories without any data
|
||||
catnames_labels = {};
|
||||
for n = 1:length(catnames)
|
||||
thisCat = catnames(n);
|
||||
catnames_labels{n} = char(thisCat);
|
||||
thisData = data(cats == thisCat);
|
||||
violins(n) = Violin({thisData}, n, varargin{:});
|
||||
end
|
||||
set(gca, 'XTick', 1:length(catnames), 'XTickLabels', catnames_labels);
|
||||
set(gca,'Box','on');
|
||||
return
|
||||
else
|
||||
data = {data};
|
||||
end
|
||||
end
|
||||
|
||||
% 1D data, no categories
|
||||
if not(hascategories) && isvector(data{1})
|
||||
violins = Violin(data, 1, varargin{:});
|
||||
set(gca, 'XTick', 1);
|
||||
% 2D data with or without categories
|
||||
elseif ismatrix(data{1})
|
||||
for n=1:size(data{1}, 2)
|
||||
thisData = cellfun(@(x)x(:,n),data,'UniformOutput',false);
|
||||
violins(n) = Violin(thisData, n, varargin{:});
|
||||
end
|
||||
set(gca, 'XTick', 1:size(data{1}, 2));
|
||||
if hascategories && length(cats) == size(data{1}, 2)
|
||||
set(gca, 'XTickLabels', cats);
|
||||
end
|
||||
end
|
||||
|
||||
set(gca,'Box','on');
|
||||
|
||||
end
|
||||
115
Functions/helper_functions_community/autoArrangeFigures.m
Normal file
@@ -0,0 +1,115 @@
|
||||
function autoArrangeFigures(NH, NW, monitor_id)
|
||||
% INPUT :
|
||||
% NH : number of grid of vertical direction
|
||||
% NW : number of grid of horizontal direction
|
||||
% OUTPUT :
|
||||
%
|
||||
% get every figures that are opened now and arrange them.
|
||||
%
|
||||
% autoArrangeFigures selects automatically Monitor1.
|
||||
% If you are dual(or more than that) monitor user, I recommend to set wide
|
||||
% monitor as Monitor1.
|
||||
%
|
||||
% if you want arrange automatically, type 'autoArrangeFigures(0,0)' or 'autoArrangeFigures()'.
|
||||
% But maximum number of figures for automatic mode is 27.
|
||||
%
|
||||
% if you want specify grid for figures, give numbers for parameters.
|
||||
% but if your grid size is smaller than required one for accommodating
|
||||
% all figures, this function changes to automatic mode and if more
|
||||
% figures are opend than maximum number, then it gives error.
|
||||
%
|
||||
% Notes
|
||||
% + 2017.1.20 use monitor id(Adam Danz's idea)
|
||||
%
|
||||
% leejaejun, Koreatech, Korea Republic, 2014.12.13
|
||||
% jaejun0201@gmail.com
|
||||
|
||||
if nargin < 2
|
||||
NH = 0;
|
||||
NW = 0;
|
||||
monitor_id = 1;
|
||||
end
|
||||
|
||||
task_bar_offset = [30 50];
|
||||
|
||||
%%
|
||||
N_FIG = NH * NW;
|
||||
if N_FIG == 0
|
||||
autoArrange = 1;
|
||||
else
|
||||
autoArrange = 0;
|
||||
end
|
||||
figHandle = sortFigureHandles(findobj('Type','figure'));
|
||||
|
||||
moveitHandle = findall(figHandle, 'Type', 'figure', 'Tag', 'Hfroot');
|
||||
|
||||
figHandle = figHandle(ismember(figHandle,moveitHandle)~=1);
|
||||
|
||||
n_fig = size(figHandle,1);
|
||||
|
||||
if n_fig <= 0
|
||||
warning('figures are not found');
|
||||
return
|
||||
end
|
||||
|
||||
screen_sz = get(0,'MonitorPositions');
|
||||
screen_sz = screen_sz(monitor_id, :);
|
||||
scn_w = screen_sz(3) - task_bar_offset(1);
|
||||
scn_h = screen_sz(4) - task_bar_offset(2);
|
||||
scn_w_begin = screen_sz(1) + task_bar_offset(1);
|
||||
scn_h_begin = screen_sz(2) + task_bar_offset(2);
|
||||
|
||||
if autoArrange==0
|
||||
if n_fig > N_FIG
|
||||
autoArrange = 1;
|
||||
warning('too many figures than you told. change to autoArrange');
|
||||
else
|
||||
nh = NH;
|
||||
nw = NW;
|
||||
end
|
||||
end
|
||||
|
||||
if autoArrange == 1
|
||||
grid = [2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4;
|
||||
3 3 3 3 3 3 3 3 4 4 4 5 5 5 5 5 5 5 5 6 6 6 7 7 7 7 7]';
|
||||
|
||||
if n_fig > length(grid)
|
||||
warning('too many figures(maximum = %d)',length(grid))
|
||||
return
|
||||
end
|
||||
|
||||
if scn_w > scn_h
|
||||
nh = grid(n_fig,1);
|
||||
nw = grid(n_fig,2);
|
||||
else
|
||||
nh = grid(n_fig,2);
|
||||
nw = grid(n_fig,1);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
fig_width = scn_w/nw;
|
||||
fig_height = scn_h/nh;
|
||||
|
||||
fig_cnt = 1;
|
||||
for i=1:1:nh
|
||||
for k=1:1:nw
|
||||
if fig_cnt>n_fig
|
||||
return
|
||||
end
|
||||
fig_pos = [scn_w_begin+fig_width*(k-1) ...
|
||||
scn_h_begin+scn_h-fig_height*i ...
|
||||
fig_width ...
|
||||
fig_height];
|
||||
set(figHandle(fig_cnt),'OuterPosition',fig_pos);
|
||||
figure(figHandle(fig_cnt)); %bring to top
|
||||
fig_cnt = fig_cnt + 1;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function figSorted = sortFigureHandles(figs)
|
||||
[tmp, idx] = sort([figs.Number]);
|
||||
figSorted = figs(idx);
|
||||
end
|
||||
45
Functions/helper_functions_community/boundedlines/.gitignore
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# MATLAB #
|
||||
##########
|
||||
# Editor autosave files
|
||||
*~
|
||||
*.asv
|
||||
# Compiled MEX binaries (all platforms)
|
||||
*.mex*
|
||||
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
*.class
|
||||
*.dll
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
|
||||
# Packages #
|
||||
############
|
||||
# it's better to unpack these files and commit the raw source
|
||||
# git has its own built in compression methods
|
||||
*.7z
|
||||
*.dmg
|
||||
*.gz
|
||||
*.iso
|
||||
*.jar
|
||||
*.rar
|
||||
*.tar
|
||||
*.zip
|
||||
|
||||
# Logs and databases #
|
||||
######################
|
||||
*.log
|
||||
*.sql
|
||||
*.sqlite
|
||||
|
||||
# OS generated files #
|
||||
######################
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
37
Functions/helper_functions_community/boundedlines/Inpaint_nans/.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
*.class
|
||||
*.dll
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
|
||||
# Packages #
|
||||
############
|
||||
# it's better to unpack these files and commit the raw source
|
||||
# git has its own built in compression methods
|
||||
*.7z
|
||||
*.dmg
|
||||
*.gz
|
||||
*.iso
|
||||
*.jar
|
||||
*.rar
|
||||
*.tar
|
||||
*.zip
|
||||
|
||||
# Logs and databases #
|
||||
######################
|
||||
*.log
|
||||
*.sql
|
||||
*.sqlite
|
||||
|
||||
# OS generated files #
|
||||
######################
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
@@ -0,0 +1,161 @@
|
||||
<html xmlns:mwsh="http://www.mathworks.com/namespace/mcode/v1/syntaxhighlight.dtd">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<!--
|
||||
This HTML is auto-generated from an M-file.
|
||||
To make changes, update the M-file and republish this document.
|
||||
-->
|
||||
<title>inpaint_nans_demo</title>
|
||||
<meta name="generator" content="MATLAB 7.0.1">
|
||||
<meta name="date" content="2006-06-28">
|
||||
<meta name="m-file" content="inpaint_nans_demo"><style>
|
||||
body {
|
||||
background-color: white;
|
||||
margin:10px;
|
||||
}
|
||||
h1 {
|
||||
color: #990000;
|
||||
font-size: x-large;
|
||||
}
|
||||
h2 {
|
||||
color: #990000;
|
||||
font-size: medium;
|
||||
}
|
||||
p.footer {
|
||||
text-align: right;
|
||||
font-size: xx-small;
|
||||
font-weight: lighter;
|
||||
font-style: italic;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
pre.codeinput {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
span.keyword {color: #0000FF}
|
||||
span.comment {color: #228B22}
|
||||
span.string {color: #A020F0}
|
||||
span.untermstring {color: #B20000}
|
||||
span.syscmd {color: #B28C00}
|
||||
|
||||
pre.showbuttons {
|
||||
margin-left: 30px;
|
||||
border: solid black 2px;
|
||||
padding: 4px;
|
||||
background: #EBEFF3;
|
||||
}
|
||||
|
||||
pre.codeoutput {
|
||||
color: gray;
|
||||
font-style: italic;
|
||||
}
|
||||
pre.error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* Make the text shrink to fit narrow windows, but not stretch too far in
|
||||
wide windows. On Gecko-based browsers, the shrink-to-fit doesn't work. */
|
||||
p,h1,h2,div {
|
||||
/* for MATLAB's browser */
|
||||
width: 600px;
|
||||
/* for Mozilla, but the "width" tag overrides it anyway */
|
||||
max-width: 600px;
|
||||
/* for IE */
|
||||
width:expression(document.body.clientWidth > 620 ? "600px": "auto" );
|
||||
}
|
||||
|
||||
</style></head>
|
||||
<body><pre class="codeinput"><span class="comment">% Surface fit artifact removal</span>
|
||||
[x,y] = meshgrid(0:.01:1);
|
||||
z0 = exp(x+y);
|
||||
|
||||
znan = z0;
|
||||
znan(20:50,40:70) = NaN;
|
||||
znan(30:90,5:10) = NaN;
|
||||
znan(70:75,40:90) = NaN;
|
||||
|
||||
z = inpaint_nans(znan,3);
|
||||
|
||||
<span class="comment">% Comparison to griddata</span>
|
||||
k = isnan(znan);
|
||||
zk = griddata(x(~k),y(~k),z(~k),x(k),y(k));
|
||||
zg = znan;
|
||||
zg(k) = zk;
|
||||
|
||||
close <span class="string">all</span>
|
||||
figure
|
||||
surf(z0)
|
||||
title <span class="string">'Original surface'</span>
|
||||
|
||||
figure
|
||||
surf(znan)
|
||||
title <span class="string">'Artifacts (large holes) in surface'</span>
|
||||
|
||||
figure
|
||||
surf(zg)
|
||||
title([<span class="string">'Griddata inpainting ('</span>,num2str(sum(isnan(zg(:)))),<span class="string">' NaNs remain)'</span>])
|
||||
|
||||
figure
|
||||
surf(z)
|
||||
title <span class="string">'Inpainted surface'</span>
|
||||
|
||||
figure
|
||||
surf(zg-z0)
|
||||
title <span class="string">'Griddata error surface'</span>
|
||||
|
||||
figure
|
||||
surf(z-z0)
|
||||
title <span class="string">'Inpainting error surface (Note z-axis scale)'</span>
|
||||
</pre><img vspace="5" hspace="5" src="inpaint_nans_demo_01.png"> <img vspace="5" hspace="5" src="inpaint_nans_demo_02.png"> <img vspace="5" hspace="5" src="inpaint_nans_demo_03.png"> <img vspace="5" hspace="5" src="inpaint_nans_demo_04.png"> <img vspace="5" hspace="5" src="inpaint_nans_demo_05.png"> <img vspace="5" hspace="5" src="inpaint_nans_demo_06.png"> <p class="footer"><br>
|
||||
Published with MATLAB® 7.0.1<br></p>
|
||||
<!--
|
||||
##### SOURCE BEGIN #####
|
||||
% Surface fit artifact removal
|
||||
[x,y] = meshgrid(0:.01:1);
|
||||
z0 = exp(x+y);
|
||||
|
||||
znan = z0;
|
||||
znan(20:50,40:70) = NaN;
|
||||
znan(30:90,5:10) = NaN;
|
||||
znan(70:75,40:90) = NaN;
|
||||
|
||||
z = inpaint_nans(znan,3);
|
||||
|
||||
% Comparison to griddata
|
||||
k = isnan(znan);
|
||||
zk = griddata(x(~k),y(~k),z(~k),x(k),y(k));
|
||||
zg = znan;
|
||||
zg(k) = zk;
|
||||
|
||||
close all
|
||||
figure
|
||||
surf(z0)
|
||||
title 'Original surface'
|
||||
|
||||
figure
|
||||
surf(znan)
|
||||
title 'Artifacts (large holes) in surface'
|
||||
|
||||
figure
|
||||
surf(zg)
|
||||
title(['Griddata inpainting (',num2str(sum(isnan(zg(:)))),' NaNs remain)'])
|
||||
|
||||
figure
|
||||
surf(z)
|
||||
title 'Inpainted surface'
|
||||
|
||||
figure
|
||||
surf(zg-z0)
|
||||
title 'Griddata error surface'
|
||||
|
||||
figure
|
||||
surf(z-z0)
|
||||
title 'Inpainting error surface (Note z-axis scale)'
|
||||
|
||||
|
||||
##### SOURCE END #####
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
@@ -0,0 +1,42 @@
|
||||
% Surface fit artifact removal
|
||||
[x,y] = meshgrid(0:.01:1);
|
||||
z0 = exp(x+y);
|
||||
|
||||
znan = z0;
|
||||
znan(20:50,40:70) = NaN;
|
||||
znan(30:90,5:10) = NaN;
|
||||
znan(70:75,40:90) = NaN;
|
||||
|
||||
z = inpaint_nans(znan,3);
|
||||
|
||||
% Comparison to griddata
|
||||
k = isnan(znan);
|
||||
zk = griddata(x(~k),y(~k),z(~k),x(k),y(k));
|
||||
zg = znan;
|
||||
zg(k) = zk;
|
||||
|
||||
close all
|
||||
figure
|
||||
surf(z0)
|
||||
title 'Original surface'
|
||||
|
||||
figure
|
||||
surf(znan)
|
||||
title 'Artifacts (large holes) in surface'
|
||||
|
||||
figure
|
||||
surf(zg)
|
||||
title(['Griddata inpainting (',num2str(sum(isnan(zg(:)))),' NaNs remain)'])
|
||||
|
||||
figure
|
||||
surf(z)
|
||||
title 'Inpainted surface'
|
||||
|
||||
figure
|
||||
surf(zg-z0)
|
||||
title 'Griddata error surface'
|
||||
|
||||
figure
|
||||
surf(z-z0)
|
||||
title 'Inpainting error surface (Note z-axis scale)'
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
{\rtf1\mac\ansicpg10000\cocoartf102
|
||||
{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
\margl1440\margr1440\vieww10780\viewh13720\viewkind0
|
||||
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural
|
||||
|
||||
\f0\fs24 \cf0 Nomination comments:\
|
||||
\
|
||||
Inpaint_nans fills a hole in matlab. (Yes, the pun was intentional.) But there\
|
||||
is indeed a niche that inpaint_nans falls into.\
|
||||
\
|
||||
The alternative to inpaint_nans is griddata (interp1 can be used for the 1-d \
|
||||
problems) but griddata fails to extrapolate well. Griddata also has serious\
|
||||
problems when its data already lies on a grid, due to its use of a Delaunay \
|
||||
triangulation. The other serious problem with the use of griddata is the\
|
||||
triangulation itself. The shape of the hole to be filled can sometimes result\
|
||||
in triangles with a poor aspect ratio (long, thin triangles) which are in turn\
|
||||
poor for interpolation. In fact, Griddata can even leave interior points\
|
||||
uninterpolated (see the tests.)\
|
||||
\
|
||||
A future plan for inpaint_nans is to add an option that will use a locally\
|
||||
anisotropic membrane model. This will allow better modeling for certain\
|
||||
classes of wavy surfaces. I'm also highly tempted to remove method 5.\
|
||||
I've never really liked it, having put it in at the request of one user. It has\
|
||||
no valid theory behind it in the context of inpaint_nans.\
|
||||
\
|
||||
In the interest of openness, I'll also say what inpaint_nans does not do. It\
|
||||
does not handle non-uniform grids. It is limited by the amount of memory \
|
||||
in the size of the arrays it can handle, although some of the methods were\
|
||||
explicitly provided to be more memory efficient than others. Inpaint_nans\
|
||||
also makes heavy use of sparse matrices, so surprisingly large problems\
|
||||
are accessible.\
|
||||
\
|
||||
Finally, while inpaint_nans does work for 1-d problems, they are not my\
|
||||
target. Interp1 (with 'spline' as the method) is as accurate, and should be\
|
||||
faster in general.\
|
||||
\
|
||||
John\
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
%{
|
||||
|
||||
The methods of inpaint_nans
|
||||
|
||||
Digital inpainting is the craft of replacing missing elements in an
|
||||
"image" array. A Google search on the words "digita inpainting" will turn
|
||||
up many hits. I just tried this search and found 18300 hits.
|
||||
|
||||
If you wish to do inpainting in matlab, one place to start is with my
|
||||
inpaint_nans code. Inpaint_nans is on the file exchange:
|
||||
|
||||
http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=4551&objectType=file
|
||||
|
||||
It looks for NaN elements in an array (or vector) and attempts to interpolate
|
||||
(or extrapolate) smoothly to replace those elements.
|
||||
|
||||
The name "inpainting" itself comes from the world of art restoration.
|
||||
Damaged paintings are restored by an artist/craftsman skilled in matching
|
||||
the style of the original artist to fill in any holes in the painting.
|
||||
|
||||
In digital inpainting, the goal is to interpolate in from the boundaries
|
||||
of a hole to smoothly replace an artifact. Obviously, where the hole is
|
||||
large the digitally inpainted repair may not be an accurate approximation
|
||||
to the original.
|
||||
|
||||
Inpaint_nans itself is really only a boundary value solver. The basic idea
|
||||
is to formulate a partial differential equation (PDE) that is assumed to
|
||||
apply in the domain of the artifact to be inpainted. The perimeter of the
|
||||
hole supplies boundary values for the PDE. Then the PDE is approximated
|
||||
using finite difference methods (the array elements are assumed to be
|
||||
equally spaced in each dimension) and then a large (and very sparse) linear
|
||||
system of equations is solved for the NaN elements in the array.
|
||||
|
||||
I've chosen a variety of simple differental equation models the user can
|
||||
specify to be solved. All the methods current use a basically elliptic
|
||||
PDE. This means that the resulting linear system will generally be well
|
||||
conditioned. It does mean that the solution will generally be fairly smooth,
|
||||
and over large holes, it will tend towards an average of the boundary
|
||||
elements. These are characteristics of the elliptic PDEs chosen. (My hope
|
||||
is to expand these options in the future.)
|
||||
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
% Lets formulate a simple problem, and see how we could solve it using
|
||||
% some of these ideas.
|
||||
A = [0 0 0 0;1 NaN NaN 4;2 3 5 8];
|
||||
|
||||
% Although we can't plot this matrix using the functions surf or mesh,
|
||||
% surely we can visualize what the fudamental shape is.
|
||||
|
||||
% There are only two unknown elements, the artifacts that inpaint_nans
|
||||
% would fill in: A(2,2) and A(2,3).
|
||||
|
||||
% For an equally spaced grid, the Laplacian equation (or Poisson's equation
|
||||
% of heat conduction at steady state if you prefer. Or, for the fickle,
|
||||
% Ficke's law of diffusion would apply.) All of these result in the PDE
|
||||
%
|
||||
% u_xx + u_yy = 0
|
||||
%
|
||||
% where u_xx is the second partial derivative of u with respect to x,
|
||||
% and u_yy is the second partial with respect to y.
|
||||
%
|
||||
% Approximating this PDE using finite differences for the partial
|
||||
% derivatives, implies that at any node in the grid, we could replace
|
||||
% it by the average of its 4 neighbors. Thus the two NaN elements
|
||||
% generate two linear equations:
|
||||
%
|
||||
% A(2,2) = (A(1,2) + A(3,2) + A(2,1) + A(2,3)) / 4
|
||||
% A(2,3) = (A(1,3) + A(3,3) + A(2,2) + A(2,4)) / 4
|
||||
%
|
||||
% Since we know all the parameters but A(2,2) and A(2,3), substitute their
|
||||
% known values.
|
||||
%
|
||||
% A(2,2) = (0 + 3 + 1 + A(2,3)) / 4
|
||||
% A(2,3) = (0 + 5 + A(2,2) + 4) / 4
|
||||
%
|
||||
% Or,
|
||||
%
|
||||
% 4*A(2,2) - A(2,3) = 4
|
||||
% -A(2,2) + 4*A(2,3) = 9
|
||||
%
|
||||
% We can solve for the unkowns now using
|
||||
u = [4 -1;-1 4]\[4;9]
|
||||
|
||||
A(2,2) = u(1);
|
||||
A(2,3) = u(2);
|
||||
|
||||
% and finally plot the surface
|
||||
close
|
||||
surf(A)
|
||||
title 'A simply inpainted surface'
|
||||
|
||||
% Neat huh? For an arbitrary number of NaN elements in an array,
|
||||
% the above scheme is all there is to method 2 of inpaint_nans,
|
||||
% together with a very slick application of sparse linear algebra
|
||||
% in Matlab.
|
||||
|
||||
% Method 0 is very similar, but I've optimized it to build as
|
||||
% small a linear system as possible for those cases where an array
|
||||
% has only a few NaN elements.
|
||||
|
||||
% Method 1 is another subtle variation on this scheme, but it
|
||||
% tries to be slightly smoother at some cost of efficiency, while
|
||||
% still not modifying the known (non-NaN) elements of the array.
|
||||
|
||||
% Method 5 of inpaint_nans is also very similar to method 2, except
|
||||
% that it uses a simple average of all 8 neighbors of an element.
|
||||
% Its not actually an approximation to our PDE.
|
||||
|
||||
% Method 3 is yet another variation on this theme, except the PDE
|
||||
% model used is one more suited to a model of a thin plate than for
|
||||
% heat diffusion. Here the governing PDE is:
|
||||
%
|
||||
% u_xxxx + 2*u_xxyy + u_yyyy = 0
|
||||
%
|
||||
% again discretized into a linear system of equations.
|
||||
|
||||
%%
|
||||
|
||||
% Finally, method 4 of inpaint_nans has a different underlying
|
||||
% model. Pretend that each element in the array was connected to
|
||||
% its immediate neighbors to the left, right, up, and down by
|
||||
% "springs". They are also connected to their neighbors at 45
|
||||
% degree angles by springs with a weaker spring constant. Since
|
||||
% the potential energy stored in a spring is proportional to its
|
||||
% extension, we can formulate this again as a linear system of
|
||||
% equations to be solved. For the example above, we would generate
|
||||
% the set of equations:
|
||||
|
||||
% A(2,2) - A(1,2) = 0
|
||||
% A(2,2) - A(2,1) = 0
|
||||
% A(2,2) - A(3,2) = 0
|
||||
% A(2,2) - A(2,3) = 0
|
||||
% (A(2,2) - A(1,1))/sqrt(2) = 0
|
||||
% (A(2,2) - A(1,3))/sqrt(2) = 0
|
||||
% (A(2,2) - A(3,1))/sqrt(2) = 0
|
||||
% (A(2,2) - A(3,3))/sqrt(2) = 0
|
||||
% A(2,3) - A(1,3) = 0
|
||||
% A(2,3) - A(2,2) = 0
|
||||
% A(2,3) - A(3,3) = 0
|
||||
% A(2,3) - A(2,4) = 0
|
||||
% (A(2,3) - A(1,2))/sqrt(2) = 0
|
||||
% (A(2,3) - A(1,4))/sqrt(2) = 0
|
||||
% (A(2,3) - A(3,2))/sqrt(2) = 0
|
||||
% (A(2,3) - A(3,4))/sqrt(2) = 0
|
||||
|
||||
% Substitute for the known elements to get
|
||||
|
||||
% A(2,2) - 0 = 0
|
||||
% A(2,2) - 1 = 0
|
||||
% A(2,2) - 3 = 0
|
||||
% A(2,2) - A(2,3) = 0
|
||||
% (A(2,2) - 0)/sqrt(2) = 0
|
||||
% (A(2,2) - 0)/sqrt(2) = 0
|
||||
% (A(2,2) - 2)/sqrt(2) = 0
|
||||
% (A(2,2) - 5)/sqrt(2) = 0
|
||||
% A(2,3) - 0 = 0
|
||||
% A(2,3) - A(2,2) = 0
|
||||
% A(2,3) - 5 = 0
|
||||
% A(2,3) - 4 = 0
|
||||
% (A(2,3) - 0)/sqrt(2) = 0
|
||||
% (A(2,3) - 0)/sqrt(2) = 0
|
||||
% (A(2,3) - 3)/sqrt(2) = 0
|
||||
% (A(2,3) - 8)/sqrt(2) = 0
|
||||
|
||||
% This system is also solvable now:
|
||||
r2 = 1/sqrt(2);
|
||||
M=[1 0;1 0;1 0;1 -1;r2 0;r2 0;r2 0;r2 0;0 1;-1 1;0 1;0 1;0 r2;0 r2;0 r2;0 r2];
|
||||
v = M\[0 1 3 0 0 0 2*r2 5*r2 0 0 5 4 0 0 3*r2 8*r2]'
|
||||
|
||||
A(2,2) = v(1);
|
||||
A(2,3) = v(2);
|
||||
|
||||
% and finally plot the surface
|
||||
surf(A)
|
||||
title 'A simply inpainted surface using a spring model'
|
||||
|
||||
%%
|
||||
|
||||
% Why did I provide this approach, based on a spring metaphor?
|
||||
% As you should have observed, methods 2 and 4 are really quite close
|
||||
% in what they do for internal NaN elements. Its on the perimeter that
|
||||
% they differ significantly. The diffusion/Laplacian model will
|
||||
% extrapolate smoothly, and as linearly as possible. The spring model
|
||||
% will tend to extrapolate as a constant function.
|
||||
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,43 @@
|
||||
%% Surface Fit Artifact Removal
|
||||
|
||||
%% Construct the Surface
|
||||
[x,y] = meshgrid(0:.01:1);
|
||||
z0 = exp(x+y);
|
||||
|
||||
close all
|
||||
figure
|
||||
surf(z0)
|
||||
title 'Original surface'
|
||||
|
||||
znan = z0;
|
||||
znan(20:50,40:70) = NaN;
|
||||
znan(30:90,5:10) = NaN;
|
||||
znan(70:75,40:90) = NaN;
|
||||
|
||||
figure
|
||||
surf(znan)
|
||||
title 'Artifacts (large holes) in surface'
|
||||
|
||||
%% In-paint Over NaNs
|
||||
z = inpaint_nans(znan,3);
|
||||
figure
|
||||
surf(z)
|
||||
title 'Inpainted surface'
|
||||
|
||||
figure
|
||||
surf(z-z0)
|
||||
title 'Inpainting error surface (Note z-axis scale)'
|
||||
|
||||
%% Comapre to GRIDDATA
|
||||
k = isnan(znan);
|
||||
zk = griddata(x(~k),y(~k),z(~k),x(k),y(k));
|
||||
zg = znan;
|
||||
zg(k) = zk;
|
||||
|
||||
figure
|
||||
surf(zg)
|
||||
title(['Griddata inpainting (',num2str(sum(isnan(zg(:)))),' NaNs remain)'])
|
||||
|
||||
figure
|
||||
surf(zg-z0)
|
||||
title 'Griddata error surface'
|
||||
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2009, John D'Errico
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
After Width: | Height: | Size: 145 KiB |
@@ -0,0 +1,178 @@
|
||||
%% Repair to an image with 50% random artifacts
|
||||
|
||||
% Garden at Sainte-Adresse (Monet, 1867)
|
||||
garden = imread('monet_adresse.jpg');
|
||||
G = double(garden);
|
||||
G(rand(size(G))<0.50) = NaN;
|
||||
Gnan = G;
|
||||
|
||||
G(:,:,1) = inpaint_nans(G(:,:,1),2);
|
||||
G(:,:,2) = inpaint_nans(G(:,:,2),2);
|
||||
G(:,:,3) = inpaint_nans(G(:,:,3),2);
|
||||
|
||||
figure
|
||||
subplot(1,3,1)
|
||||
image(garden)
|
||||
title 'Garden at Sainte-Adresse (Monet)'
|
||||
|
||||
subplot(1,3,2)
|
||||
image(uint8(Gnan))
|
||||
title 'Corrupted - 50%'
|
||||
|
||||
subplot(1,3,3)
|
||||
image(uint8(G))
|
||||
title 'Inpainted Garden'
|
||||
|
||||
%% Surface fit artifact removal
|
||||
|
||||
[x,y] = meshgrid(0:.01:1);
|
||||
z0 = exp(x+y);
|
||||
|
||||
znan = z0;
|
||||
znan(20:50,40:70) = NaN;
|
||||
znan(30:90,5:10) = NaN;
|
||||
znan(70:75,40:90) = NaN;
|
||||
|
||||
tic,z = inpaint_nans(znan,3);toc
|
||||
|
||||
tic
|
||||
k = isnan(znan);
|
||||
zk = griddata(x(~k),y(~k),z(~k),x(k),y(k));
|
||||
zg = znan;
|
||||
zg(k) = zk;
|
||||
toc
|
||||
|
||||
figure
|
||||
surf(z0)
|
||||
title 'Original surface'
|
||||
|
||||
figure
|
||||
surf(znan)
|
||||
title 'Artifacts (large holes) in surface'
|
||||
|
||||
figure
|
||||
surf(zg)
|
||||
title(['Griddata inpainting (',num2str(sum(isnan(zg(:)))),' NaNs remain)'])
|
||||
|
||||
figure
|
||||
surf(z)
|
||||
title 'Inpainted surface'
|
||||
|
||||
figure
|
||||
surf(zg-z0)
|
||||
title 'Griddata error surface'
|
||||
|
||||
figure
|
||||
surf(z-z0)
|
||||
title 'Inpainting error surface (Note z-axis scale)'
|
||||
|
||||
%% Comparison of methods
|
||||
|
||||
[x,y] = meshgrid(-1:.02:1);
|
||||
r = sqrt(x.^2 + y.^2);
|
||||
z = exp(-(x.^2+ y.^2));
|
||||
|
||||
z(r>=0.9) = NaN;
|
||||
|
||||
z((r<=.5) & (x<0)) = NaN;
|
||||
|
||||
figure
|
||||
pcolor(z);
|
||||
title 'Surface provided to inpaint_nans'
|
||||
|
||||
% Method 0
|
||||
tic,z0 = inpaint_nans(z,0);toc
|
||||
|
||||
% Method 1
|
||||
tic,z1 = inpaint_nans(z,1);toc
|
||||
|
||||
% Method 2
|
||||
tic,z2 = inpaint_nans(z,2);toc
|
||||
|
||||
% Method 3
|
||||
tic,z3 = inpaint_nans(z,3);toc
|
||||
|
||||
% Method 4
|
||||
tic,z4 = inpaint_nans(z,4);toc
|
||||
|
||||
% Method 5
|
||||
tic,z5 = inpaint_nans(z,5);toc
|
||||
|
||||
figure
|
||||
surf(z0)
|
||||
colormap copper
|
||||
hold on
|
||||
h = surf(z);
|
||||
set(h,'facecolor','r')
|
||||
hold off
|
||||
title 'Method 0 (Red was provided)'
|
||||
|
||||
figure
|
||||
surf(z1)
|
||||
hold on
|
||||
h = surf(z);
|
||||
set(h,'facecolor','r')
|
||||
hold off
|
||||
title 'Method 1 (Red was provided)'
|
||||
|
||||
figure
|
||||
surf(z2)
|
||||
hold on
|
||||
h = surf(z);
|
||||
set(h,'facecolor','r')
|
||||
hold off
|
||||
title 'Method 2 (Red was provided) - least accurate, but fastest'
|
||||
|
||||
figure
|
||||
surf(z3)
|
||||
hold on
|
||||
h = surf(z);
|
||||
set(h,'facecolor','r')
|
||||
hold off
|
||||
title 'Method 3 (Red was provided) - Slow, but accurate'
|
||||
|
||||
figure
|
||||
surf(z4)
|
||||
hold on
|
||||
h = surf(z);
|
||||
set(h,'facecolor','r')
|
||||
hold off
|
||||
title 'Method 4 (Red was provided) - designed for constant extrapolation!'
|
||||
|
||||
figure
|
||||
h = surf(z5);
|
||||
set(h,'facecolor','y')
|
||||
hold on
|
||||
h = surf(z);
|
||||
set(h,'facecolor','r')
|
||||
hold off
|
||||
title 'Method 5 (Red was provided)'
|
||||
|
||||
|
||||
%% 1-d "inpainting" using interp1
|
||||
|
||||
x = linspace(0,3*pi,100);
|
||||
y0 = sin(x);
|
||||
y = y0;
|
||||
% Drop out 2/3 of the data
|
||||
y(1:3:end) = NaN;
|
||||
y(2:3:end) = NaN;
|
||||
|
||||
% inpaint_nans
|
||||
y_inpaint = inpaint_nans(y,1);
|
||||
|
||||
% interpolate using interp1
|
||||
k = isnan(y);
|
||||
y_interp1c = y;
|
||||
y_interp1s = y;
|
||||
y_interp1c(k) = interp1(x(~k),y(~k),x(k),'cubic');
|
||||
y_interp1s(k) = interp1(x(~k),y(~k),x(k),'spline');
|
||||
|
||||
figure
|
||||
plot(x,y,'ro',x,y_inpaint,'b+')
|
||||
legend('sin(x), missing 2/3 points','inpaint-nans','Location','North')
|
||||
|
||||
figure
|
||||
plot(x,y0-y_inpaint,'r-',x,y0-y_interp1c,'b--',x,y0-y_interp1s,'g--')
|
||||
title 'Inpainting residuals'
|
||||
legend('Inpaint-nans','Pchip','Spline','Location','North')
|
||||
@@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Kelly Kearney
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
377
Functions/helper_functions_community/boundedlines/README.html
Normal file
@@ -0,0 +1,377 @@
|
||||
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<!--
|
||||
This HTML was auto-generated from MATLAB code.
|
||||
To make changes, update the MATLAB code and republish this document.
|
||||
--><title>boundedline.m: line with shaded error/confidence bounds</title><meta name="generator" content="MATLAB 9.1"><link rel="schema.DC" href="http://purl.org/dc/elements/1.1/"><meta name="DC.date" content="2017-08-08"><meta name="DC.source" content="./readmeExtras/README.m"><style type="text/css">
|
||||
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}:focus{outine:0}ins{text-decoration:none}del{text-decoration:line-through}table{border-collapse:collapse;border-spacing:0}
|
||||
|
||||
html { min-height:100%; margin-bottom:1px; }
|
||||
html body { height:100%; margin:0px; font-family:Arial, Helvetica, sans-serif; font-size:10px; color:#000; line-height:140%; background:#fff none; overflow-y:scroll; }
|
||||
html body td { vertical-align:top; text-align:left; }
|
||||
|
||||
h1 { padding:0px; margin:0px 0px 25px; font-family:Arial, Helvetica, sans-serif; font-size:1.5em; color:#d55000; line-height:100%; font-weight:normal; }
|
||||
h2 { padding:0px; margin:0px 0px 8px; font-family:Arial, Helvetica, sans-serif; font-size:1.2em; color:#000; font-weight:bold; line-height:140%; border-bottom:1px solid #d6d4d4; display:block; }
|
||||
h3 { padding:0px; margin:0px 0px 5px; font-family:Arial, Helvetica, sans-serif; font-size:1.1em; color:#000; font-weight:bold; line-height:140%; }
|
||||
|
||||
a { color:#005fce; text-decoration:none; }
|
||||
a:hover { color:#005fce; text-decoration:underline; }
|
||||
a:visited { color:#004aa0; text-decoration:none; }
|
||||
|
||||
p { padding:0px; margin:0px 0px 20px; }
|
||||
img { padding:0px; margin:0px 0px 20px; border:none; }
|
||||
p img, pre img, tt img, li img, h1 img, h2 img { margin-bottom:0px; }
|
||||
|
||||
ul { padding:0px; margin:0px 0px 20px 23px; list-style:square; }
|
||||
ul li { padding:0px; margin:0px 0px 7px 0px; }
|
||||
ul li ul { padding:5px 0px 0px; margin:0px 0px 7px 23px; }
|
||||
ul li ol li { list-style:decimal; }
|
||||
ol { padding:0px; margin:0px 0px 20px 0px; list-style:decimal; }
|
||||
ol li { padding:0px; margin:0px 0px 7px 23px; list-style-type:decimal; }
|
||||
ol li ol { padding:5px 0px 0px; margin:0px 0px 7px 0px; }
|
||||
ol li ol li { list-style-type:lower-alpha; }
|
||||
ol li ul { padding-top:7px; }
|
||||
ol li ul li { list-style:square; }
|
||||
|
||||
.content { font-size:1.2em; line-height:140%; padding: 20px; }
|
||||
|
||||
pre, code { font-size:12px; }
|
||||
tt { font-size: 1.2em; }
|
||||
pre { margin:0px 0px 20px; }
|
||||
pre.codeinput { padding:10px; border:1px solid #d3d3d3; background:#f7f7f7; }
|
||||
pre.codeoutput { padding:10px 11px; margin:0px 0px 20px; color:#4c4c4c; }
|
||||
pre.error { color:red; }
|
||||
|
||||
@media print { pre.codeinput, pre.codeoutput { word-wrap:break-word; width:100%; } }
|
||||
|
||||
span.keyword { color:#0000FF }
|
||||
span.comment { color:#228B22 }
|
||||
span.string { color:#A020F0 }
|
||||
span.untermstring { color:#B20000 }
|
||||
span.syscmd { color:#B28C00 }
|
||||
|
||||
.footer { width:auto; padding:10px 0px; margin:25px 0px 0px; border-top:1px dotted #878787; font-size:0.8em; line-height:140%; font-style:italic; color:#878787; text-align:left; float:none; }
|
||||
.footer p { margin:0px; }
|
||||
.footer a { color:#878787; }
|
||||
.footer a:hover { color:#878787; text-decoration:underline; }
|
||||
.footer a:visited { color:#878787; }
|
||||
|
||||
table th { padding:7px 5px; text-align:left; vertical-align:middle; border: 1px solid #d6d4d4; font-weight:bold; }
|
||||
table td { padding:7px 5px; text-align:left; vertical-align:top; border:1px solid #d6d4d4; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</style></head><body><div class="content"><h1><tt>boundedline.m</tt>: line with shaded error/confidence bounds</h1><!--introduction--><p>Author: Kelly Kearney</p><p>This repository includes the code for the <tt>boundedline.m</tt> Matlab function and the accompanying <tt>outlinebounds.m</tt> function, along with all dependent functions required to run them.</p><p>The <tt>boundedline</tt> function allows a user to easily plot and line with a shaded patch around it. Ths sort of plot is often used to indicate uncertainty intervals or error bounds around a line.</p><!--/introduction--><h2>Contents</h2><div><ul><li><a href="#1">Getting started</a></li><li><a href="#2">Syntax</a></li><li><a href="#3">Example 1: Plotting lines using various syntax options</a></li><li><a href="#7">Example 2: Filling gaps</a></li><li><a href="#12">Contributions</a></li></ul></div><h2 id="1">Getting started</h2><p><b>Prerequisites</b></p><p>This function requires Matlab R14 or later.</p><p><b>Downloading and installation</b></p><p>This code can be downloaded from <a href="https://github.com/kakearney/boundedline-pkg/">Github</a> or the <a href="http://www.mathworks.com/matlabcentral/fileexchange/27485-boundedline-m">MatlabCentral File Exchange</a>. The File Exchange entry is updated daily from the GitHub repository.</p><p><b>Matlab Search Path</b></p><p>The following folders need to be added to your Matlab Search path (via <tt>addpath</tt>, <tt>pathtool</tt>, etc.):</p><pre class="language-matlab">boundedline-pkg/Inpaint_nans
|
||||
boundedline-pkg/boundedline
|
||||
boundedline-pkg/catuneven
|
||||
boundedline-pkg/singlepatch
|
||||
</pre><h2 id="2">Syntax</h2><p><tt>boundedline(x, y, b)</tt> plots a line with coordinates given by <tt>x</tt> and <tt>y</tt>, surrounded by a patch extending a certain distance <tt>b</tt> above/below that line. The dimensions of the <tt>x</tt>, <tt>y</tt>, and <tt>b</tt> arrays can vary to allow for multiple lines to be plotted at once, and for patch bounds to be either constant or varying along the length of the line. See function header help for full details of these variations.</p><p><tt>boundedline(..., 'alpha')</tt> renders the bounded area patch using a partially-transparent patch the same color as the corresponding line(s). If not included, the bounded area will use a fully-opaque patch in a lighter shade of the corresponding line color.</p><p><tt>boundedline(..., 'transparency', transp)</tt> indicates the tranparency or intensity of the bounds patch, using a scalar between 0 and 1. Default is 0.2.</p><p><tt>boundedline(..., 'orientation', orient)</tt> indicates the orientation of the bounds. Orientation can be either <tt>'vert'</tt> for vertical (y-direction) bounds, or <tt>'horiz'</tt> for horizontal (x-direction) bounds. Default is <tt>'vert'</tt>.</p><p><tt>boundedline(..., 'nan', nanflag)</tt> indicates how the bounds patch should handle NaNs in the line coordinates or bounds values. Options are <tt>'fill'</tt>, to smooth over the gap using neighboring values, <tt>'gap'</tt> to leave a blank space in the patch at those points, or <tt>'remove'</tt> to drop the NaN-points entirely, leading to linear interpolation of the gap in the patch. See examples below for more details on these options.</p><p><tt>boundedline(..., 'cmap', cmap)</tt> colors the lines (in order of plotting) acording to the colors in this n x 3 colormap array, overriding any linespec or default colors.</p><p><tt>boundedline(..., ax)</tt> plots the bounded line to the axis indicated by handle <tt>ax</tt>. If not included, the current axis is used.</p><p><tt>[hl, hp] = boundedline(...)</tt> returns the handles the resulting line and patch object(s).</p><p><tt>hout = outlinebounds(hl, hp)</tt> adds an outline to the bounds patch generated by <tt>boundedline</tt>, returning the handle of the resulting line object in <tt>hout</tt>.</p><p>Full details of all input and output variables for both functions can be accessed via the <tt>help</tt> function.</p><h2 id="3">Example 1: Plotting lines using various syntax options</h2><p>This example builds the 4-panel example image used on the MatlabCentral File Exchange, which shows several different methods for supplying line coordinates, bounds coordinates, and shading options.</p><p>The first axis plots two lines using the LineSpec option for input, which allows yoy to set line color, line color, and marker type for each line. The bounds on the first line vary over x, while the bounds on the second line are constant for all x. An outline is added to the bounds so the overlapping region can be seen more clearly.</p><pre class="codeinput">x = linspace(0, 2*pi, 50);
|
||||
y1 = sin(x);
|
||||
y2 = cos(x);
|
||||
e1 = rand(size(y1))*.5+.5;
|
||||
e2 = [.25 .5];
|
||||
|
||||
ax(1) = subplot(2,2,1);
|
||||
[l,p] = boundedline(x, y1, e1, <span class="string">'-b*'</span>, x, y2, e2, <span class="string">'--ro'</span>);
|
||||
outlinebounds(l,p);
|
||||
title(<span class="string">'Opaque bounds, with outline'</span>);
|
||||
axis <span class="string">tight</span>;
|
||||
</pre><img vspace="5" hspace="5" src="./readmeExtras/README_01.png" alt=""> <p>For our second axis, we use the same 2 lines, and this time assign x-varying bounds to both lines. Rather than using the LineSpec syntax, this example uses the default color order to assign the colors of the lines and patches. I also turn on the <tt>'alpha'</tt> option, which renders the patch wit partial transparency.</p><pre class="codeinput">ax(2) = subplot(2,2,2);
|
||||
boundedline(x, [y1;y2], rand(length(y1),2,2)*.5+.5, <span class="string">'alpha'</span>);
|
||||
title(<span class="string">'Transparent bounds'</span>);
|
||||
axis <span class="string">tight</span>;
|
||||
</pre><img vspace="5" hspace="5" src="./readmeExtras/README_02.png" alt=""> <p>The bounds can also be assigned to a horizontal orientation, for a case where the x-axis represents the dependent variable. In this case, the scalar error bound value applies to both lines and both sides of the lines.</p><pre class="codeinput">ax(3) = subplot(2,2,3);
|
||||
boundedline([y1;y2], x, e1(1), <span class="string">'orientation'</span>, <span class="string">'horiz'</span>)
|
||||
title(<span class="string">'Horizontal bounds'</span>);
|
||||
axis <span class="string">tight</span>;
|
||||
</pre><img vspace="5" hspace="5" src="./readmeExtras/README_03.png" alt=""> <p>Rather than use a LineSpec or the default color order, a colormap array can be used to assign colors. In this case, increasingly-narrower bounds are added on top of the same line.</p><pre class="codeinput">ax(4) = subplot(2,2,4);
|
||||
boundedline(x, repmat(y1, 4,1), permute(0.5:-0.1:0.2, [3 1 2]), <span class="keyword">...</span>
|
||||
<span class="string">'cmap'</span>, cool(4), <span class="keyword">...</span>
|
||||
<span class="string">'transparency'</span>, 0.5);
|
||||
title(<span class="string">'Multiple bounds using colormap'</span>);
|
||||
|
||||
set(ax([1 2 4]), <span class="string">'xlim'</span>, [0 2*pi]);
|
||||
set(ax(3), <span class="string">'ylim'</span>, [0 2*pi]);
|
||||
axis <span class="string">tight</span>;
|
||||
</pre><img vspace="5" hspace="5" src="./readmeExtras/README_04.png" alt=""> <h2 id="7">Example 2: Filling gaps</h2><p>If you plot a line with one or more NaNs in either the <tt>x</tt> or <tt>y</tt> vector, the NaN location is rendered as a missing marker with a gap in the line. However, the <tt>patch</tt> command does not handle NaNs gracefully; it simply fails to show the patch at all if any of the coordinates include NaNs.</p><p>Because of this, the expected behavior of the patch part of boundedline when confronted with a NaN in either the bounds array (<tt>b</tt>) or the x/y-coordinates of the line (which are used to calculate the patch coordinates) is ambiguous. I offer a few options.</p><p>Before I demonstrate the options, I'll create a dataset that has a few different types of gaps:</p><pre class="codeinput">x = linspace(0, 2*pi, 50);
|
||||
y = sin(x);
|
||||
b = [ones(size(y))*0.2; rand(size(y))*.5+.5]';
|
||||
|
||||
y(10) = NaN; <span class="comment">% NaN in the line but not bounds</span>
|
||||
b(20,1) = NaN; <span class="comment">% NaN in lower bound but not line</span>
|
||||
b(30,2) = NaN; <span class="comment">% NaN in upper bound but not line</span>
|
||||
b(40,:) = NaN; <span class="comment">% NaN in both sides of bound but not line</span>
|
||||
</pre><p>Here's what that looks like in an errorbar plot.</p><pre class="codeinput">figure;
|
||||
he = errorbar(x,y,b(:,1), b(:,2), <span class="string">'-bo'</span>);
|
||||
|
||||
|
||||
line([x([10 20 30 40]); x([10 20 30 40])], [ones(1,4)*-2;ones(1,4)*2], <span class="keyword">...</span>
|
||||
<span class="string">'color'</span>, ones(1,3)*0.5, <span class="string">'linestyle'</span>, <span class="string">':'</span>);
|
||||
text(x(10), sin(x(10))-0.2, {<span class="string">'\uparrow'</span>,<span class="string">'Line'</span>,<span class="string">'gap'</span>}, <span class="string">'vert'</span>, <span class="string">'top'</span>, <span class="string">'horiz'</span>, <span class="string">'center'</span>);
|
||||
text(x(20), sin(x(20))-0.2, {<span class="string">'\uparrow'</span>,<span class="string">'Lower'</span>,<span class="string">'bound'</span>,<span class="string">'gap'</span>}, <span class="string">'vert'</span>, <span class="string">'top'</span>, <span class="string">'horiz'</span>, <span class="string">'center'</span>);
|
||||
text(x(30), sin(x(30))-0.2, {<span class="string">'\uparrow'</span>,<span class="string">'Upper'</span>,<span class="string">'bound'</span>,<span class="string">'gap'</span>}, <span class="string">'vert'</span>, <span class="string">'top'</span>, <span class="string">'horiz'</span>, <span class="string">'center'</span>);
|
||||
text(x(40), sin(x(40))-0.2, {<span class="string">'\uparrow'</span>,<span class="string">'Two-sided'</span>,<span class="string">'bound'</span>,<span class="string">'gap'</span>}, <span class="string">'vert'</span>, <span class="string">'top'</span>, <span class="string">'horiz'</span>, <span class="string">'center'</span>);
|
||||
|
||||
axis <span class="string">tight</span> <span class="string">equal</span>;
|
||||
</pre><img vspace="5" hspace="5" src="./readmeExtras/README_05.png" alt=""> <p>The default method for dealing with NaNs in boundedline is to leave the gap in the line, but smooth over the gap in the bounds based on the neighboring points. This option can be nice if you only have one or two missing points, and you're not interested in emphasizing those gaps in your plot:</p><pre class="codeinput">delete(he);
|
||||
[hl,hp] = boundedline(x,y,b,<span class="string">'-bo'</span>, <span class="string">'nan'</span>, <span class="string">'fill'</span>);
|
||||
ho = outlinebounds(hl,hp);
|
||||
set(ho, <span class="string">'linestyle'</span>, <span class="string">':'</span>, <span class="string">'color'</span>, <span class="string">'r'</span>, <span class="string">'marker'</span>, <span class="string">'.'</span>);
|
||||
</pre><img vspace="5" hspace="5" src="./readmeExtras/README_06.png" alt=""> <p>I've added bounds outlines in a contrasting color so you can see how I'm handling individual points.</p><p>The second option leaves a full gap in the patch for any NaN. I considered allowing one-sided gaps, but couldn't think of a good way to distinguish a gap from a zero-valued bound. I'm open to suggestions if you have any (email me).</p><pre class="codeinput">delete([hl hp ho]);
|
||||
[hl,hp] = boundedline(x,y,b,<span class="string">'-bo'</span>, <span class="string">'nan'</span>, <span class="string">'gap'</span>);
|
||||
ho = outlinebounds(hl,hp);
|
||||
set(ho, <span class="string">'linestyle'</span>, <span class="string">':'</span>, <span class="string">'color'</span>, <span class="string">'r'</span>, <span class="string">'marker'</span>, <span class="string">'.'</span>);
|
||||
</pre><img vspace="5" hspace="5" src="./readmeExtras/README_07.png" alt=""> <p>The final option removes points from the patch that are NaNs. The visual result is very similar to the fill option, but the missing points are apparent if you plot the bounds outlines.</p><pre class="codeinput">delete([hl hp ho]);
|
||||
[hl,hp] = boundedline(x,y,b,<span class="string">'-bo'</span>, <span class="string">'nan'</span>, <span class="string">'remove'</span>);
|
||||
ho = outlinebounds(hl,hp);
|
||||
set(ho, <span class="string">'linestyle'</span>, <span class="string">':'</span>, <span class="string">'color'</span>, <span class="string">'r'</span>, <span class="string">'marker'</span>, <span class="string">'.'</span>);
|
||||
</pre><img vspace="5" hspace="5" src="./readmeExtras/README_08.png" alt=""> <h2 id="12">Contributions</h2><p>Community contributions to this package are welcome!</p><p>To report bugs, please submit <a href="https://github.com/kakearney/boundedline-pkg/issues">an issue</a> on GitHub and include:</p><div><ul><li>your operating system</li><li>your version of Matlab and all relevant toolboxes (type <tt>ver</tt> at the Matlab command line to get this info)</li><li>code/data to reproduce the error or buggy behavior, and the full text of any error messages received</li></ul></div><p>Please also feel free to submit enhancement requests, or to send pull requests (via GitHub) for bug fixes or new features.</p><p>I do monitor the MatlabCentral FileExchange entry for any issues raised in the comments, but would prefer to track issues on GitHub.</p><p class="footer"><br><a href="http://www.mathworks.com/products/matlab/">Published with MATLAB® R2016b</a><br></p></div><!--
|
||||
##### SOURCE BEGIN #####
|
||||
%% |boundedline.m|: line with shaded error/confidence bounds
|
||||
% Author: Kelly Kearney
|
||||
%
|
||||
% This repository includes the code for the |boundedline.m| Matlab function
|
||||
% and the accompanying |outlinebounds.m| function, along with all dependent
|
||||
% functions required to run them.
|
||||
%
|
||||
% The |boundedline| function allows a user to easily plot and line with a
|
||||
% shaded patch around it. Ths sort of plot is often used to indicate
|
||||
% uncertainty intervals or error bounds around a line.
|
||||
%
|
||||
%% Getting started
|
||||
%
|
||||
% *Prerequisites*
|
||||
%
|
||||
% This function requires Matlab R14 or later.
|
||||
%
|
||||
% *Downloading and installation*
|
||||
%
|
||||
% This code can be downloaded from <https://github.com/kakearney/boundedline-pkg/ Github>
|
||||
% or the
|
||||
% <http://www.mathworks.com/matlabcentral/fileexchange/27485-boundedline-m
|
||||
% MatlabCentral File Exchange>. The File Exchange entry is updated daily
|
||||
% from the GitHub repository.
|
||||
%
|
||||
% *Matlab Search Path*
|
||||
%
|
||||
% The following folders need to be added to your Matlab Search path (via
|
||||
% |addpath|, |pathtool|, etc.):
|
||||
%
|
||||
% boundedline-pkg/Inpaint_nans
|
||||
% boundedline-pkg/boundedline
|
||||
% boundedline-pkg/catuneven
|
||||
% boundedline-pkg/singlepatch
|
||||
|
||||
%% Syntax
|
||||
%
|
||||
% |boundedline(x, y, b)| plots a line with coordinates given by
|
||||
% |x| and |y|, surrounded by a patch extending a certain distance |b|
|
||||
% above/below that line. The dimensions of the |x|, |y|, and |b| arrays
|
||||
% can vary to allow for multiple lines to be plotted at once, and for
|
||||
% patch bounds to be either constant or varying along the length of the
|
||||
% line. See function header help for full details of these variations.
|
||||
%
|
||||
% |boundedline(..., 'alpha')| renders the bounded area patch using a
|
||||
% partially-transparent patch the same color as the corresponding line(s).
|
||||
% If not included, the bounded area will use a fully-opaque patch in a
|
||||
% lighter shade of the corresponding line color.
|
||||
%
|
||||
% |boundedline(..., 'transparency', transp)| indicates the
|
||||
% tranparency or intensity of the bounds patch, using a scalar between 0
|
||||
% and 1. Default is 0.2.
|
||||
%
|
||||
% |boundedline(..., 'orientation', orient)| indicates the orientation of
|
||||
% the bounds. Orientation can be either |'vert'| for vertical (y-direction)
|
||||
% bounds, or |'horiz'| for horizontal (x-direction) bounds. Default is
|
||||
% |'vert'|.
|
||||
%
|
||||
% |boundedline(..., 'nan', nanflag)| indicates how the bounds patch should
|
||||
% handle NaNs in the line coordinates or bounds values. Options are
|
||||
% |'fill'|, to smooth over the gap using neighboring values, |'gap'| to
|
||||
% leave a blank space in the patch at those points, or |'remove'| to drop
|
||||
% the NaN-points entirely, leading to linear interpolation of the gap in
|
||||
% the patch. See examples below for more details on these options.
|
||||
%
|
||||
% |boundedline(..., 'cmap', cmap)| colors the lines (in order of plotting)
|
||||
% acording to the colors in this n x 3 colormap array, overriding any
|
||||
% linespec or default colors.
|
||||
%
|
||||
% |boundedline(..., ax)| plots the bounded line to the axis indicated by
|
||||
% handle |ax|. If not included, the current axis is used.
|
||||
%
|
||||
% |[hl, hp] = boundedline(...)| returns the handles the resulting line
|
||||
% and patch object(s).
|
||||
%
|
||||
% |hout = outlinebounds(hl, hp)| adds an outline to the bounds patch
|
||||
% generated by |boundedline|, returning the handle of the resulting line
|
||||
% object in |hout|.
|
||||
%
|
||||
% Full details of all input and output variables for both functions can be
|
||||
% accessed via the |help| function.
|
||||
|
||||
%% Example 1: Plotting lines using various syntax options
|
||||
%
|
||||
% This example builds the 4-panel example image used on the MatlabCentral
|
||||
% File Exchange, which shows several different methods for supplying line
|
||||
% coordinates, bounds coordinates, and shading options.
|
||||
%
|
||||
% The first axis plots two lines using the LineSpec option for input, which
|
||||
% allows yoy to set line color, line color, and marker type for each line.
|
||||
% The bounds on the first line vary over x, while the bounds on the second
|
||||
% line are constant for all x. An outline is added to the bounds so the
|
||||
% overlapping region can be seen more clearly.
|
||||
|
||||
x = linspace(0, 2*pi, 50);
|
||||
y1 = sin(x);
|
||||
y2 = cos(x);
|
||||
e1 = rand(size(y1))*.5+.5;
|
||||
e2 = [.25 .5];
|
||||
|
||||
ax(1) = subplot(2,2,1);
|
||||
[l,p] = boundedline(x, y1, e1, '-b*', x, y2, e2, 'REPLACE_WITH_DASH_DASHro');
|
||||
outlinebounds(l,p);
|
||||
title('Opaque bounds, with outline');
|
||||
axis tight;
|
||||
|
||||
%%
|
||||
% For our second axis, we use the same 2 lines, and this time assign
|
||||
% x-varying bounds to both lines. Rather than using the LineSpec syntax,
|
||||
% this example uses the default color order to assign the colors of the
|
||||
% lines and patches. I also turn on the |'alpha'| option, which renders
|
||||
% the patch wit partial transparency.
|
||||
|
||||
ax(2) = subplot(2,2,2);
|
||||
boundedline(x, [y1;y2], rand(length(y1),2,2)*.5+.5, 'alpha');
|
||||
title('Transparent bounds');
|
||||
axis tight;
|
||||
|
||||
%%
|
||||
% The bounds can also be assigned to a horizontal orientation, for a case
|
||||
% where the x-axis represents the dependent variable. In this case, the
|
||||
% scalar error bound value applies to both lines and both sides of the
|
||||
% lines.
|
||||
|
||||
ax(3) = subplot(2,2,3);
|
||||
boundedline([y1;y2], x, e1(1), 'orientation', 'horiz')
|
||||
title('Horizontal bounds');
|
||||
axis tight;
|
||||
|
||||
%%
|
||||
% Rather than use a LineSpec or the default color order, a colormap array
|
||||
% can be used to assign colors. In this case, increasingly-narrower bounds
|
||||
% are added on top of the same line.
|
||||
|
||||
ax(4) = subplot(2,2,4);
|
||||
boundedline(x, repmat(y1, 4,1), permute(0.5:-0.1:0.2, [3 1 2]), ...
|
||||
'cmap', cool(4), ...
|
||||
'transparency', 0.5);
|
||||
title('Multiple bounds using colormap');
|
||||
|
||||
set(ax([1 2 4]), 'xlim', [0 2*pi]);
|
||||
set(ax(3), 'ylim', [0 2*pi]);
|
||||
axis tight;
|
||||
|
||||
%% Example 2: Filling gaps
|
||||
%
|
||||
% If you plot a line with one or more NaNs in either the |x| or |y| vector,
|
||||
% the NaN location is rendered as a missing marker with a gap in the line.
|
||||
% However, the |patch| command does not handle NaNs gracefully; it simply
|
||||
% fails to show the patch at all if any of the coordinates include NaNs.
|
||||
%
|
||||
% Because of this, the expected behavior of the patch part of boundedline
|
||||
% when confronted with a NaN in either the bounds array (|b|) or the
|
||||
% x/y-coordinates of the line (which are used to calculate the patch
|
||||
% coordinates) is ambiguous. I offer a few options.
|
||||
%
|
||||
% Before I demonstrate the options, I'll create a dataset that has a few
|
||||
% different types of gaps:
|
||||
|
||||
x = linspace(0, 2*pi, 50);
|
||||
y = sin(x);
|
||||
b = [ones(size(y))*0.2; rand(size(y))*.5+.5]';
|
||||
|
||||
y(10) = NaN; % NaN in the line but not bounds
|
||||
b(20,1) = NaN; % NaN in lower bound but not line
|
||||
b(30,2) = NaN; % NaN in upper bound but not line
|
||||
b(40,:) = NaN; % NaN in both sides of bound but not line
|
||||
|
||||
%%
|
||||
% Here's what that looks like in an errorbar plot.
|
||||
|
||||
figure;
|
||||
he = errorbar(x,y,b(:,1), b(:,2), '-bo');
|
||||
|
||||
|
||||
line([x([10 20 30 40]); x([10 20 30 40])], [ones(1,4)*-2;ones(1,4)*2], ...
|
||||
'color', ones(1,3)*0.5, 'linestyle', ':');
|
||||
text(x(10), sin(x(10))-0.2, {'\uparrow','Line','gap'}, 'vert', 'top', 'horiz', 'center');
|
||||
text(x(20), sin(x(20))-0.2, {'\uparrow','Lower','bound','gap'}, 'vert', 'top', 'horiz', 'center');
|
||||
text(x(30), sin(x(30))-0.2, {'\uparrow','Upper','bound','gap'}, 'vert', 'top', 'horiz', 'center');
|
||||
text(x(40), sin(x(40))-0.2, {'\uparrow','Two-sided','bound','gap'}, 'vert', 'top', 'horiz', 'center');
|
||||
|
||||
axis tight equal;
|
||||
|
||||
%%
|
||||
% The default method for dealing with NaNs in boundedline is to leave the
|
||||
% gap in the line, but smooth over the gap in the bounds based on the
|
||||
% neighboring points. This option can be nice if you only have one or two
|
||||
% missing points, and you're not interested in emphasizing those gaps in
|
||||
% your plot:
|
||||
|
||||
delete(he);
|
||||
[hl,hp] = boundedline(x,y,b,'-bo', 'nan', 'fill');
|
||||
ho = outlinebounds(hl,hp);
|
||||
set(ho, 'linestyle', ':', 'color', 'r', 'marker', '.');
|
||||
|
||||
%%
|
||||
% I've added bounds outlines in a contrasting color so you can see how I'm
|
||||
% handling individual points.
|
||||
%
|
||||
% The second option leaves a full gap in the patch for any NaN. I
|
||||
% considered allowing one-sided gaps, but couldn't think of a good way to
|
||||
% distinguish a gap from a zero-valued bound. I'm open to suggestions if
|
||||
% you have any (email me).
|
||||
|
||||
delete([hl hp ho]);
|
||||
[hl,hp] = boundedline(x,y,b,'-bo', 'nan', 'gap');
|
||||
ho = outlinebounds(hl,hp);
|
||||
set(ho, 'linestyle', ':', 'color', 'r', 'marker', '.');
|
||||
|
||||
%%
|
||||
% The final option removes points from the patch that are NaNs. The visual
|
||||
% result is very similar to the fill option, but the missing points are
|
||||
% apparent if you plot the bounds outlines.
|
||||
|
||||
delete([hl hp ho]);
|
||||
[hl,hp] = boundedline(x,y,b,'-bo', 'nan', 'remove');
|
||||
ho = outlinebounds(hl,hp);
|
||||
set(ho, 'linestyle', ':', 'color', 'r', 'marker', '.');
|
||||
|
||||
|
||||
%% Contributions
|
||||
%
|
||||
% Community contributions to this package are welcome!
|
||||
%
|
||||
% To report bugs, please submit
|
||||
% <https://github.com/kakearney/boundedline-pkg/issues an issue> on GitHub and
|
||||
% include:
|
||||
%
|
||||
% * your operating system
|
||||
% * your version of Matlab and all relevant toolboxes (type |ver| at the Matlab command line to get this info)
|
||||
% * code/data to reproduce the error or buggy behavior, and the full text of any error messages received
|
||||
%
|
||||
% Please also feel free to submit enhancement requests, or to send pull
|
||||
% requests (via GitHub) for bug fixes or new features.
|
||||
%
|
||||
% I do monitor the MatlabCentral FileExchange entry for any issues raised
|
||||
% in the comments, but would prefer to track issues on GitHub.
|
||||
%
|
||||
|
||||
|
||||
##### SOURCE END #####
|
||||
--></body></html>
|
||||
240
Functions/helper_functions_community/boundedlines/README.m
Normal file
@@ -0,0 +1,240 @@
|
||||
%% |boundedline.m|: line with shaded error/confidence bounds
|
||||
% Author: Kelly Kearney
|
||||
%
|
||||
% This repository includes the code for the |boundedline.m| Matlab function
|
||||
% and the accompanying |outlinebounds.m| function, along with all dependent
|
||||
% functions required to run them.
|
||||
%
|
||||
% The |boundedline| function allows a user to easily plot and line with a
|
||||
% shaded patch around it. Ths sort of plot is often used to indicate
|
||||
% uncertainty intervals or error bounds around a line.
|
||||
%
|
||||
%% Getting started
|
||||
%
|
||||
% *Prerequisites*
|
||||
%
|
||||
% This function requires Matlab R14 or later.
|
||||
%
|
||||
% *Downloading and installation*
|
||||
%
|
||||
% This code can be downloaded from <https://github.com/kakearney/boundedline-pkg/ Github>
|
||||
% or the
|
||||
% <http://www.mathworks.com/matlabcentral/fileexchange/27485-boundedline-m
|
||||
% MatlabCentral File Exchange>. The File Exchange entry is updated daily
|
||||
% from the GitHub repository.
|
||||
%
|
||||
% *Matlab Search Path*
|
||||
%
|
||||
% The following folders need to be added to your Matlab Search path (via
|
||||
% |addpath|, |pathtool|, etc.):
|
||||
%
|
||||
% boundedline-pkg/Inpaint_nans
|
||||
% boundedline-pkg/boundedline
|
||||
% boundedline-pkg/catuneven
|
||||
% boundedline-pkg/singlepatch
|
||||
|
||||
%% Syntax
|
||||
%
|
||||
% |boundedline(x, y, b)| plots a line with coordinates given by
|
||||
% |x| and |y|, surrounded by a patch extending a certain distance |b|
|
||||
% above/below that line. The dimensions of the |x|, |y|, and |b| arrays
|
||||
% can vary to allow for multiple lines to be plotted at once, and for
|
||||
% patch bounds to be either constant or varying along the length of the
|
||||
% line. See function header help for full details of these variations.
|
||||
%
|
||||
% |boundedline(..., 'alpha')| renders the bounded area patch using a
|
||||
% partially-transparent patch the same color as the corresponding line(s).
|
||||
% If not included, the bounded area will use a fully-opaque patch in a
|
||||
% lighter shade of the corresponding line color.
|
||||
%
|
||||
% |boundedline(..., 'transparency', transp)| indicates the
|
||||
% tranparency or intensity of the bounds patch, using a scalar between 0
|
||||
% and 1. Default is 0.2.
|
||||
%
|
||||
% |boundedline(..., 'orientation', orient)| indicates the orientation of
|
||||
% the bounds. Orientation can be either |'vert'| for vertical (y-direction)
|
||||
% bounds, or |'horiz'| for horizontal (x-direction) bounds. Default is
|
||||
% |'vert'|.
|
||||
%
|
||||
% |boundedline(..., 'nan', nanflag)| indicates how the bounds patch should
|
||||
% handle NaNs in the line coordinates or bounds values. Options are
|
||||
% |'fill'|, to smooth over the gap using neighboring values, |'gap'| to
|
||||
% leave a blank space in the patch at those points, or |'remove'| to drop
|
||||
% the NaN-points entirely, leading to linear interpolation of the gap in
|
||||
% the patch. See examples below for more details on these options.
|
||||
%
|
||||
% |boundedline(..., 'cmap', cmap)| colors the lines (in order of plotting)
|
||||
% acording to the colors in this n x 3 colormap array, overriding any
|
||||
% linespec or default colors.
|
||||
%
|
||||
% |boundedline(..., ax)| plots the bounded line to the axis indicated by
|
||||
% handle |ax|. If not included, the current axis is used.
|
||||
%
|
||||
% |[hl, hp] = boundedline(...)| returns the handles the resulting line
|
||||
% and patch object(s).
|
||||
%
|
||||
% |hout = outlinebounds(hl, hp)| adds an outline to the bounds patch
|
||||
% generated by |boundedline|, returning the handle of the resulting line
|
||||
% object in |hout|.
|
||||
%
|
||||
% Full details of all input and output variables for both functions can be
|
||||
% accessed via the |help| function.
|
||||
|
||||
%% Example 1: Plotting lines using various syntax options
|
||||
%
|
||||
% This example builds the 4-panel example image used on the MatlabCentral
|
||||
% File Exchange, which shows several different methods for supplying line
|
||||
% coordinates, bounds coordinates, and shading options.
|
||||
%
|
||||
% The first axis plots two lines using the LineSpec option for input, which
|
||||
% allows yoy to set line color, line color, and marker type for each line.
|
||||
% The bounds on the first line vary over x, while the bounds on the second
|
||||
% line are constant for all x. An outline is added to the bounds so the
|
||||
% overlapping region can be seen more clearly.
|
||||
|
||||
x = linspace(0, 2*pi, 50);
|
||||
y1 = sin(x);
|
||||
y2 = cos(x);
|
||||
e1 = rand(size(y1))*.5+.5;
|
||||
e2 = [.25 .5];
|
||||
|
||||
ax(1) = subplot(2,2,1);
|
||||
[l,p] = boundedline(x, y1, e1, '-b*', x, y2, e2, '--ro');
|
||||
outlinebounds(l,p);
|
||||
title('Opaque bounds, with outline');
|
||||
axis tight;
|
||||
|
||||
%%
|
||||
% For our second axis, we use the same 2 lines, and this time assign
|
||||
% x-varying bounds to both lines. Rather than using the LineSpec syntax,
|
||||
% this example uses the default color order to assign the colors of the
|
||||
% lines and patches. I also turn on the |'alpha'| option, which renders
|
||||
% the patch with partial transparency.
|
||||
|
||||
ax(2) = subplot(2,2,2);
|
||||
boundedline(x, [y1;y2], rand(length(y1),2,2)*.5+.5, 'alpha');
|
||||
title('Transparent bounds');
|
||||
axis tight;
|
||||
|
||||
%%
|
||||
% The bounds can also be assigned to a horizontal orientation, for a case
|
||||
% where the x-axis represents the dependent variable. In this case, the
|
||||
% scalar error bound value applies to both lines and both sides of the
|
||||
% lines.
|
||||
|
||||
ax(3) = subplot(2,2,3);
|
||||
boundedline([y1;y2], x, e1(1), 'orientation', 'horiz')
|
||||
title('Horizontal bounds');
|
||||
axis tight;
|
||||
|
||||
%%
|
||||
% Rather than use a LineSpec or the default color order, a colormap array
|
||||
% can be used to assign colors. In this case, increasingly-narrower bounds
|
||||
% are added on top of the same line.
|
||||
|
||||
ax(4) = subplot(2,2,4);
|
||||
boundedline(x, repmat(y1, 4,1), permute(0.5:-0.1:0.2, [3 1 2]), ...
|
||||
'cmap', cool(4), ...
|
||||
'transparency', 0.5);
|
||||
title('Multiple bounds using colormap');
|
||||
|
||||
set(ax([1 2 4]), 'xlim', [0 2*pi]);
|
||||
set(ax(3), 'ylim', [0 2*pi]);
|
||||
axis tight;
|
||||
|
||||
%% Example 2: Filling gaps
|
||||
%
|
||||
% If you plot a line with one or more NaNs in either the |x| or |y| vector,
|
||||
% the NaN location is rendered as a missing marker with a gap in the line.
|
||||
% However, the |patch| command does not handle NaNs gracefully; it simply
|
||||
% fails to show the patch at all if any of the coordinates include NaNs.
|
||||
%
|
||||
% Because of this, the expected behavior of the patch part of boundedline
|
||||
% when confronted with a NaN in either the bounds array (|b|) or the
|
||||
% x/y-coordinates of the line (which are used to calculate the patch
|
||||
% coordinates) is ambiguous. I offer a few options.
|
||||
%
|
||||
% Before I demonstrate the options, I'll create a dataset that has a few
|
||||
% different types of gaps:
|
||||
|
||||
x = linspace(0, 2*pi, 50);
|
||||
y = sin(x);
|
||||
b = [ones(size(y))*0.2; rand(size(y))*.5+.5]';
|
||||
|
||||
y(10) = NaN; % NaN in the line but not bounds
|
||||
b(20,1) = NaN; % NaN in lower bound but not line
|
||||
b(30,2) = NaN; % NaN in upper bound but not line
|
||||
b(40,:) = NaN; % NaN in both sides of bound but not line
|
||||
|
||||
%%
|
||||
% Here's what that looks like in an errorbar plot.
|
||||
|
||||
figure;
|
||||
he = errorbar(x,y,b(:,1), b(:,2), '-bo');
|
||||
|
||||
|
||||
line([x([10 20 30 40]); x([10 20 30 40])], [ones(1,4)*-2;ones(1,4)*2], ...
|
||||
'color', ones(1,3)*0.5, 'linestyle', ':');
|
||||
text(x(10), sin(x(10))-0.2, {'\uparrow','Line','gap'}, 'vert', 'top', 'horiz', 'center');
|
||||
text(x(20), sin(x(20))-0.2, {'\uparrow','Lower','bound','gap'}, 'vert', 'top', 'horiz', 'center');
|
||||
text(x(30), sin(x(30))-0.2, {'\uparrow','Upper','bound','gap'}, 'vert', 'top', 'horiz', 'center');
|
||||
text(x(40), sin(x(40))-0.2, {'\uparrow','Two-sided','bound','gap'}, 'vert', 'top', 'horiz', 'center');
|
||||
|
||||
axis tight equal;
|
||||
|
||||
%%
|
||||
% The default method for dealing with NaNs in boundedline is to leave the
|
||||
% gap in the line, but smooth over the gap in the bounds based on the
|
||||
% neighboring points. This option can be nice if you only have one or two
|
||||
% missing points, and you're not interested in emphasizing those gaps in
|
||||
% your plot:
|
||||
|
||||
delete(he);
|
||||
[hl,hp] = boundedline(x,y,b,'-bo', 'nan', 'fill');
|
||||
ho = outlinebounds(hl,hp);
|
||||
set(ho, 'linestyle', ':', 'color', 'r', 'marker', '.');
|
||||
|
||||
%%
|
||||
% I've added bounds outlines in a contrasting color so you can see how I'm
|
||||
% handling individual points.
|
||||
%
|
||||
% The second option leaves a full gap in the patch for any NaN. I
|
||||
% considered allowing one-sided gaps, but couldn't think of a good way to
|
||||
% distinguish a gap from a zero-valued bound. I'm open to suggestions if
|
||||
% you have any (email me).
|
||||
|
||||
delete([hl hp ho]);
|
||||
[hl,hp] = boundedline(x,y,b,'-bo', 'nan', 'gap');
|
||||
ho = outlinebounds(hl,hp);
|
||||
set(ho, 'linestyle', ':', 'color', 'r', 'marker', '.');
|
||||
|
||||
%%
|
||||
% The final option removes points from the patch that are NaNs. The visual
|
||||
% result is very similar to the fill option, but the missing points are
|
||||
% apparent if you plot the bounds outlines.
|
||||
|
||||
delete([hl hp ho]);
|
||||
[hl,hp] = boundedline(x,y,b,'-bo', 'nan', 'remove');
|
||||
ho = outlinebounds(hl,hp);
|
||||
set(ho, 'linestyle', ':', 'color', 'r', 'marker', '.');
|
||||
|
||||
|
||||
%% Contributions
|
||||
%
|
||||
% Community contributions to this package are welcome!
|
||||
%
|
||||
% To report bugs, please submit
|
||||
% <https://github.com/kakearney/boundedline-pkg/issues an issue> on GitHub and
|
||||
% include:
|
||||
%
|
||||
% * your operating system
|
||||
% * your version of Matlab and all relevant toolboxes (type |ver| at the Matlab command line to get this info)
|
||||
% * code/data to reproduce the error or buggy behavior, and the full text of any error messages received
|
||||
%
|
||||
% Please also feel free to submit enhancement requests, or to send pull
|
||||
% requests (via GitHub) for bug fixes or new features.
|
||||
%
|
||||
% I do monitor the MatlabCentral FileExchange entry for any issues raised
|
||||
% in the comments, but would prefer to track issues on GitHub.
|
||||
%
|
||||
|
||||
279
Functions/helper_functions_community/boundedlines/README.md
Normal file
@@ -0,0 +1,279 @@
|
||||
|
||||
# boundedline.m: line with shaded error/confidence bounds
|
||||
|
||||
|
||||
Author: Kelly Kearney
|
||||
[](https://www.mathworks.com/matlabcentral/fileexchange/27485-boundedline-m)
|
||||
|
||||
|
||||
This repository includes the code for the `boundedline.m` Matlab function and the accompanying `outlinebounds.m` function, along with all dependent functions required to run them.
|
||||
|
||||
|
||||
The `boundedline` function allows a user to easily plot and line with a shaded patch around it. Ths sort of plot is often used to indicate uncertainty intervals or error bounds around a line.
|
||||
|
||||
|
||||
|
||||
## Contents
|
||||
|
||||
|
||||
- Getting started
|
||||
- Syntax
|
||||
- Example 1: Plotting lines using various syntax options
|
||||
- Example 2: Filling gaps
|
||||
- Contributions
|
||||
|
||||
## Getting started
|
||||
|
||||
|
||||
**Prerequisites**
|
||||
|
||||
|
||||
This function requires Matlab R14 or later.
|
||||
|
||||
|
||||
**Downloading and installation**
|
||||
|
||||
|
||||
This code can be downloaded from [Github](https://github.com/kakearney/boundedline-pkg/) or the [MatlabCentral File Exchange](http://www.mathworks.com/matlabcentral/fileexchange/27485-boundedline-m). The File Exchange entry is updated daily from the GitHub repository.
|
||||
|
||||
|
||||
**Matlab Search Path**
|
||||
|
||||
|
||||
The following folders need to be added to your Matlab Search path (via `addpath`, `pathtool`, etc.):
|
||||
|
||||
|
||||
|
||||
```matlab
|
||||
boundedline-pkg/Inpaint_nans
|
||||
boundedline-pkg/boundedline
|
||||
boundedline-pkg/catuneven
|
||||
boundedline-pkg/singlepatch
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
|
||||
`boundedline(x, y, b)` plots a line with coordinates given by `x` and `y`, surrounded by a patch extending a certain distance `b` above/below that line. The dimensions of the `x`, `y`, and `b` arrays can vary to allow for multiple lines to be plotted at once, and for patch bounds to be either constant or varying along the length of the line. See function header help for full details of these variations.
|
||||
|
||||
|
||||
`boundedline(..., 'alpha')` renders the bounded area patch using a partially-transparent patch the same color as the corresponding line(s). If not included, the bounded area will use a fully-opaque patch in a lighter shade of the corresponding line color.
|
||||
|
||||
|
||||
`boundedline(..., 'transparency', transp)` indicates the tranparency or intensity of the bounds patch, using a scalar between 0 and 1. Default is 0.2.
|
||||
|
||||
|
||||
`boundedline(..., 'orientation', orient)` indicates the orientation of the bounds. Orientation can be either `'vert'` for vertical (y-direction) bounds, or `'horiz'` for horizontal (x-direction) bounds. Default is `'vert'`.
|
||||
|
||||
|
||||
`boundedline(..., 'nan', nanflag)` indicates how the bounds patch should handle NaNs in the line coordinates or bounds values. Options are `'fill'`, to smooth over the gap using neighboring values, `'gap'` to leave a blank space in the patch at those points, or `'remove'` to drop the NaN-points entirely, leading to linear interpolation of the gap in the patch. See examples below for more details on these options.
|
||||
|
||||
|
||||
`boundedline(..., 'cmap', cmap)` colors the lines (in order of plotting) acording to the colors in this n x 3 colormap array, overriding any linespec or default colors.
|
||||
|
||||
|
||||
`boundedline(..., ax)` plots the bounded line to the axis indicated by handle `ax`. If not included, the current axis is used.
|
||||
|
||||
|
||||
`[hl, hp] = boundedline(...)` returns the handles the resulting line and patch object(s).
|
||||
|
||||
|
||||
`hout = outlinebounds(hl, hp)` adds an outline to the bounds patch generated by `boundedline`, returning the handle of the resulting line object in `hout`.
|
||||
|
||||
|
||||
Full details of all input and output variables for both functions can be accessed via the `help` function.
|
||||
|
||||
|
||||
|
||||
## Example 1: Plotting lines using various syntax options
|
||||
|
||||
|
||||
This example builds the 4-panel example image used on the MatlabCentral File Exchange, which shows several different methods for supplying line coordinates, bounds coordinates, and shading options.
|
||||
|
||||
|
||||
The first axis plots two lines using the LineSpec option for input, which allows you to set line color, line color, and marker type for each line. The bounds on the first line vary over x, while the bounds on the second line are constant for all x. An outline is added to the bounds so the overlapping region can be seen more clearly.
|
||||
|
||||
|
||||
|
||||
```matlab
|
||||
x = linspace(0, 2*pi, 50);
|
||||
y1 = sin(x);
|
||||
y2 = cos(x);
|
||||
e1 = rand(size(y1))*.5+.5;
|
||||
e2 = [.25 .5];
|
||||
|
||||
ax(1) = subplot(2,2,1);
|
||||
[l,p] = boundedline(x, y1, e1, '-b*', x, y2, e2, '--ro');
|
||||
outlinebounds(l,p);
|
||||
title('Opaque bounds, with outline');
|
||||
axis tight;
|
||||
```
|
||||
|
||||
|
||||

|
||||
|
||||
For our second axis, we use the same 2 lines, and this time assign x-varying bounds to both lines. Rather than using the LineSpec syntax, this example uses the default color order to assign the colors of the lines and patches. I also turn on the `'alpha'` option, which renders the patch with partial transparency.
|
||||
|
||||
|
||||
|
||||
```matlab
|
||||
ax(2) = subplot(2,2,2);
|
||||
boundedline(x, [y1;y2], rand(length(y1),2,2)*.5+.5, 'alpha');
|
||||
title('Transparent bounds');
|
||||
axis tight;
|
||||
```
|
||||
|
||||
|
||||

|
||||
|
||||
The bounds can also be assigned to a horizontal orientation, for a case where the x-axis represents the dependent variable. In this case, the scalar error bound value applies to both lines and both sides of the lines.
|
||||
|
||||
|
||||
|
||||
```matlab
|
||||
ax(3) = subplot(2,2,3);
|
||||
boundedline([y1;y2], x, e1(1), 'orientation', 'horiz')
|
||||
title('Horizontal bounds');
|
||||
axis tight;
|
||||
```
|
||||
|
||||
|
||||

|
||||
|
||||
Rather than use a LineSpec or the default color order, a colormap array can be used to assign colors. In this case, increasingly-narrower bounds are added on top of the same line.
|
||||
|
||||
|
||||
|
||||
```matlab
|
||||
ax(4) = subplot(2,2,4);
|
||||
boundedline(x, repmat(y1, 4,1), permute(0.5:-0.1:0.2, [3 1 2]), ...
|
||||
'cmap', cool(4), ...
|
||||
'transparency', 0.5);
|
||||
title('Multiple bounds using colormap');
|
||||
|
||||
set(ax([1 2 4]), 'xlim', [0 2*pi]);
|
||||
set(ax(3), 'ylim', [0 2*pi]);
|
||||
axis tight;
|
||||
```
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
## Example 2: Filling gaps
|
||||
|
||||
|
||||
If you plot a line with one or more NaNs in either the `x` or `y` vector, the NaN location is rendered as a missing marker with a gap in the line. However, the `patch` command does not handle NaNs gracefully; it simply fails to show the patch at all if any of the coordinates include NaNs.
|
||||
|
||||
|
||||
Because of this, the expected behavior of the patch part of boundedline when confronted with a NaN in either the bounds array (`b`) or the x/y-coordinates of the line (which are used to calculate the patch coordinates) is ambiguous. I offer a few options.
|
||||
|
||||
|
||||
Before I demonstrate the options, I'll create a dataset that has a few different types of gaps:
|
||||
|
||||
|
||||
|
||||
```matlab
|
||||
x = linspace(0, 2*pi, 50);
|
||||
y = sin(x);
|
||||
b = [ones(size(y))*0.2; rand(size(y))*.5+.5]';
|
||||
|
||||
y(10) = NaN; % NaN in the line but not bounds
|
||||
b(20,1) = NaN; % NaN in lower bound but not line
|
||||
b(30,2) = NaN; % NaN in upper bound but not line
|
||||
b(40,:) = NaN; % NaN in both sides of bound but not line
|
||||
```
|
||||
|
||||
|
||||
Here's what that looks like in an errorbar plot.
|
||||
|
||||
|
||||
|
||||
```matlab
|
||||
figure;
|
||||
he = errorbar(x,y,b(:,1), b(:,2), '-bo');
|
||||
|
||||
|
||||
line([x([10 20 30 40]); x([10 20 30 40])], [ones(1,4)*-2;ones(1,4)*2], ...
|
||||
'color', ones(1,3)*0.5, 'linestyle', ':');
|
||||
text(x(10), sin(x(10))-0.2, {'\uparrow','Line','gap'}, 'vert', 'top', 'horiz', 'center');
|
||||
text(x(20), sin(x(20))-0.2, {'\uparrow','Lower','bound','gap'}, 'vert', 'top', 'horiz', 'center');
|
||||
text(x(30), sin(x(30))-0.2, {'\uparrow','Upper','bound','gap'}, 'vert', 'top', 'horiz', 'center');
|
||||
text(x(40), sin(x(40))-0.2, {'\uparrow','Two-sided','bound','gap'}, 'vert', 'top', 'horiz', 'center');
|
||||
|
||||
axis tight equal;
|
||||
```
|
||||
|
||||
|
||||

|
||||
|
||||
The default method for dealing with NaNs in boundedline is to leave the gap in the line, but smooth over the gap in the bounds based on the neighboring points. This option can be nice if you only have one or two missing points, and you're not interested in emphasizing those gaps in your plot:
|
||||
|
||||
|
||||
|
||||
```matlab
|
||||
delete(he);
|
||||
[hl,hp] = boundedline(x,y,b,'-bo', 'nan', 'fill');
|
||||
ho = outlinebounds(hl,hp);
|
||||
set(ho, 'linestyle', ':', 'color', 'r', 'marker', '.');
|
||||
```
|
||||
|
||||
|
||||

|
||||
|
||||
I've added bounds outlines in a contrasting color so you can see how I'm handling individual points.
|
||||
|
||||
|
||||
The second option leaves a full gap in the patch for any NaN. I considered allowing one-sided gaps, but couldn't think of a good way to distinguish a gap from a zero-valued bound. I'm open to suggestions if you have any (email me).
|
||||
|
||||
|
||||
|
||||
```matlab
|
||||
delete([hl hp ho]);
|
||||
[hl,hp] = boundedline(x,y,b,'-bo', 'nan', 'gap');
|
||||
ho = outlinebounds(hl,hp);
|
||||
set(ho, 'linestyle', ':', 'color', 'r', 'marker', '.');
|
||||
```
|
||||
|
||||
|
||||

|
||||
|
||||
The final option removes points from the patch that are NaNs. The visual result is very similar to the fill option, but the missing points are apparent if you plot the bounds outlines.
|
||||
|
||||
|
||||
|
||||
```matlab
|
||||
delete([hl hp ho]);
|
||||
[hl,hp] = boundedline(x,y,b,'-bo', 'nan', 'remove');
|
||||
ho = outlinebounds(hl,hp);
|
||||
set(ho, 'linestyle', ':', 'color', 'r', 'marker', '.');
|
||||
```
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
## Contributions
|
||||
|
||||
|
||||
Community contributions to this package are welcome!
|
||||
|
||||
|
||||
To report bugs, please submit [an issue](https://github.com/kakearney/boundedline-pkg/issues) on GitHub and include:
|
||||
|
||||
|
||||
|
||||
- your operating system
|
||||
- your version of Matlab and all relevant toolboxes (type `ver` at the Matlab command line to get this info)
|
||||
- code/data to reproduce the error or buggy behavior, and the full text of any error messages received
|
||||
|
||||
Please also feel free to submit enhancement requests, or to send pull requests (via GitHub) for bug fixes or new features.
|
||||
|
||||
|
||||
I do monitor the MatlabCentral FileExchange entry for any issues raised in the comments, but would prefer to track issues on GitHub.
|
||||
|
||||
|
||||
|
||||
<sub>[Published with MATLAB R2016b]("http://www.mathworks.com/products/matlab/")</sub>
|
||||
37
Functions/helper_functions_community/boundedlines/boundedline/.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
*.class
|
||||
*.dll
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
|
||||
# Packages #
|
||||
############
|
||||
# it's better to unpack these files and commit the raw source
|
||||
# git has its own built in compression methods
|
||||
*.7z
|
||||
*.dmg
|
||||
*.gz
|
||||
*.iso
|
||||
*.jar
|
||||
*.rar
|
||||
*.tar
|
||||
*.zip
|
||||
|
||||
# Logs and databases #
|
||||
######################
|
||||
*.log
|
||||
*.sql
|
||||
*.sqlite
|
||||
|
||||
# OS generated files #
|
||||
######################
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
@@ -0,0 +1,501 @@
|
||||
function varargout = boundedline(varargin)
|
||||
%BOUNDEDLINE Plot a line with shaded error/confidence bounds
|
||||
%
|
||||
% [hl, hp] = boundedline(x, y, b)
|
||||
% [hl, hp] = boundedline(x, y, b, linespec)
|
||||
% [hl, hp] = boundedline(x1, y1, b1, linespec1, x2, y2, b2, linespec2)
|
||||
% [hl, hp] = boundedline(..., 'alpha')
|
||||
% [hl, hp] = boundedline(..., ax)
|
||||
% [hl, hp] = boundedline(..., 'transparency', trans)
|
||||
% [hl, hp] = boundedline(..., 'orientation', orient)
|
||||
% [hl, hp] = boundedline(..., 'nan', nanflag)
|
||||
% [hl, hp] = boundedline(..., 'cmap', cmap)
|
||||
%
|
||||
% Input variables:
|
||||
%
|
||||
% x, y: x and y values, either vectors of the same length, matrices
|
||||
% of the same size, or vector/matrix pair where the row or
|
||||
% column size of the array matches the length of the vector
|
||||
% (same requirements as for plot function).
|
||||
%
|
||||
% b: npoint x nside x nline array. Distance from line to
|
||||
% boundary, for each point along the line (dimension 1), for
|
||||
% each side of the line (lower/upper or left/right, depending
|
||||
% on orientation) (dimension 2), and for each plotted line
|
||||
% described by the preceding x-y values (dimension 3). If
|
||||
% size(b,1) == 1, the bounds will be the same for all points
|
||||
% along the line. If size(b,2) == 1, the bounds will be
|
||||
% symmetrical on both sides of the lines. If size(b,3) == 1,
|
||||
% the same bounds will be applied to all lines described by
|
||||
% the preceding x-y arrays (only applicable when either x or
|
||||
% y is an array). Bounds cannot include Inf, -Inf, or NaN,
|
||||
%
|
||||
% linespec: line specification that determines line type, marker
|
||||
% symbol, and color of the plotted lines for the preceding
|
||||
% x-y values.
|
||||
%
|
||||
% 'alpha': if included, the bounded area will be rendered with a
|
||||
% partially-transparent patch the same color as the
|
||||
% corresponding line(s). If not included, the bounded area
|
||||
% will be an opaque patch with a lighter shade of the
|
||||
% corresponding line color.
|
||||
%
|
||||
% ax: handle of axis where lines will be plotted. If not
|
||||
% included, the current axis will be used.
|
||||
%
|
||||
% transp: Scalar between 0 and 1 indicating with the transparency or
|
||||
% intensity of color of the bounded area patch. Default is
|
||||
% 0.2.
|
||||
%
|
||||
% orient: direction to add bounds
|
||||
% 'vert': add bounds in vertical (y) direction (default)
|
||||
% 'horiz': add bounds in horizontal (x) direction
|
||||
%
|
||||
% nanflag: Sets how NaNs in the boundedline patch should be handled
|
||||
% 'fill': fill the value based on neighboring values,
|
||||
% smoothing over the gap
|
||||
% 'gap': leave a blank space over/below the line
|
||||
% 'remove': drop NaNs from patches, creating a linear
|
||||
% interpolation over the gap. Note that this
|
||||
% applies only to the bounds; NaNs in the line will
|
||||
% remain.
|
||||
%
|
||||
% cmap: n x 3 colormap array. If included, lines will be colored
|
||||
% (in order of plotting) according to this colormap,
|
||||
% overriding any linespec or default colors.
|
||||
%
|
||||
% Output variables:
|
||||
%
|
||||
% hl: handles to line objects
|
||||
%
|
||||
% hp: handles to patch objects
|
||||
%
|
||||
% Example:
|
||||
%
|
||||
% x = linspace(0, 2*pi, 50);
|
||||
% y1 = sin(x);
|
||||
% y2 = cos(x);
|
||||
% e1 = rand(size(y1))*.5+.5;
|
||||
% e2 = [.25 .5];
|
||||
%
|
||||
% ax(1) = subplot(2,2,1);
|
||||
% [l,p] = boundedline(x, y1, e1, '-b*', x, y2, e2, '--ro');
|
||||
% outlinebounds(l,p);
|
||||
% title('Opaque bounds, with outline');
|
||||
%
|
||||
% ax(2) = subplot(2,2,2);
|
||||
% boundedline(x, [y1;y2], rand(length(y1),2,2)*.5+.5, 'alpha');
|
||||
% title('Transparent bounds');
|
||||
%
|
||||
% ax(3) = subplot(2,2,3);
|
||||
% boundedline([y1;y2], x, e1(1), 'orientation', 'horiz')
|
||||
% title('Horizontal bounds');
|
||||
%
|
||||
% ax(4) = subplot(2,2,4);
|
||||
% boundedline(x, repmat(y1, 4,1), permute(0.5:-0.1:0.2, [3 1 2]), ...
|
||||
% 'cmap', cool(4), 'transparency', 0.5);
|
||||
% title('Multiple bounds using colormap');
|
||||
|
||||
|
||||
% Copyright 2010 Kelly Kearney
|
||||
|
||||
%--------------------
|
||||
% Parse input
|
||||
%--------------------
|
||||
|
||||
% Color and cmap are mechanically the same:
|
||||
|
||||
tmp = strncmpi(varargin,'color',3);
|
||||
if any(tmp)
|
||||
varargin{tmp} = 'cmap';
|
||||
end
|
||||
|
||||
% Alpha flag
|
||||
|
||||
isalpha = cellfun(@(x) ischar(x) && strcmp(x, 'alpha'), varargin);
|
||||
if any(isalpha)
|
||||
usealpha = true;
|
||||
varargin = varargin(~isalpha);
|
||||
else
|
||||
usealpha = false;
|
||||
end
|
||||
|
||||
% Axis
|
||||
|
||||
isax = cellfun(@(x) isscalar(x) && ishandle(x) && strcmp('axes', get(x,'type')), varargin);
|
||||
if any(isax)
|
||||
hax = varargin{isax};
|
||||
varargin = varargin(~isax);
|
||||
else
|
||||
hax = gca;
|
||||
end
|
||||
|
||||
% Transparency
|
||||
|
||||
[found, trans, varargin] = parseparam(varargin, 'transparency');
|
||||
|
||||
if ~found
|
||||
trans = 0.2;
|
||||
end
|
||||
|
||||
if ~isscalar(trans) || trans < 0 || trans > 1
|
||||
error('Transparency must be scalar between 0 and 1');
|
||||
end
|
||||
|
||||
% Orientation
|
||||
|
||||
[found, orient, varargin] = parseparam(varargin, 'orientation');
|
||||
|
||||
if ~found
|
||||
orient = 'vert';
|
||||
end
|
||||
|
||||
if strcmp(orient, 'vert')
|
||||
isvert = true;
|
||||
elseif strcmp(orient, 'horiz')
|
||||
isvert = false;
|
||||
else
|
||||
error('Orientation must be ''vert'' or ''horiz''');
|
||||
end
|
||||
|
||||
% Colormap
|
||||
|
||||
[hascmap, cmap, varargin] = parseparam(varargin, 'cmap');
|
||||
|
||||
% NaN flag
|
||||
|
||||
[found, nanflag, varargin] = parseparam(varargin, 'nan');
|
||||
if ~found
|
||||
nanflag = 'fill';
|
||||
end
|
||||
if ~ismember(nanflag, {'fill', 'gap', 'remove'})
|
||||
error('Nan flag must be ''fill'', ''gap'', or ''remove''');
|
||||
end
|
||||
|
||||
[haslw, lwidth, varargin] = parseparam(varargin, 'linewidth');
|
||||
if ~haslw
|
||||
lwidth = get(0, 'DefaultLineLineWidth');
|
||||
end
|
||||
|
||||
% X, Y, E triplets, and linespec
|
||||
|
||||
[x,y,err,linespec] = deal(cell(0));
|
||||
while ~isempty(varargin)
|
||||
if length(varargin) < 3
|
||||
error('Unexpected input: should be x, y, bounds triplets');
|
||||
end
|
||||
if all(cellfun(@isnumeric, varargin(1:3)))
|
||||
x = [x varargin(1)];
|
||||
y = [y varargin(2)];
|
||||
err = [err varargin(3)];
|
||||
varargin(1:3) = [];
|
||||
else
|
||||
if any(cellfun(@(x) isa(x, 'datetime'), varargin(1:3)))
|
||||
% Special error message for most likely culprit: datetimes
|
||||
error('boundedline cannot support datetime input due to incompatibility between patches and datetime axes; please convert to datenumbers instead');
|
||||
else
|
||||
% Otherwise
|
||||
error('Unexpected input: should be numeric x, y, bounds triplets');
|
||||
end
|
||||
end
|
||||
if ~isempty(varargin) && ischar(varargin{1})
|
||||
linespec = [linespec varargin(1)];
|
||||
varargin(1) = [];
|
||||
else
|
||||
linespec = [linespec {[]}];
|
||||
end
|
||||
end
|
||||
|
||||
%--------------------
|
||||
% Reformat x and y
|
||||
% for line and patch
|
||||
% plotting
|
||||
%--------------------
|
||||
|
||||
% Calculate y values for bounding lines
|
||||
|
||||
plotdata = cell(0,7);
|
||||
|
||||
htemp = figure('visible', 'off');
|
||||
for ix = 1:length(x)
|
||||
|
||||
% Get full x, y, and linespec data for each line (easier to let plot
|
||||
% check for properly-sized x and y and expand values than to try to do
|
||||
% it myself)
|
||||
|
||||
try
|
||||
if isempty(linespec{ix})
|
||||
hltemp = plot(x{ix}, y{ix});
|
||||
else
|
||||
hltemp = plot(x{ix}, y{ix}, linespec{ix});
|
||||
end
|
||||
catch
|
||||
close(htemp);
|
||||
error('X and Y matrices and/or linespec not appropriate for line plot');
|
||||
end
|
||||
|
||||
linedata = get(hltemp, {'xdata', 'ydata', 'marker', 'linestyle', 'color'});
|
||||
|
||||
nline = size(linedata,1);
|
||||
|
||||
% Expand bounds matrix if necessary
|
||||
|
||||
if nline > 1
|
||||
if ndims(err{ix}) == 3
|
||||
err2 = squeeze(num2cell(err{ix},[1 2]));
|
||||
else
|
||||
err2 = repmat(err(ix),nline,1);
|
||||
end
|
||||
else
|
||||
err2 = err(ix);
|
||||
end
|
||||
|
||||
% Figure out upper and lower bounds
|
||||
|
||||
[lo, hi] = deal(cell(nline,1));
|
||||
for iln = 1:nline
|
||||
|
||||
x2 = linedata{iln,1};
|
||||
y2 = linedata{iln,2};
|
||||
nx = length(x2);
|
||||
|
||||
if isvert
|
||||
lineval = y2;
|
||||
else
|
||||
lineval = x2;
|
||||
end
|
||||
|
||||
sz = size(err2{iln});
|
||||
|
||||
if isequal(sz, [nx 2])
|
||||
lo{iln} = lineval - err2{iln}(:,1)';
|
||||
hi{iln} = lineval + err2{iln}(:,2)';
|
||||
elseif isequal(sz, [nx 1])
|
||||
lo{iln} = lineval - err2{iln}';
|
||||
hi{iln} = lineval + err2{iln}';
|
||||
elseif isequal(sz, [1 2])
|
||||
lo{iln} = lineval - err2{iln}(1);
|
||||
hi{iln} = lineval + err2{iln}(2);
|
||||
elseif isequal(sz, [1 1])
|
||||
lo{iln} = lineval - err2{iln};
|
||||
hi{iln} = lineval + err2{iln};
|
||||
elseif isequal(sz, [2 nx]) % not documented, but accepted anyways
|
||||
lo{iln} = lineval - err2{iln}(:,1);
|
||||
hi{iln} = lineval + err2{iln}(:,2);
|
||||
elseif isequal(sz, [1 nx]) % not documented, but accepted anyways
|
||||
lo{iln} = lineval - err2{iln};
|
||||
hi{iln} = lineval + err2{iln};
|
||||
elseif isequal(sz, [2 1]) % not documented, but accepted anyways
|
||||
lo{iln} = lineval - err2{iln}(1);
|
||||
hi{iln} = lineval + err2{iln}(2);
|
||||
else
|
||||
error('Error bounds must be npt x nside x nline array');
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
% Combine all data (xline, yline, marker, linestyle, color, lower bound
|
||||
% (x or y), upper bound (x or y)
|
||||
|
||||
plotdata = [plotdata; linedata lo hi];
|
||||
|
||||
end
|
||||
close(htemp);
|
||||
|
||||
% Override colormap
|
||||
|
||||
if hascmap
|
||||
nd = size(plotdata,1);
|
||||
cmap = repmat(cmap, ceil(nd/size(cmap,1)), 1);
|
||||
cmap = cmap(1:nd,:);
|
||||
plotdata(:,5) = num2cell(cmap,2);
|
||||
end
|
||||
|
||||
|
||||
%--------------------
|
||||
% Plot
|
||||
%--------------------
|
||||
|
||||
% Setup of x and y, plus line and patch properties
|
||||
|
||||
nline = size(plotdata,1);
|
||||
[xl, yl, xp, yp, marker, lnsty, lncol, ptchcol, alpha] = deal(cell(nline,1));
|
||||
|
||||
for iln = 1:nline
|
||||
xl{iln} = plotdata{iln,1};
|
||||
yl{iln} = plotdata{iln,2};
|
||||
% if isvert
|
||||
% xp{iln} = [plotdata{iln,1} fliplr(plotdata{iln,1})];
|
||||
% yp{iln} = [plotdata{iln,6} fliplr(plotdata{iln,7})];
|
||||
% else
|
||||
% xp{iln} = [plotdata{iln,6} fliplr(plotdata{iln,7})];
|
||||
% yp{iln} = [plotdata{iln,2} fliplr(plotdata{iln,2})];
|
||||
% end
|
||||
|
||||
[xp{iln}, yp{iln}] = calcpatch(plotdata{iln,1}, plotdata{iln,2}, isvert, plotdata{iln,6}, plotdata{iln,7}, nanflag);
|
||||
|
||||
marker{iln} = plotdata{iln,3};
|
||||
lnsty{iln} = plotdata{iln,4};
|
||||
|
||||
if usealpha
|
||||
lncol{iln} = plotdata{iln,5};
|
||||
ptchcol{iln} = plotdata{iln,5};
|
||||
alpha{iln} = trans;
|
||||
else
|
||||
lncol{iln} = plotdata{iln,5};
|
||||
ptchcol{iln} = interp1([0 1], [1 1 1; lncol{iln}], trans);
|
||||
alpha{iln} = 1;
|
||||
end
|
||||
end
|
||||
|
||||
% Plot patches and lines
|
||||
|
||||
if verLessThan('matlab', '8.4.0')
|
||||
[hp,hl] = deal(zeros(nline,1));
|
||||
else
|
||||
[hp,hl] = deal(gobjects(nline,1));
|
||||
end
|
||||
|
||||
|
||||
for iln = 1:nline
|
||||
hp(iln) = patch(xp{iln}, yp{iln}, ptchcol{iln}, ...
|
||||
'facealpha', alpha{iln}, ...
|
||||
'edgecolor', 'none', ...
|
||||
'parent', hax);
|
||||
end
|
||||
|
||||
for iln = 1:nline
|
||||
hl(iln) = line(xl{iln}, yl{iln}, ...
|
||||
'marker', marker{iln}, ...
|
||||
'linestyle', lnsty{iln}, ...
|
||||
'color', lncol{iln}, ...
|
||||
'linewidth', lwidth, ...
|
||||
'parent', hax);
|
||||
end
|
||||
|
||||
%--------------------
|
||||
% Assign output
|
||||
%--------------------
|
||||
|
||||
nargoutchk(0,2);
|
||||
|
||||
if nargout >= 1
|
||||
varargout{1} = hl;
|
||||
end
|
||||
|
||||
if nargout == 2
|
||||
varargout{2} = hp;
|
||||
end
|
||||
|
||||
%--------------------
|
||||
% Parse optional
|
||||
% parameters
|
||||
%--------------------
|
||||
|
||||
function [found, val, vars] = parseparam(vars, param)
|
||||
|
||||
isvar = cellfun(@(x) ischar(x) && strcmpi(x, param), vars);
|
||||
|
||||
if sum(isvar) > 1
|
||||
error('Parameters can only be passed once');
|
||||
end
|
||||
|
||||
if any(isvar)
|
||||
found = true;
|
||||
idx = find(isvar);
|
||||
val = vars{idx+1};
|
||||
vars([idx idx+1]) = [];
|
||||
else
|
||||
found = false;
|
||||
val = [];
|
||||
end
|
||||
|
||||
%----------------------------
|
||||
% Calculate patch coordinates
|
||||
%----------------------------
|
||||
|
||||
function [xp, yp] = calcpatch(xl, yl, isvert, lo, hi, nanflag)
|
||||
|
||||
ismissing = isnan([xl;yl;lo;hi]);
|
||||
|
||||
% If gap method, split
|
||||
|
||||
if any(ismissing(:)) && strcmp(nanflag, 'gap')
|
||||
|
||||
tmp = [xl;yl;lo;hi];
|
||||
|
||||
idx = find(any(ismissing,1));
|
||||
n = diff([0 idx length(xl)]);
|
||||
|
||||
tmp = mat2cell(tmp, 4, n);
|
||||
isemp = cellfun('isempty', tmp);
|
||||
tmp = tmp(~isemp);
|
||||
|
||||
tmp = cellfun(@(a) a(:,~any(isnan(a),1)), tmp, 'uni', 0);
|
||||
isemp = cellfun('isempty', tmp);
|
||||
tmp = tmp(~isemp);
|
||||
|
||||
xl = cellfun(@(a) a(1,:), tmp, 'uni', 0);
|
||||
yl = cellfun(@(a) a(2,:), tmp, 'uni', 0);
|
||||
lo = cellfun(@(a) a(3,:), tmp, 'uni', 0);
|
||||
hi = cellfun(@(a) a(4,:), tmp, 'uni', 0);
|
||||
else
|
||||
xl = {xl};
|
||||
yl = {yl};
|
||||
lo = {lo};
|
||||
hi = {hi};
|
||||
end
|
||||
|
||||
[xp, yp] = deal(cell(size(xl)));
|
||||
|
||||
for ii = 1:length(xl)
|
||||
|
||||
iseq = ~verLessThan('matlab', '8.4.0') && isequal(lo{ii}, hi{ii}); % deal with zero-width bug in R2014b/R2015a
|
||||
|
||||
if isvert
|
||||
if iseq
|
||||
xp{ii} = [xl{ii} nan(size(xl{ii}))];
|
||||
yp{ii} = [lo{ii} fliplr(hi{ii})];
|
||||
else
|
||||
xp{ii} = [xl{ii} fliplr(xl{ii})];
|
||||
yp{ii} = [lo{ii} fliplr(hi{ii})];
|
||||
end
|
||||
else
|
||||
if iseq
|
||||
xp{ii} = [lo{ii} fliplr(hi{ii})];
|
||||
yp{ii} = [yl{ii} nan(size(yl{ii}))];
|
||||
else
|
||||
xp{ii} = [lo{ii} fliplr(hi{ii})];
|
||||
yp{ii} = [yl{ii} fliplr(yl{ii})];
|
||||
end
|
||||
end
|
||||
|
||||
if strcmp(nanflag, 'fill')
|
||||
xp{ii} = inpaint_nans(xp{ii}', 4);
|
||||
yp{ii} = inpaint_nans(yp{ii}', 4);
|
||||
if iseq % need to maintain NaNs for zero-width bug
|
||||
nx = length(xp{ii});
|
||||
xp{ii}((nx/2)+1:end) = NaN;
|
||||
end
|
||||
elseif strcmp(nanflag, 'remove')
|
||||
if iseq
|
||||
nx = length(xp{ii});
|
||||
keepnan = false(size(xp));
|
||||
keepnan((nx/2)+1:end) = true;
|
||||
isn = (isnan(xp{ii}) | isnan(yp{ii})) & ~keepnan;
|
||||
else
|
||||
isn = isnan(xp{ii}) | isnan(yp{ii});
|
||||
end
|
||||
xp{ii} = xp{ii}(~isn);
|
||||
yp{ii} = yp{ii}(~isn);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if strcmp(nanflag, 'gap')
|
||||
[xp, yp] = singlepatch(xp, yp);
|
||||
else
|
||||
xp = xp{1};
|
||||
yp = yp{1};
|
||||
end
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
function hnew = outlinebounds(hl, hp)
|
||||
%OUTLINEBOUNDS Outline the patch of a boundedline
|
||||
%
|
||||
% hnew = outlinebounds(hl, hp)
|
||||
%
|
||||
% This function adds an outline to the patch objects created by
|
||||
% boundedline, matching the color of the central line associated with each
|
||||
% patch.
|
||||
%
|
||||
% Input variables:
|
||||
%
|
||||
% hl: handles to line objects from boundedline
|
||||
%
|
||||
% hp: handles to patch objects from boundedline
|
||||
%
|
||||
% Output variables:
|
||||
%
|
||||
% hnew: handle to new line objects
|
||||
|
||||
% Copyright 2012 Kelly Kearney
|
||||
|
||||
|
||||
hnew = zeros(size(hl));
|
||||
for il = 1:numel(hp)
|
||||
col = get(hl(il), 'color');
|
||||
xy = get(hp(il), {'xdata','ydata'});
|
||||
ax = ancestor(hl(il), 'axes');
|
||||
|
||||
nline = size(xy{1},2);
|
||||
if mod(size(xy{1}, 1), 2) == 0
|
||||
% Insert a NaN between upper and lower lines, so they're disconnected
|
||||
L = size(xy{1}, 1) / 2;
|
||||
xy{1} = [xy{1}(1:L, :); nan(1, nline); xy{1}(L+1:end, :)];
|
||||
xy{2} = [xy{2}(1:L, :); nan(1, nline); xy{2}(L+1:end, :)];
|
||||
end
|
||||
if nline > 1
|
||||
xy{1} = reshape([xy{1}; nan(1,nline)], [], 1);
|
||||
xy{2} = reshape([xy{2}; nan(1,nline)], [], 1);
|
||||
end
|
||||
hnew(il) = line(xy{1}, xy{2}, 'parent', ax, 'linestyle', '-', 'color', col);
|
||||
|
||||
end
|
||||
|
||||
37
Functions/helper_functions_community/boundedlines/catuneven/.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
*.class
|
||||
*.dll
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
|
||||
# Packages #
|
||||
############
|
||||
# it's better to unpack these files and commit the raw source
|
||||
# git has its own built in compression methods
|
||||
*.7z
|
||||
*.dmg
|
||||
*.gz
|
||||
*.iso
|
||||
*.jar
|
||||
*.rar
|
||||
*.tar
|
||||
*.zip
|
||||
|
||||
# Logs and databases #
|
||||
######################
|
||||
*.log
|
||||
*.sql
|
||||
*.sqlite
|
||||
|
||||
# OS generated files #
|
||||
######################
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
@@ -0,0 +1,57 @@
|
||||
function b = catuneven(dim, padval, varargin)
|
||||
%CATUNEVEN Concatenate unequally-sized arrays, padding with a value
|
||||
%
|
||||
% This function is similar to cat, except it does not require the arrays to
|
||||
% be equally-sized along non-concatenated dimensions. Instead, all arrays
|
||||
% are padded to be equally-sized using the value specified.
|
||||
%
|
||||
% b = catuneven(dim, padval, a1, a2, ...)
|
||||
%
|
||||
% Input variables:
|
||||
%
|
||||
% dim: dimension along which to concatenate
|
||||
%
|
||||
% padval: value used as placeholder when arrays are expanded
|
||||
%
|
||||
% a#: arrays to be concatenated, numerical
|
||||
%
|
||||
% Output variables:
|
||||
%
|
||||
% b: concatenated array
|
||||
|
||||
% Copyright 2013 Kelly Kearney
|
||||
|
||||
ndim = max(cellfun(@ndims, varargin));
|
||||
ndim = max(ndim, dim);
|
||||
|
||||
for ii = 1:ndim
|
||||
sz(:,ii) = cellfun(@(x) size(x, ii), varargin);
|
||||
end
|
||||
maxsz = max(sz, [], 1);
|
||||
|
||||
nv = length(varargin);
|
||||
val = cell(size(varargin));
|
||||
for ii = 1:nv
|
||||
sztmp = maxsz;
|
||||
sztmp(dim) = sz(ii,dim);
|
||||
|
||||
idx = cell(ndim,1);
|
||||
[idx{:}] = ind2sub(sz(ii,:), 1:numel(varargin{ii}));
|
||||
|
||||
idxnew = sub2ind(sztmp, idx{:});
|
||||
|
||||
try
|
||||
val{ii} = ones(sztmp) * padval;
|
||||
catch
|
||||
val{ii} = repmat(padval, sztmp);
|
||||
end
|
||||
val{ii}(idxnew) = varargin{ii};
|
||||
|
||||
end
|
||||
|
||||
b = cat(dim, val{:});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 24 KiB |
37
Functions/helper_functions_community/boundedlines/singlepatch/.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
*.class
|
||||
*.dll
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
|
||||
# Packages #
|
||||
############
|
||||
# it's better to unpack these files and commit the raw source
|
||||
# git has its own built in compression methods
|
||||
*.7z
|
||||
*.dmg
|
||||
*.gz
|
||||
*.iso
|
||||
*.jar
|
||||
*.rar
|
||||
*.tar
|
||||
*.zip
|
||||
|
||||
# Logs and databases #
|
||||
######################
|
||||
*.log
|
||||
*.sql
|
||||
*.sqlite
|
||||
|
||||
# OS generated files #
|
||||
######################
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
@@ -0,0 +1,65 @@
|
||||
function varargout = singlepatch(varargin)
|
||||
%SINGLEPATCH Concatenate patches to be plotted as one
|
||||
%
|
||||
% [xp, yp, zp, ...] = singlepatch(x, y, z, ...)
|
||||
%
|
||||
% Concatenates uneven vectors of x and y coordinates by replicating the
|
||||
% last point in each polygon. This allows patches with different numbers
|
||||
% of vertices to be plotted as one, which is often much, much more
|
||||
% efficient than plotting lots of individual patches.
|
||||
%
|
||||
% Input variables:
|
||||
%
|
||||
% x: cell array, with each cell holding a vector of coordinates
|
||||
% associates with a single patch. The input variables must all be
|
||||
% of the same size, and usually will correspond to x, y, z, and c
|
||||
% data for the patches.
|
||||
%
|
||||
% Output variables:
|
||||
%
|
||||
% xp: m x n array of coordinates, where m is the maximum length of the
|
||||
% vectors in x and n is numel(x).
|
||||
|
||||
% Copyright 2015 Kelly Kearney
|
||||
|
||||
if nargin ~= nargout
|
||||
error('Must supply the same number of input variables as output variables');
|
||||
end
|
||||
|
||||
nv = nargin;
|
||||
vars = varargin;
|
||||
|
||||
sz = cellfun(@size, vars{1}(:), 'uni', 0);
|
||||
sz = cat(1, sz{:});
|
||||
|
||||
if all(sz(:,1) == 1)
|
||||
for ii = 1:nv
|
||||
vars{ii} = catuneven(1, NaN, vars{ii}{:})';
|
||||
end
|
||||
% x = catuneven(1, NaN, x{:})';
|
||||
% y = catuneven(1, NaN, y{:})';
|
||||
elseif all(sz(:,2) == 1)
|
||||
for ii = 1:nv
|
||||
vars{ii} = catuneven(2, NaN, vars{ii}{:});
|
||||
end
|
||||
% x = catuneven(2, NaN, x{:});
|
||||
% y = catuneven(2, NaN, y{:});
|
||||
else
|
||||
error('Inputs must be cell arrays of vectors');
|
||||
end
|
||||
|
||||
[ii,jj] = find(isnan(vars{1}));
|
||||
|
||||
ind = accumarray(jj, ii, [size(vars{1},2) 1], @min);
|
||||
ij1 = [ii jj];
|
||||
ij2 = [ind(jj)-1 jj];
|
||||
idx1 = sub2ind(size(vars{1}), ij1(:,1), ij1(:,2));
|
||||
idx2 = sub2ind(size(vars{1}), ij2(:,1), ij2(:,2));
|
||||
|
||||
for ii = 1:nv
|
||||
vars{ii}(idx1) = vars{ii}(idx2);
|
||||
end
|
||||
|
||||
varargout = vars;
|
||||
|
||||
|
||||
260
Functions/helper_functions_community/cbrewer2/cbrewer2.m
Normal file
@@ -0,0 +1,260 @@
|
||||
%CBREWER2 Interpolated versions of Cynthia Brewer's ColorBrewer colormaps
|
||||
% CBREWER2(CNAME, NCOL) returns the colour scheme CNAME with the number
|
||||
% of colours equal to NCOL. If there is a ColorBrewer scheme with exactly
|
||||
% this number of colours, the color scheme is returned as-is. If NCOL
|
||||
% larger (or smaller) than the designed colormaps for this scheme, the
|
||||
% largest (smallest) one is interpolated to provide enough colours,
|
||||
% unless the requested colour scheme CNAME is a qualitative palette. For
|
||||
% a qualitative scheme, the colours are repeated, cycling from the
|
||||
% beginning again, to output the requested NCOL colours.
|
||||
%
|
||||
% CBREWER2(CNAME) without an NCOL input will use the same number of
|
||||
% colours as the current colormap.
|
||||
%
|
||||
% CBREWER2(CNAME, NCOL, INTERP_METHOD) allows you to change the method
|
||||
% used for the interpolation. The default is 'cubic'.
|
||||
%
|
||||
% CBREWER2(CNAME, NCOL, INTERP_METHOD, INTERP_SPACE) allows you to
|
||||
% change the colorspace used for the interpolation. By default, this is
|
||||
% in the CIELAB colorspace, which is approximately perceptually uniform.
|
||||
% Options for INTERP_SPACE are
|
||||
% 'rgb' : interpolation in sRGB (as used in original CBREWER)
|
||||
% 'lab' : interpolation in CIELAB (default)
|
||||
% 'lch' : interpolation in CIELCH_ab (not recommended due to the
|
||||
% discontinuities at C=0 and H=0)
|
||||
% Anything else supported by COLORSPACE will also function.
|
||||
%
|
||||
% The input format CBREWER2(TYPE, ...) can also be used, where TYPE is
|
||||
% one of 'seq', 'div', 'qual'. This input is redandant and will be
|
||||
% ignored. This input format is provided for backwards compatibility with
|
||||
% the original CBREWER.
|
||||
%
|
||||
% Example 1 (sequential heatmap):
|
||||
% C = [0 2 4 6; 8 10 12 14; 16 18 20 22];
|
||||
% imagesc(C);
|
||||
% colorbar;
|
||||
% colormap(cbrewer('YlOrRd', 256);
|
||||
%
|
||||
% Example 2 (line plot):
|
||||
% x = 0:0.01:2;
|
||||
% sc = [0.5; 1; 2];
|
||||
% t0 = [0; 0.2; 0.4];
|
||||
% t = bsxfun(@rdivide, bsxfun(@plus, x, t0), sc);
|
||||
% y = sin(t * 2 * pi);
|
||||
% cmap = cbrewer2('Set1', numel(sc));
|
||||
% axes('ColorOrder', cmap, 'NextPlot', 'ReplaceChildren');
|
||||
% plot(x, y);
|
||||
%
|
||||
% Example 3 (divergent heatmap):
|
||||
% [X,Y,Z] = peaks(30);
|
||||
% surfc(X,Y,Z);
|
||||
% colormap(cbrewer2('RdBu'));
|
||||
%
|
||||
% This product includes color specifications and designs developed by
|
||||
% Cynthia Brewer (http://colorbrewer.org/). For more information on
|
||||
% ColorBrewer, please visit http://colorbrewer.org/.
|
||||
%
|
||||
% CBREWER2 uses a cached copy of the Cynthia Brewer color schemes which
|
||||
% was converted to .mat format by Charles Robert for use with CBREWER.
|
||||
% CBREWER is available from the MATLAB FileExchange under the MIT license.
|
||||
%
|
||||
% See also CBREWER, BREWERMAP, COLORSPACE, INTERP1.
|
||||
|
||||
|
||||
% Copyright (c) 2016 Scott Lowe
|
||||
%
|
||||
% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
% you may not use this file except in compliance with the License.
|
||||
% You may obtain a copy of the License at
|
||||
%
|
||||
% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%
|
||||
% Unless required by applicable law or agreed to in writing, software
|
||||
% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
% See the License for the specific language governing permissions and
|
||||
% limitations under the License.
|
||||
|
||||
|
||||
function colormap = cbrewer2(...
|
||||
cname, ncol, interp_method, interp_space, varargin)
|
||||
|
||||
% Definitions -------------------------------------------------------------
|
||||
|
||||
% List of all of Cynthia Brewer's colormaps and their types
|
||||
% seq: sequential
|
||||
% div: divergent
|
||||
% qual: qualitative
|
||||
cbdict = {...
|
||||
'Blues', 'seq'; ...
|
||||
'BuGn', 'seq'; ...
|
||||
'BuPu', 'seq'; ...
|
||||
'GnBu', 'seq'; ...
|
||||
'Greens', 'seq'; ...
|
||||
'Greys', 'seq'; ...
|
||||
'Oranges', 'seq'; ...
|
||||
'OrRd', 'seq'; ...
|
||||
'PuBu', 'seq'; ...
|
||||
'PuBuGn', 'seq'; ...
|
||||
'PuRd', 'seq'; ...
|
||||
'Purples', 'seq'; ...
|
||||
'RdPu', 'seq'; ...
|
||||
'Reds', 'seq'; ...
|
||||
'YlGn', 'seq'; ...
|
||||
'YlGnBu', 'seq'; ...
|
||||
'YlOrBr', 'seq'; ...
|
||||
'YlOrRd', 'seq'; ...
|
||||
'BrBG', 'div'; ...
|
||||
'PiYG', 'div'; ...
|
||||
'PRGn', 'div'; ...
|
||||
'PuOr', 'div'; ...
|
||||
'RdBu', 'div'; ...
|
||||
'RdGy', 'div'; ...
|
||||
'RdYlBu', 'div'; ...
|
||||
'RdYlGn', 'div'; ...
|
||||
'Spectral', 'div'; ...
|
||||
'Accent', 'qual'; ...
|
||||
'Dark2', 'qual'; ...
|
||||
'Paired', 'qual'; ...
|
||||
'Pastel1', 'qual'; ...
|
||||
'Pastel2', 'qual'; ...
|
||||
'Set1', 'qual'; ...
|
||||
'Set2', 'qual'; ...
|
||||
'Set3', 'qual'; ...
|
||||
};
|
||||
|
||||
|
||||
% Input handling ----------------------------------------------------------
|
||||
|
||||
narginchk(1, 5);
|
||||
|
||||
% Initialise variables if not supplied
|
||||
if nargin<2
|
||||
ncol = [];
|
||||
end
|
||||
if nargin<3
|
||||
interp_method = [];
|
||||
end
|
||||
if nargin<4
|
||||
interp_space = [];
|
||||
end
|
||||
if nargin<5
|
||||
varargin = {[]};
|
||||
end
|
||||
|
||||
% Check if the colormap type was unnecessarily input
|
||||
types = unique(cbdict(:, 2));
|
||||
if nargin > 1 && ischar(cname) && ischar(ncol)
|
||||
LI = ismember({cname ncol}, types);
|
||||
if ~any(LI); error('Number of colors cannot be a string'); end;
|
||||
if all(LI); error('Incorrect colormap name'); end;
|
||||
if LI(1)
|
||||
vgn = {cname; ncol; interp_method; interp_space};
|
||||
cname = vgn{2};
|
||||
ncol = vgn{3};
|
||||
interp_method = vgn{4};
|
||||
interp_space = varargin{1};
|
||||
ctype_input = vgn{1};
|
||||
elseif LI(2)
|
||||
vgn = {cname; ncol; interp_method; interp_space};
|
||||
cname = vgn{1};
|
||||
ncol = vgn{3};
|
||||
interp_method = vgn{4};
|
||||
interp_space = varargin{1};
|
||||
ctype_input = vgn{2};
|
||||
end
|
||||
else
|
||||
ctype_input = '';
|
||||
end
|
||||
|
||||
% Default values
|
||||
if isempty(ncol)
|
||||
% Number of colours in the colormap
|
||||
ncol = size(get(gcf,'colormap'), 1);
|
||||
end
|
||||
if isempty(interp_method)
|
||||
interp_method = 'pchip';
|
||||
end
|
||||
if isempty(interp_space)
|
||||
interp_space = 'lab';
|
||||
end
|
||||
|
||||
|
||||
% Load colorbrewer data ---------------------------------------------------
|
||||
Tmp = load('colorbrewer.mat');
|
||||
colorbrewer = Tmp.colorbrewer;
|
||||
|
||||
[TF, idict] = ismember(lower(cname), lower(cbdict(:, 1)));
|
||||
|
||||
if ~TF
|
||||
error('%s is not a recognised Brewer colormap',cname);
|
||||
end
|
||||
|
||||
cname = cbdict{idict, 1};
|
||||
ctype = cbdict{idict, 2};
|
||||
|
||||
if (~isfield(colorbrewer.(ctype), cname))
|
||||
error('Colormap %s is not present in loaded data',cname);
|
||||
end
|
||||
|
||||
|
||||
% Main script -------------------------------------------------------------
|
||||
|
||||
if ncol > length(colorbrewer.(ctype).(cname))
|
||||
% If we specified too many colours, we take the maximum and interpolate
|
||||
colormap = colorbrewer.(ctype).(cname){length(colorbrewer.(ctype).(cname))};
|
||||
colormap = colormap ./ 255;
|
||||
elseif isempty(colorbrewer.(ctype).(cname){ncol})
|
||||
% If we specified too few colours, we take the minimum and interpolate
|
||||
nmin = find(~cellfun(@isempty, colorbrewer.(ctype).(cname)), 1);
|
||||
colormap = colorbrewer.(ctype).(cname){nmin};
|
||||
colormap = colormap./255;
|
||||
else
|
||||
% If we specified a number of colours in the pre-designed range, no
|
||||
% need to interpolate
|
||||
colormap = (colorbrewer.(ctype).(cname){ncol}) ./ 255;
|
||||
return;
|
||||
end
|
||||
|
||||
% Don't interpolate if qualitative type
|
||||
if strcmp(ctype,'qual')
|
||||
if size(colormap, 1) >= ncol
|
||||
colormap = colormap(1:ncol, :);
|
||||
return;
|
||||
end
|
||||
warning('CBREWER2:QualTooManyColors', ...
|
||||
['Too many colors requested: cannot interpolate a qualitative' ...
|
||||
' colorscheme']);
|
||||
% Cycle the colours from the beginning again, so we have enough to
|
||||
% return
|
||||
colormap = repmat(colormap, ceil(ncol / size(colormap, 1)), 1);
|
||||
colormap = colormap(1:ncol, :);
|
||||
return;
|
||||
end
|
||||
|
||||
% Make sure we have colorspace downloaded from the FEX
|
||||
if ~strcmpi(interp_space, 'rgb') && ~exist('colorspace.m', 'file')
|
||||
P = requireFEXpackage(28790);
|
||||
if isempty(P);
|
||||
error(...
|
||||
['You need to download COLORSPACE from the MATLAB FEX and' ...
|
||||
' add it to the MATLAB path.']);
|
||||
end;
|
||||
end
|
||||
|
||||
% Move to perceptually uniform space
|
||||
if ~strcmpi(interp_space,'rgb')
|
||||
colormap = colorspace(['rgb->' interp_space], colormap);
|
||||
end
|
||||
|
||||
% Linearly interpolate
|
||||
X = linspace(0, 1, size(colormap, 1));
|
||||
XI = linspace(0, 1, ncol);
|
||||
colormap = interp1(X, colormap, XI, interp_method);
|
||||
|
||||
% Move from perceptually uniform space back to sRGB
|
||||
if ~strcmpi(interp_space,'rgb')
|
||||
colormap = colorspace(['rgb<-' interp_space], colormap);
|
||||
end
|
||||
|
||||
end
|
||||
BIN
Functions/helper_functions_community/cbrewer2/colorbrewer.mat
Normal file
@@ -0,0 +1,194 @@
|
||||
function AddedPath = requireFEXpackage(FEXSubmissionID)
|
||||
%Function requireFEXpackage -
|
||||
%installs Matlab Central File Exchange (FEX) submission
|
||||
%with given ID into the directory chosen by the user.
|
||||
%A new FEX submissions may use previous FEX submissions as its part.
|
||||
%The function 'requireFEXpackage' helps in adding those previous
|
||||
%submissions to the user's MATLAB installation.
|
||||
%
|
||||
%This function is a part of File Exchange submission 31069.
|
||||
%Download the entire submission:
|
||||
%http://www.mathworks.com/matlabcentral/fileexchange/31069
|
||||
%
|
||||
% SYNTAX:
|
||||
% AddedPath = requireFEXpackage(FEXSubmissionID)
|
||||
%
|
||||
% INPUT:
|
||||
% ID of the required submission to File Exchange
|
||||
%
|
||||
% OUTPUT:
|
||||
% the path to that submission added to the user's MATLAB path.
|
||||
%
|
||||
% HOW TO CALL:
|
||||
% The command
|
||||
% P = requireFEXpackage(8277)
|
||||
% will download and install the package with ID 8277
|
||||
% (namely, nice 'fminsearchbnd' by John D'Errico)
|
||||
%
|
||||
% EXAMPLES -- HOW TO USE:
|
||||
%
|
||||
% EXAMPLE 1 (using 'exist' command):
|
||||
%
|
||||
% % first, somewhere in the very beginning of your code,
|
||||
% % check if the function 'fminsearchbnd' from the FEX package 8277
|
||||
% % is on your MATLAB path, and if it is not there,
|
||||
% % require the FEX package 8277:
|
||||
% if ~(exist('fminsearchbnd', 'file') == 2)
|
||||
% P = requireFEXpackage(8277); % fminsearchbnd is part of 8277
|
||||
% end
|
||||
%
|
||||
% % Then just use 'fminsearchbnd' where you need it:
|
||||
% syms x
|
||||
% RosenbrockBananaFunction = @(x) (1-x(1)).^2 + 100*(x(2)-x(1).^2).^2;
|
||||
% x = fminsearchbnd(RosenbrockBananaFunction,[3 3])
|
||||
|
||||
% EXAMPLE 2 (using 'try-catch' command):
|
||||
%
|
||||
% syms x
|
||||
% RosenbrockBananaFunction = @(x) (1-x(1)).^2+100*(x(2)-x(1).^2).^2;
|
||||
% try
|
||||
% % if function 'fminsearchbnd' already exists in your MATLAB
|
||||
% % installation, just use it:
|
||||
% x = fminsearchbnd(RosenbrockBananaFunction,[3 3])
|
||||
% catch
|
||||
% % if function 'fminsearchbnd' is not present in your MATLAB
|
||||
% % installation, first get the package 8277 (to which it belongs)
|
||||
% % from the MATLAB Central File Exchange (FEX)
|
||||
% P = requireFEXpackage(8277); % fminsearchbnd is part of 8277
|
||||
% % and then use that function:
|
||||
% x = fminsearchbnd(RosenbrockBananaFunction,[3 3])
|
||||
% end
|
||||
%
|
||||
%
|
||||
% NOTE: on Mac platform, the title of the dialog box for
|
||||
% choosing the directory for installing the required FEX package
|
||||
% is not shown; this is not a bug, this is how UIGETDIR works on Macs --
|
||||
% see the documentation for UIGETDIR
|
||||
% http://www.mathworks.com/help/techdoc/ref/uigetdir.html
|
||||
%
|
||||
% (C) Igor Podlubny, 2011
|
||||
|
||||
% Copyright (c) 2011, Igor Podlubny
|
||||
% All rights reserved.
|
||||
%
|
||||
% Redistribution and use in source and binary forms, with or without
|
||||
% modification, are permitted provided that the following conditions are
|
||||
% met:
|
||||
%
|
||||
% * Redistributions of source code must retain the above copyright
|
||||
% notice, this list of conditions and the following disclaimer.
|
||||
% * Redistributions in binary form must reproduce the above copyright
|
||||
% notice, this list of conditions and the following disclaimer in
|
||||
% the documentation and/or other materials provided with the distribution
|
||||
%
|
||||
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
% POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
ID = num2str(FEXSubmissionID);
|
||||
|
||||
% Ask user for the confirmation of the installation
|
||||
% of the required FEX package
|
||||
yes = ['YES, Install package ' ID];
|
||||
no = 'NO, do not install';
|
||||
userchoice = questdlg(['The Matlab function/toolbox, which you are running, ' ...
|
||||
'requires the presence of the package ' ID ...
|
||||
' from Matlab Central File Exchange.' ...
|
||||
sprintf('\n\n') ...
|
||||
'Would you like to install the FEX package ' ID ' now?'] , ...
|
||||
['Required package ' ID], ...
|
||||
yes, no, yes);
|
||||
|
||||
% Handle response
|
||||
switch userchoice
|
||||
case yes,
|
||||
install = 1;
|
||||
case no,
|
||||
install = 0;
|
||||
otherwise,
|
||||
install = 0;
|
||||
end
|
||||
|
||||
|
||||
if install == 1
|
||||
baseURL = 'http://www.mathworks.com/matlabcentral/fileexchange/';
|
||||
query = '?download=true';
|
||||
|
||||
location = uigetdir(pwd, ['Select the directory for installing the required FEX package' ID ]);
|
||||
if location ~= 0
|
||||
% download package 'ID' from Matlab Central File Exchange
|
||||
filetosave = [location filesep ID '.zip'];
|
||||
FEXpackage = [baseURL ID query];
|
||||
[f,status] = urlwrite(FEXpackage,filetosave);
|
||||
if status==0
|
||||
warndlg(['No connection to Matlab Central File Exchange,' ' or package ' ID ' does not exist.' ...
|
||||
' Package ' ID ' has not been installed. ' ...
|
||||
' Check you internet settings and the ID of the required package, and try again. '] , ...
|
||||
['No connection to Matlab Central File Exchange' ' or package ' ID ' does not exist'], ...
|
||||
'modal');
|
||||
AddedPath = '';
|
||||
return
|
||||
end
|
||||
% unzip the downloaded file to the subdirectory 'ID'
|
||||
todir = [location filesep ID];
|
||||
% if the directory 'ID' doesn't exist at given location, create it
|
||||
if ~(exist([location filesep ID], 'dir') == 7)
|
||||
mkdir(location, ID);
|
||||
end
|
||||
try
|
||||
unzip(filetosave, todir);
|
||||
% after unzipping, delete the downloaded ZIP file
|
||||
delete(filetosave);
|
||||
% prepend the paths to the downloaded package to the MATLAB path
|
||||
P = genpath([location filesep ID]);
|
||||
path(P,path);
|
||||
catch
|
||||
% if the FEX package is not ZIP, then it is a single m-file
|
||||
% just move the file to the ID directory
|
||||
[pathstr, name, ext] = fileparts(filetosave);
|
||||
movefile(filetosave, [todir filesep name '.m']);
|
||||
P = genpath([location filesep ID]);
|
||||
path(P,path);
|
||||
end
|
||||
else
|
||||
P = '';
|
||||
end
|
||||
|
||||
AddedPath = P;
|
||||
else
|
||||
AddedPath = '';
|
||||
end
|
||||
|
||||
|
||||
if install == 1,
|
||||
% Ask user about reviewing and saving the modified MATLAB path,
|
||||
% and take him to PATHTOOL, if the user wants to save the modified path
|
||||
yes = 'YES, I want to review and save the MATLAB path';
|
||||
no = 'NO, I don''t want to save the path permanently';
|
||||
userchoice = questdlg(['After adding the package ' ID ...
|
||||
' from Matlab Central File Exchange to your MATLAB installation,' ...
|
||||
' the MATLAB path has been modified accordingly. ', ...
|
||||
'Would you like to review and save the modified MATLAB path?'] , ...
|
||||
'Review and save the modified MATLAB path for future use?', ...
|
||||
yes, no, yes);
|
||||
|
||||
% Handle response
|
||||
switch userchoice
|
||||
case yes,
|
||||
pathtool;
|
||||
case no,
|
||||
otherwise,
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
1285
Functions/helper_functions_community/colorspace/colorspace.c
Normal file
72
Functions/helper_functions_community/colorspace/colorspace.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @file colorspace.h
|
||||
* @author Pascal Getreuer 2005-2010 <getreuer@gmail.com>
|
||||
*/
|
||||
#ifndef _COLORSPACE_H_
|
||||
#define _COLORSPACE_H_
|
||||
|
||||
/** @brief Datatype to use for representing real numbers
|
||||
* Set this typedef to either double or float depending on the application.
|
||||
*/
|
||||
typedef double num;
|
||||
|
||||
|
||||
/** @brief XYZ color of the D65 white point */
|
||||
#define WHITEPOINT_X 0.950456
|
||||
#define WHITEPOINT_Y 1.0
|
||||
#define WHITEPOINT_Z 1.088754
|
||||
|
||||
|
||||
|
||||
/** @brief struct for representing a color transform */
|
||||
typedef struct
|
||||
{
|
||||
int NumStages;
|
||||
void (*Fun[2])(num*, num*, num*, num, num, num);
|
||||
} colortransform;
|
||||
|
||||
int GetColorTransform(colortransform *Trans, const char *TransformString);
|
||||
void ApplyColorTransform(colortransform Trans,
|
||||
num *D0, num *D1, num *D2, num S0, num S1, num S2);
|
||||
|
||||
void Rgb2Yuv(num *Y, num *U, num *V, num R, num G, num B);
|
||||
void Yuv2Rgb(num *R, num *G, num *B, num Y, num U, num V);
|
||||
void Rgb2Ycbcr(num *Y, num *Cb, num *Cr, num R, num G, num B);
|
||||
void Ycbcr2Rgb(num *R, num *G, num *B, num Y, num Cb, num Cr);
|
||||
void Rgb2Jpegycbcr(num *R, num *G, num *B, num Y, num Cb, num Cr);
|
||||
void Jpegycbcr2Rgb(num *R, num *G, num *B, num Y, num Cb, num Cr);
|
||||
void Rgb2Ypbpr(num *Y, num *Pb, num *Pr, num R, num G, num B);
|
||||
void Ypbpr2Rgb(num *R, num *G, num *B, num Y, num Pb, num Pr);
|
||||
void Rgb2Ydbdr(num *Y, num *Db, num *Dr, num R, num G, num B);
|
||||
void Ydbdr2Rgb(num *R, num *G, num *B, num Y, num Db, num Dr);
|
||||
void Rgb2Yiq(num *Y, num *I, num *Q, num R, num G, num B);
|
||||
void Yiq2Rgb(num *R, num *G, num *B, num Y, num I, num Q);
|
||||
|
||||
void Rgb2Hsv(num *H, num *S, num *V, num R, num G, num B);
|
||||
void Hsv2Rgb(num *R, num *G, num *B, num H, num S, num V);
|
||||
void Rgb2Hsl(num *H, num *S, num *L, num R, num G, num B);
|
||||
void Hsl2Rgb(num *R, num *G, num *B, num H, num S, num L);
|
||||
void Rgb2Hsi(num *H, num *S, num *I, num R, num G, num B);
|
||||
void Hsi2Rgb(num *R, num *G, num *B, num H, num S, num I);
|
||||
|
||||
void Rgb2Xyz(num *X, num *Y, num *Z, num R, num G, num B);
|
||||
void Xyz2Rgb(num *R, num *G, num *B, num X, num Y, num Z);
|
||||
void Xyz2Lab(num *L, num *a, num *b, num X, num Y, num Z);
|
||||
void Lab2Xyz(num *X, num *Y, num *Z, num L, num a, num b);
|
||||
void Xyz2Luv(num *L, num *u, num *v, num X, num Y, num Z);
|
||||
void Luv2Xyz(num *X, num *Y, num *Z, num L, num u, num v);
|
||||
void Xyz2Lch(num *L, num *C, num *H, num X, num Y, num Z);
|
||||
void Lch2Xyz(num *X, num *Y, num *Z, num L, num C, num H);
|
||||
void Xyz2Cat02lms(num *L, num *M, num *S, num X, num Y, num Z);
|
||||
void Cat02lms2Xyz(num *X, num *Y, num *Z, num L, num M, num S);
|
||||
|
||||
void Rgb2Lab(num *L, num *a, num *b, num R, num G, num B);
|
||||
void Lab2Rgb(num *R, num *G, num *B, num L, num a, num b);
|
||||
void Rgb2Luv(num *L, num *u, num *v, num R, num G, num B);
|
||||
void Luv2Rgb(num *R, num *G, num *B, num L, num u, num v);
|
||||
void Rgb2Lch(num *L, num *C, num *H, num R, num G, num B);
|
||||
void Lch2Rgb(num *R, num *G, num *B, num L, num C, num H);
|
||||
void Rgb2Cat02lms(num *L, num *M, num *S, num R, num G, num B);
|
||||
void Cat02lms2Rgb(num *R, num *G, num *B, num L, num M, num S);
|
||||
|
||||
#endif /* _COLORSPACE_H_ */
|
||||
493
Functions/helper_functions_community/colorspace/colorspace.m
Normal file
@@ -0,0 +1,493 @@
|
||||
function varargout = colorspace(Conversion,varargin)
|
||||
%COLORSPACE Transform a color image between color representations.
|
||||
% B = COLORSPACE(S,A) transforms the color representation of image A
|
||||
% where S is a string specifying the conversion. The input array A
|
||||
% should be a real full double array of size Mx3 or MxNx3. The output B
|
||||
% is the same size as A.
|
||||
%
|
||||
% S tells the source and destination color spaces, S = 'dest<-src', or
|
||||
% alternatively, S = 'src->dest'. Supported color spaces are
|
||||
%
|
||||
% 'RGB' sRGB IEC 61966-2-1
|
||||
% 'YCbCr' Luma + Chroma ("digitized" version of Y'PbPr)
|
||||
% 'JPEG-YCbCr' Luma + Chroma space used in JFIF JPEG
|
||||
% 'YDbDr' SECAM Y'DbDr Luma + Chroma
|
||||
% 'YPbPr' Luma (ITU-R BT.601) + Chroma
|
||||
% 'YUV' NTSC PAL Y'UV Luma + Chroma
|
||||
% 'YIQ' NTSC Y'IQ Luma + Chroma
|
||||
% 'HSV' or 'HSB' Hue Saturation Value/Brightness
|
||||
% 'HSL' or 'HLS' Hue Saturation Luminance
|
||||
% 'HSI' Hue Saturation Intensity
|
||||
% 'XYZ' CIE 1931 XYZ
|
||||
% 'Lab' CIE 1976 L*a*b* (CIELAB)
|
||||
% 'Luv' CIE L*u*v* (CIELUV)
|
||||
% 'LCH' CIE L*C*H* (CIELCH)
|
||||
% 'CAT02 LMS' CIE CAT02 LMS
|
||||
%
|
||||
% All conversions assume 2 degree observer and D65 illuminant.
|
||||
%
|
||||
% Color space names are case insensitive and spaces are ignored. When
|
||||
% sRGB is the source or destination, it can be omitted. For example
|
||||
% 'yuv<-' is short for 'yuv<-rgb'.
|
||||
%
|
||||
% For sRGB, the values should be scaled between 0 and 1. Beware that
|
||||
% transformations generally do not constrain colors to be "in gamut."
|
||||
% Particularly, transforming from another space to sRGB may obtain
|
||||
% R'G'B' values outside of the [0,1] range. So the result should be
|
||||
% clamped to [0,1] before displaying:
|
||||
% image(min(max(B,0),1)); % Clamp B to [0,1] and display
|
||||
%
|
||||
% sRGB (Red Green Blue) is the (ITU-R BT.709 gamma-corrected) standard
|
||||
% red-green-blue representation of colors used in digital imaging. The
|
||||
% components should be scaled between 0 and 1. The space can be
|
||||
% visualized geometrically as a cube.
|
||||
%
|
||||
% Y'PbPr, Y'CbCr, Y'DbDr, Y'UV, and Y'IQ are related to sRGB by linear
|
||||
% transformations. These spaces separate a color into a grayscale
|
||||
% luminance component Y and two chroma components. The valid ranges of
|
||||
% the components depends on the space.
|
||||
%
|
||||
% HSV (Hue Saturation Value) is related to sRGB by
|
||||
% H = hexagonal hue angle (0 <= H < 360),
|
||||
% S = C/V (0 <= S <= 1),
|
||||
% V = max(R',G',B') (0 <= V <= 1),
|
||||
% where C = max(R',G',B') - min(R',G',B'). The hue angle H is computed on
|
||||
% a hexagon. The space is geometrically a hexagonal cone.
|
||||
%
|
||||
% HSL (Hue Saturation Lightness) is related to sRGB by
|
||||
% H = hexagonal hue angle (0 <= H < 360),
|
||||
% S = C/(1 - |2L-1|) (0 <= S <= 1),
|
||||
% L = (max(R',G',B') + min(R',G',B'))/2 (0 <= L <= 1),
|
||||
% where H and C are the same as in HSV. Geometrically, the space is a
|
||||
% double hexagonal cone.
|
||||
%
|
||||
% HSI (Hue Saturation Intensity) is related to sRGB by
|
||||
% H = polar hue angle (0 <= H < 360),
|
||||
% S = 1 - min(R',G',B')/I (0 <= S <= 1),
|
||||
% I = (R'+G'+B')/3 (0 <= I <= 1).
|
||||
% Unlike HSV and HSL, the hue angle H is computed on a circle rather than
|
||||
% a hexagon.
|
||||
%
|
||||
% CIE XYZ is related to sRGB by inverse gamma correction followed by a
|
||||
% linear transform. Other CIE color spaces are defined relative to XYZ.
|
||||
%
|
||||
% CIE L*a*b*, L*u*v*, and L*C*H* are nonlinear functions of XYZ. The L*
|
||||
% component is designed to match closely with human perception of
|
||||
% lightness. The other two components describe the chroma.
|
||||
%
|
||||
% CIE CAT02 LMS is the linear transformation of XYZ using the MCAT02
|
||||
% chromatic adaptation matrix. The space is designed to model the
|
||||
% response of the three types of cones in the human eye, where L, M, S,
|
||||
% correspond respectively to red ("long"), green ("medium"), and blue
|
||||
% ("short").
|
||||
|
||||
% Pascal Getreuer 2005-2010
|
||||
|
||||
|
||||
%%% Input parsing %%%
|
||||
if nargin < 2, error('Not enough input arguments.'); end
|
||||
[SrcSpace,DestSpace] = parse(Conversion);
|
||||
|
||||
if nargin == 2
|
||||
Image = varargin{1};
|
||||
elseif nargin >= 3
|
||||
Image = cat(3,varargin{:});
|
||||
else
|
||||
error('Invalid number of input arguments.');
|
||||
end
|
||||
|
||||
FlipDims = (size(Image,3) == 1);
|
||||
|
||||
if FlipDims, Image = permute(Image,[1,3,2]); end
|
||||
if ~isa(Image,'double'), Image = double(Image)/255; end
|
||||
if size(Image,3) ~= 3, error('Invalid input size.'); end
|
||||
|
||||
SrcT = gettransform(SrcSpace);
|
||||
DestT = gettransform(DestSpace);
|
||||
|
||||
if ~ischar(SrcT) && ~ischar(DestT)
|
||||
% Both source and destination transforms are affine, so they
|
||||
% can be composed into one affine operation
|
||||
T = [DestT(:,1:3)*SrcT(:,1:3),DestT(:,1:3)*SrcT(:,4)+DestT(:,4)];
|
||||
Temp = zeros(size(Image));
|
||||
Temp(:,:,1) = T(1)*Image(:,:,1) + T(4)*Image(:,:,2) + T(7)*Image(:,:,3) + T(10);
|
||||
Temp(:,:,2) = T(2)*Image(:,:,1) + T(5)*Image(:,:,2) + T(8)*Image(:,:,3) + T(11);
|
||||
Temp(:,:,3) = T(3)*Image(:,:,1) + T(6)*Image(:,:,2) + T(9)*Image(:,:,3) + T(12);
|
||||
Image = Temp;
|
||||
elseif ~ischar(DestT)
|
||||
Image = rgb(Image,SrcSpace);
|
||||
Temp = zeros(size(Image));
|
||||
Temp(:,:,1) = DestT(1)*Image(:,:,1) + DestT(4)*Image(:,:,2) + DestT(7)*Image(:,:,3) + DestT(10);
|
||||
Temp(:,:,2) = DestT(2)*Image(:,:,1) + DestT(5)*Image(:,:,2) + DestT(8)*Image(:,:,3) + DestT(11);
|
||||
Temp(:,:,3) = DestT(3)*Image(:,:,1) + DestT(6)*Image(:,:,2) + DestT(9)*Image(:,:,3) + DestT(12);
|
||||
Image = Temp;
|
||||
else
|
||||
Image = feval(DestT,Image,SrcSpace);
|
||||
end
|
||||
|
||||
%%% Output format %%%
|
||||
if nargout > 1
|
||||
varargout = {Image(:,:,1),Image(:,:,2),Image(:,:,3)};
|
||||
else
|
||||
if FlipDims, Image = permute(Image,[1,3,2]); end
|
||||
varargout = {Image};
|
||||
end
|
||||
|
||||
return;
|
||||
|
||||
|
||||
function [SrcSpace,DestSpace] = parse(Str)
|
||||
% Parse conversion argument
|
||||
|
||||
if ischar(Str)
|
||||
Str = lower(strrep(strrep(Str,'-',''),'=',''));
|
||||
k = find(Str == '>');
|
||||
|
||||
if length(k) == 1 % Interpret the form 'src->dest'
|
||||
SrcSpace = Str(1:k-1);
|
||||
DestSpace = Str(k+1:end);
|
||||
else
|
||||
k = find(Str == '<');
|
||||
|
||||
if length(k) == 1 % Interpret the form 'dest<-src'
|
||||
DestSpace = Str(1:k-1);
|
||||
SrcSpace = Str(k+1:end);
|
||||
else
|
||||
error(['Invalid conversion, ''',Str,'''.']);
|
||||
end
|
||||
end
|
||||
|
||||
SrcSpace = alias(SrcSpace);
|
||||
DestSpace = alias(DestSpace);
|
||||
else
|
||||
SrcSpace = 1; % No source pre-transform
|
||||
DestSpace = Conversion;
|
||||
if any(size(Conversion) ~= 3), error('Transformation matrix must be 3x3.'); end
|
||||
end
|
||||
return;
|
||||
|
||||
|
||||
function Space = alias(Space)
|
||||
Space = strrep(strrep(Space,'cie',''),' ','');
|
||||
|
||||
if isempty(Space)
|
||||
Space = 'rgb';
|
||||
end
|
||||
|
||||
switch Space
|
||||
case {'ycbcr','ycc'}
|
||||
Space = 'ycbcr';
|
||||
case {'hsv','hsb'}
|
||||
Space = 'hsv';
|
||||
case {'hsl','hsi','hls'}
|
||||
Space = 'hsl';
|
||||
case {'rgb','yuv','yiq','ydbdr','ycbcr','jpegycbcr','xyz','lab','luv','lch'}
|
||||
return;
|
||||
end
|
||||
return;
|
||||
|
||||
|
||||
function T = gettransform(Space)
|
||||
% Get a colorspace transform: either a matrix describing an affine transform,
|
||||
% or a string referring to a conversion subroutine
|
||||
switch Space
|
||||
case 'ypbpr'
|
||||
T = [0.299,0.587,0.114,0;-0.1687367,-0.331264,0.5,0;0.5,-0.418688,-0.081312,0];
|
||||
case 'yuv'
|
||||
% sRGB to NTSC/PAL YUV
|
||||
% Wikipedia: http://en.wikipedia.org/wiki/YUV
|
||||
T = [0.299,0.587,0.114,0;-0.147,-0.289,0.436,0;0.615,-0.515,-0.100,0];
|
||||
case 'ydbdr'
|
||||
% sRGB to SECAM YDbDr
|
||||
% Wikipedia: http://en.wikipedia.org/wiki/YDbDr
|
||||
T = [0.299,0.587,0.114,0;-0.450,-0.883,1.333,0;-1.333,1.116,0.217,0];
|
||||
case 'yiq'
|
||||
% sRGB in [0,1] to NTSC YIQ in [0,1];[-0.595716,0.595716];[-0.522591,0.522591];
|
||||
% Wikipedia: http://en.wikipedia.org/wiki/YIQ
|
||||
T = [0.299,0.587,0.114,0;0.595716,-0.274453,-0.321263,0;0.211456,-0.522591,0.311135,0];
|
||||
case 'ycbcr'
|
||||
% sRGB (range [0,1]) to ITU-R BRT.601 (CCIR 601) Y'CbCr
|
||||
% Wikipedia: http://en.wikipedia.org/wiki/YCbCr
|
||||
% Poynton, Equation 3, scaling of R'G'B to Y'PbPr conversion
|
||||
T = [65.481,128.553,24.966,16;-37.797,-74.203,112.0,128;112.0,-93.786,-18.214,128];
|
||||
case 'jpegycbcr'
|
||||
% Wikipedia: http://en.wikipedia.org/wiki/YCbCr
|
||||
T = [0.299,0.587,0.114,0;-0.168736,-0.331264,0.5,0.5;0.5,-0.418688,-0.081312,0.5]*255;
|
||||
case {'rgb','xyz','hsv','hsl','lab','luv','lch','cat02lms'}
|
||||
T = Space;
|
||||
otherwise
|
||||
error(['Unknown color space, ''',Space,'''.']);
|
||||
end
|
||||
return;
|
||||
|
||||
|
||||
function Image = rgb(Image,SrcSpace)
|
||||
% Convert to sRGB from 'SrcSpace'
|
||||
switch SrcSpace
|
||||
case 'rgb'
|
||||
return;
|
||||
case 'hsv'
|
||||
% Convert HSV to sRGB
|
||||
Image = huetorgb((1 - Image(:,:,2)).*Image(:,:,3),Image(:,:,3),Image(:,:,1));
|
||||
case 'hsl'
|
||||
% Convert HSL to sRGB
|
||||
L = Image(:,:,3);
|
||||
Delta = Image(:,:,2).*min(L,1-L);
|
||||
Image = huetorgb(L-Delta,L+Delta,Image(:,:,1));
|
||||
case {'xyz','lab','luv','lch','cat02lms'}
|
||||
% Convert to CIE XYZ
|
||||
Image = xyz(Image,SrcSpace);
|
||||
% Convert XYZ to RGB
|
||||
T = [3.2406, -1.5372, -0.4986; -0.9689, 1.8758, 0.0415; 0.0557, -0.2040, 1.057];
|
||||
R = T(1)*Image(:,:,1) + T(4)*Image(:,:,2) + T(7)*Image(:,:,3); % R
|
||||
G = T(2)*Image(:,:,1) + T(5)*Image(:,:,2) + T(8)*Image(:,:,3); % G
|
||||
B = T(3)*Image(:,:,1) + T(6)*Image(:,:,2) + T(9)*Image(:,:,3); % B
|
||||
% Desaturate and rescale to constrain resulting RGB values to [0,1]
|
||||
AddWhite = -min(min(min(R,G),B),0);
|
||||
R = R + AddWhite;
|
||||
G = G + AddWhite;
|
||||
B = B + AddWhite;
|
||||
% Apply gamma correction to convert linear RGB to sRGB
|
||||
Image(:,:,1) = gammacorrection(R); % R'
|
||||
Image(:,:,2) = gammacorrection(G); % G'
|
||||
Image(:,:,3) = gammacorrection(B); % B'
|
||||
otherwise % Conversion is through an affine transform
|
||||
T = gettransform(SrcSpace);
|
||||
temp = inv(T(:,1:3));
|
||||
T = [temp,-temp*T(:,4)];
|
||||
R = T(1)*Image(:,:,1) + T(4)*Image(:,:,2) + T(7)*Image(:,:,3) + T(10);
|
||||
G = T(2)*Image(:,:,1) + T(5)*Image(:,:,2) + T(8)*Image(:,:,3) + T(11);
|
||||
B = T(3)*Image(:,:,1) + T(6)*Image(:,:,2) + T(9)*Image(:,:,3) + T(12);
|
||||
Image(:,:,1) = R;
|
||||
Image(:,:,2) = G;
|
||||
Image(:,:,3) = B;
|
||||
end
|
||||
|
||||
% Clip to [0,1]
|
||||
Image = min(max(Image,0),1);
|
||||
return;
|
||||
|
||||
|
||||
function Image = xyz(Image,SrcSpace)
|
||||
% Convert to CIE XYZ from 'SrcSpace'
|
||||
WhitePoint = [0.950456,1,1.088754];
|
||||
|
||||
switch SrcSpace
|
||||
case 'xyz'
|
||||
return;
|
||||
case 'luv'
|
||||
% Convert CIE L*uv to XYZ
|
||||
WhitePointU = (4*WhitePoint(1))./(WhitePoint(1) + 15*WhitePoint(2) + 3*WhitePoint(3));
|
||||
WhitePointV = (9*WhitePoint(2))./(WhitePoint(1) + 15*WhitePoint(2) + 3*WhitePoint(3));
|
||||
L = Image(:,:,1);
|
||||
Y = (L + 16)/116;
|
||||
Y = invf(Y)*WhitePoint(2);
|
||||
U = Image(:,:,2)./(13*L + 1e-6*(L==0)) + WhitePointU;
|
||||
V = Image(:,:,3)./(13*L + 1e-6*(L==0)) + WhitePointV;
|
||||
Image(:,:,1) = -(9*Y.*U)./((U-4).*V - U.*V); % X
|
||||
Image(:,:,2) = Y; % Y
|
||||
Image(:,:,3) = (9*Y - (15*V.*Y) - (V.*Image(:,:,1)))./(3*V); % Z
|
||||
case {'lab','lch'}
|
||||
Image = lab(Image,SrcSpace);
|
||||
% Convert CIE L*ab to XYZ
|
||||
fY = (Image(:,:,1) + 16)/116;
|
||||
fX = fY + Image(:,:,2)/500;
|
||||
fZ = fY - Image(:,:,3)/200;
|
||||
Image(:,:,1) = WhitePoint(1)*invf(fX); % X
|
||||
Image(:,:,2) = WhitePoint(2)*invf(fY); % Y
|
||||
Image(:,:,3) = WhitePoint(3)*invf(fZ); % Z
|
||||
case 'cat02lms'
|
||||
% Convert CAT02 LMS to XYZ
|
||||
T = inv([0.7328, 0.4296, -0.1624;-0.7036, 1.6975, 0.0061; 0.0030, 0.0136, 0.9834]);
|
||||
L = Image(:,:,1);
|
||||
M = Image(:,:,2);
|
||||
S = Image(:,:,3);
|
||||
Image(:,:,1) = T(1)*L + T(4)*M + T(7)*S; % X
|
||||
Image(:,:,2) = T(2)*L + T(5)*M + T(8)*S; % Y
|
||||
Image(:,:,3) = T(3)*L + T(6)*M + T(9)*S; % Z
|
||||
otherwise % Convert from some gamma-corrected space
|
||||
% Convert to sRGB
|
||||
Image = rgb(Image,SrcSpace);
|
||||
% Undo gamma correction
|
||||
R = invgammacorrection(Image(:,:,1));
|
||||
G = invgammacorrection(Image(:,:,2));
|
||||
B = invgammacorrection(Image(:,:,3));
|
||||
% Convert RGB to XYZ
|
||||
T = inv([3.2406, -1.5372, -0.4986; -0.9689, 1.8758, 0.0415; 0.0557, -0.2040, 1.057]);
|
||||
Image(:,:,1) = T(1)*R + T(4)*G + T(7)*B; % X
|
||||
Image(:,:,2) = T(2)*R + T(5)*G + T(8)*B; % Y
|
||||
Image(:,:,3) = T(3)*R + T(6)*G + T(9)*B; % Z
|
||||
end
|
||||
return;
|
||||
|
||||
|
||||
function Image = hsv(Image,SrcSpace)
|
||||
% Convert to HSV
|
||||
Image = rgb(Image,SrcSpace);
|
||||
V = max(Image,[],3);
|
||||
S = (V - min(Image,[],3))./(V + (V == 0));
|
||||
Image(:,:,1) = rgbtohue(Image);
|
||||
Image(:,:,2) = S;
|
||||
Image(:,:,3) = V;
|
||||
return;
|
||||
|
||||
|
||||
function Image = hsl(Image,SrcSpace)
|
||||
% Convert to HSL
|
||||
switch SrcSpace
|
||||
case 'hsv'
|
||||
% Convert HSV to HSL
|
||||
MaxVal = Image(:,:,3);
|
||||
MinVal = (1 - Image(:,:,2)).*MaxVal;
|
||||
L = 0.5*(MaxVal + MinVal);
|
||||
temp = min(L,1-L);
|
||||
Image(:,:,2) = 0.5*(MaxVal - MinVal)./(temp + (temp == 0));
|
||||
Image(:,:,3) = L;
|
||||
otherwise
|
||||
Image = rgb(Image,SrcSpace); % Convert to sRGB
|
||||
% Convert sRGB to HSL
|
||||
MinVal = min(Image,[],3);
|
||||
MaxVal = max(Image,[],3);
|
||||
L = 0.5*(MaxVal + MinVal);
|
||||
temp = min(L,1-L);
|
||||
S = 0.5*(MaxVal - MinVal)./(temp + (temp == 0));
|
||||
Image(:,:,1) = rgbtohue(Image);
|
||||
Image(:,:,2) = S;
|
||||
Image(:,:,3) = L;
|
||||
end
|
||||
return;
|
||||
|
||||
|
||||
function Image = lab(Image,SrcSpace)
|
||||
% Convert to CIE L*a*b* (CIELAB)
|
||||
WhitePoint = [0.950456,1,1.088754];
|
||||
|
||||
switch SrcSpace
|
||||
case 'lab'
|
||||
return;
|
||||
case 'lch'
|
||||
% Convert CIE L*CH to CIE L*ab
|
||||
C = Image(:,:,2);
|
||||
Image(:,:,2) = cos(Image(:,:,3)*pi/180).*C; % a*
|
||||
Image(:,:,3) = sin(Image(:,:,3)*pi/180).*C; % b*
|
||||
otherwise
|
||||
Image = xyz(Image,SrcSpace); % Convert to XYZ
|
||||
% Convert XYZ to CIE L*a*b*
|
||||
X = Image(:,:,1)/WhitePoint(1);
|
||||
Y = Image(:,:,2)/WhitePoint(2);
|
||||
Z = Image(:,:,3)/WhitePoint(3);
|
||||
fX = f(X);
|
||||
fY = f(Y);
|
||||
fZ = f(Z);
|
||||
Image(:,:,1) = 116*fY - 16; % L*
|
||||
Image(:,:,2) = 500*(fX - fY); % a*
|
||||
Image(:,:,3) = 200*(fY - fZ); % b*
|
||||
end
|
||||
return;
|
||||
|
||||
|
||||
function Image = luv(Image,SrcSpace)
|
||||
% Convert to CIE L*u*v* (CIELUV)
|
||||
WhitePoint = [0.950456,1,1.088754];
|
||||
WhitePointU = (4*WhitePoint(1))./(WhitePoint(1) + 15*WhitePoint(2) + 3*WhitePoint(3));
|
||||
WhitePointV = (9*WhitePoint(2))./(WhitePoint(1) + 15*WhitePoint(2) + 3*WhitePoint(3));
|
||||
|
||||
Image = xyz(Image,SrcSpace); % Convert to XYZ
|
||||
Denom = Image(:,:,1) + 15*Image(:,:,2) + 3*Image(:,:,3);
|
||||
U = (4*Image(:,:,1))./(Denom + (Denom == 0));
|
||||
V = (9*Image(:,:,2))./(Denom + (Denom == 0));
|
||||
Y = Image(:,:,2)/WhitePoint(2);
|
||||
L = 116*f(Y) - 16;
|
||||
Image(:,:,1) = L; % L*
|
||||
Image(:,:,2) = 13*L.*(U - WhitePointU); % u*
|
||||
Image(:,:,3) = 13*L.*(V - WhitePointV); % v*
|
||||
return;
|
||||
|
||||
|
||||
function Image = lch(Image,SrcSpace)
|
||||
% Convert to CIE L*ch
|
||||
Image = lab(Image,SrcSpace); % Convert to CIE L*ab
|
||||
H = atan2(Image(:,:,3),Image(:,:,2));
|
||||
H = H*180/pi + 360*(H < 0);
|
||||
Image(:,:,2) = sqrt(Image(:,:,2).^2 + Image(:,:,3).^2); % C
|
||||
Image(:,:,3) = H; % H
|
||||
return;
|
||||
|
||||
|
||||
function Image = cat02lms(Image,SrcSpace)
|
||||
% Convert to CAT02 LMS
|
||||
Image = xyz(Image,SrcSpace);
|
||||
T = [0.7328, 0.4296, -0.1624;-0.7036, 1.6975, 0.0061; 0.0030, 0.0136, 0.9834];
|
||||
X = Image(:,:,1);
|
||||
Y = Image(:,:,2);
|
||||
Z = Image(:,:,3);
|
||||
Image(:,:,1) = T(1)*X + T(4)*Y + T(7)*Z; % L
|
||||
Image(:,:,2) = T(2)*X + T(5)*Y + T(8)*Z; % M
|
||||
Image(:,:,3) = T(3)*X + T(6)*Y + T(9)*Z; % S
|
||||
return;
|
||||
|
||||
|
||||
function Image = huetorgb(m0,m2,H)
|
||||
% Convert HSV or HSL hue to RGB
|
||||
N = size(H);
|
||||
H = min(max(H(:),0),360)/60;
|
||||
m0 = m0(:);
|
||||
m2 = m2(:);
|
||||
F = H - round(H/2)*2;
|
||||
M = [m0, m0 + (m2-m0).*abs(F), m2];
|
||||
Num = length(m0);
|
||||
j = [2 1 0;1 2 0;0 2 1;0 1 2;1 0 2;2 0 1;2 1 0]*Num;
|
||||
k = floor(H) + 1;
|
||||
Image = reshape([M(j(k,1)+(1:Num).'),M(j(k,2)+(1:Num).'),M(j(k,3)+(1:Num).')],[N,3]);
|
||||
return;
|
||||
|
||||
|
||||
function H = rgbtohue(Image)
|
||||
% Convert RGB to HSV or HSL hue
|
||||
[M,i] = sort(Image,3);
|
||||
i = i(:,:,3);
|
||||
Delta = M(:,:,3) - M(:,:,1);
|
||||
Delta = Delta + (Delta == 0);
|
||||
R = Image(:,:,1);
|
||||
G = Image(:,:,2);
|
||||
B = Image(:,:,3);
|
||||
H = zeros(size(R));
|
||||
k = (i == 1);
|
||||
H(k) = (G(k) - B(k))./Delta(k);
|
||||
k = (i == 2);
|
||||
H(k) = 2 + (B(k) - R(k))./Delta(k);
|
||||
k = (i == 3);
|
||||
H(k) = 4 + (R(k) - G(k))./Delta(k);
|
||||
H = 60*H + 360*(H < 0);
|
||||
H(Delta == 0) = nan;
|
||||
return;
|
||||
|
||||
|
||||
function Rp = gammacorrection(R)
|
||||
Rp = zeros(size(R));
|
||||
i = (R <= 0.0031306684425005883);
|
||||
Rp(i) = 12.92*R(i);
|
||||
Rp(~i) = real(1.055*R(~i).^0.416666666666666667 - 0.055);
|
||||
return;
|
||||
|
||||
|
||||
function R = invgammacorrection(Rp)
|
||||
R = zeros(size(Rp));
|
||||
i = (Rp <= 0.0404482362771076);
|
||||
R(i) = Rp(i)/12.92;
|
||||
R(~i) = real(((Rp(~i) + 0.055)/1.055).^2.4);
|
||||
return;
|
||||
|
||||
|
||||
function fY = f(Y)
|
||||
fY = real(Y.^(1/3));
|
||||
i = (Y < 0.008856);
|
||||
fY(i) = Y(i)*(841/108) + (4/29);
|
||||
return;
|
||||
|
||||
|
||||
function Y = invf(fY)
|
||||
Y = fY.^3;
|
||||
i = (Y < 0.008856);
|
||||
Y(i) = (fY(i) - 4/29)*(108/841);
|
||||
return;
|
||||
261
Functions/helper_functions_community/linspecer.m
Normal file
@@ -0,0 +1,261 @@
|
||||
% function lineStyles = linspecer(N)
|
||||
% This function creates an Nx3 array of N [R B G] colors
|
||||
% These can be used to plot lots of lines with distinguishable and nice
|
||||
% looking colors.
|
||||
%
|
||||
% lineStyles = linspecer(N); makes N colors for you to use: lineStyles(ii,:)
|
||||
%
|
||||
% colormap(linspecer); set your colormap to have easily distinguishable
|
||||
% colors and a pleasing aesthetic
|
||||
%
|
||||
% lineStyles = linspecer(N,'qualitative'); forces the colors to all be distinguishable (up to 12)
|
||||
% lineStyles = linspecer(N,'sequential'); forces the colors to vary along a spectrum
|
||||
%
|
||||
% % Examples demonstrating the colors.
|
||||
%
|
||||
% LINE COLORS
|
||||
% N=6;
|
||||
% X = linspace(0,pi*3,1000);
|
||||
% Y = bsxfun(@(x,n)sin(x+2*n*pi/N), X.', 1:N);
|
||||
% C = linspecer(N);
|
||||
% axes('NextPlot','replacechildren', 'ColorOrder',C);
|
||||
% plot(X,Y,'linewidth',5)
|
||||
% ylim([-1.1 1.1]);
|
||||
%
|
||||
% SIMPLER LINE COLOR EXAMPLE
|
||||
% N = 6; X = linspace(0,pi*3,1000);
|
||||
% C = linspecer(N)
|
||||
% hold off;
|
||||
% for ii=1:N
|
||||
% Y = sin(X+2*ii*pi/N);
|
||||
% plot(X,Y,'color',C(ii,:),'linewidth',3);
|
||||
% hold on;
|
||||
% end
|
||||
%
|
||||
% COLORMAP EXAMPLE
|
||||
% A = rand(15);
|
||||
% figure; imagesc(A); % default colormap
|
||||
% figure; imagesc(A); colormap(linspecer); % linspecer colormap
|
||||
%
|
||||
% See also NDHIST, NHIST, PLOT, COLORMAP, 43700-cubehelix-colormaps
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% by Jonathan Lansey, March 2009-2013 – Lansey at gmail.com %
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%
|
||||
%% credits and where the function came from
|
||||
% The colors are largely taken from:
|
||||
% http://colorbrewer2.org and Cynthia Brewer, Mark Harrower and The Pennsylvania State University
|
||||
%
|
||||
%
|
||||
% She studied this from a phsychometric perspective and crafted the colors
|
||||
% beautifully.
|
||||
%
|
||||
% I made choices from the many there to decide the nicest once for plotting
|
||||
% lines in Matlab. I also made a small change to one of the colors I
|
||||
% thought was a bit too bright. In addition some interpolation is going on
|
||||
% for the sequential line styles.
|
||||
%
|
||||
%
|
||||
%%
|
||||
|
||||
function lineStyles=linspecer(N,varargin)
|
||||
|
||||
if nargin==0 % return a colormap
|
||||
lineStyles = linspecer(128);
|
||||
return;
|
||||
end
|
||||
|
||||
if ischar(N)
|
||||
lineStyles = linspecer(128,N);
|
||||
return;
|
||||
end
|
||||
|
||||
if N<=0 % its empty, nothing else to do here
|
||||
lineStyles=[];
|
||||
return;
|
||||
end
|
||||
|
||||
% interperet varagin
|
||||
qualFlag = 0;
|
||||
colorblindFlag = 0;
|
||||
|
||||
if ~isempty(varargin)>0 % you set a parameter?
|
||||
switch lower(varargin{1})
|
||||
case {'qualitative','qua'}
|
||||
if N>12 % go home, you just can't get this.
|
||||
warning('qualitiative is not possible for greater than 12 items, please reconsider');
|
||||
else
|
||||
if N>9
|
||||
warning(['Default may be nicer for ' num2str(N) ' for clearer colors use: whitebg(''black''); ']);
|
||||
end
|
||||
end
|
||||
qualFlag = 1;
|
||||
case {'sequential','seq'}
|
||||
lineStyles = colorm(N);
|
||||
return;
|
||||
case {'white','whitefade'}
|
||||
lineStyles = whiteFade(N);return;
|
||||
case 'red'
|
||||
lineStyles = whiteFade(N,'red');return;
|
||||
case 'blue'
|
||||
lineStyles = whiteFade(N,'blue');return;
|
||||
case 'green'
|
||||
lineStyles = whiteFade(N,'green');return;
|
||||
case {'gray','grey'}
|
||||
lineStyles = whiteFade(N,'gray');return;
|
||||
case {'colorblind'}
|
||||
colorblindFlag = 1;
|
||||
otherwise
|
||||
warning(['parameter ''' varargin{1} ''' not recognized']);
|
||||
end
|
||||
end
|
||||
% *.95
|
||||
% predefine some colormaps
|
||||
set3 = colorBrew2mat({[141, 211, 199];[ 255, 237, 111];[ 190, 186, 218];[ 251, 128, 114];[ 128, 177, 211];[ 253, 180, 98];[ 179, 222, 105];[ 188, 128, 189];[ 217, 217, 217];[ 204, 235, 197];[ 252, 205, 229];[ 255, 255, 179]}');
|
||||
set1JL = brighten(colorBrew2mat({[228, 26, 28];[ 55, 126, 184]; [ 77, 175, 74];[ 255, 127, 0];[ 255, 237, 111]*.85;[ 166, 86, 40];[ 247, 129, 191];[ 153, 153, 153];[ 152, 78, 163]}'));
|
||||
set1 = brighten(colorBrew2mat({[ 55, 126, 184]*.85;[228, 26, 28];[ 77, 175, 74];[ 255, 127, 0];[ 152, 78, 163]}),.8);
|
||||
|
||||
% colorblindSet = {[215,25,28];[253,174,97];[171,217,233];[44,123,182]};
|
||||
colorblindSet = {[215,25,28];[253,174,97];[171,217,233]*.8;[44,123,182]*.8};
|
||||
|
||||
set3 = dim(set3,.93);
|
||||
|
||||
if colorblindFlag
|
||||
switch N
|
||||
% sorry about this line folks. kind of legacy here because I used to
|
||||
% use individual 1x3 cells instead of nx3 arrays
|
||||
case 4
|
||||
lineStyles = colorBrew2mat(colorblindSet);
|
||||
otherwise
|
||||
colorblindFlag = false;
|
||||
warning('sorry unsupported colorblind set for this number, using regular types');
|
||||
end
|
||||
end
|
||||
if ~colorblindFlag
|
||||
switch N
|
||||
case 1
|
||||
lineStyles = { [ 55, 126, 184]/255};
|
||||
case {2, 3, 4, 5 }
|
||||
lineStyles = set1(1:N);
|
||||
case {6 , 7, 8, 9}
|
||||
lineStyles = set1JL(1:N)';
|
||||
case {10, 11, 12}
|
||||
if qualFlag % force qualitative graphs
|
||||
lineStyles = set3(1:N)';
|
||||
else % 10 is a good number to start with the sequential ones.
|
||||
lineStyles = cmap2linspecer(colorm(N));
|
||||
end
|
||||
otherwise % any old case where I need a quick job done.
|
||||
lineStyles = cmap2linspecer(colorm(N));
|
||||
end
|
||||
end
|
||||
lineStyles = cell2mat(lineStyles);
|
||||
|
||||
end
|
||||
|
||||
% extra functions
|
||||
function varIn = colorBrew2mat(varIn)
|
||||
for ii=1:length(varIn) % just divide by 255
|
||||
varIn{ii}=varIn{ii}/255;
|
||||
end
|
||||
end
|
||||
|
||||
function varIn = brighten(varIn,varargin) % increase the brightness
|
||||
|
||||
if isempty(varargin),
|
||||
frac = .9;
|
||||
else
|
||||
frac = varargin{1};
|
||||
end
|
||||
|
||||
for ii=1:length(varIn)
|
||||
varIn{ii}=varIn{ii}*frac+(1-frac);
|
||||
end
|
||||
end
|
||||
|
||||
function varIn = dim(varIn,f)
|
||||
for ii=1:length(varIn)
|
||||
varIn{ii} = f*varIn{ii};
|
||||
end
|
||||
end
|
||||
|
||||
function vOut = cmap2linspecer(vIn) % changes the format from a double array to a cell array with the right format
|
||||
vOut = cell(size(vIn,1),1);
|
||||
for ii=1:size(vIn,1)
|
||||
vOut{ii} = vIn(ii,:);
|
||||
end
|
||||
end
|
||||
%%
|
||||
% colorm returns a colormap which is really good for creating informative
|
||||
% heatmap style figures.
|
||||
% No particular color stands out and it doesn't do too badly for colorblind people either.
|
||||
% It works by interpolating the data from the
|
||||
% 'spectral' setting on http://colorbrewer2.org/ set to 11 colors
|
||||
% It is modified a little to make the brightest yellow a little less bright.
|
||||
function cmap = colorm(varargin)
|
||||
n = 100;
|
||||
if ~isempty(varargin)
|
||||
n = varargin{1};
|
||||
end
|
||||
|
||||
if n==1
|
||||
cmap = [0.2005 0.5593 0.7380];
|
||||
return;
|
||||
end
|
||||
if n==2
|
||||
cmap = [0.2005 0.5593 0.7380;
|
||||
0.9684 0.4799 0.2723];
|
||||
return;
|
||||
end
|
||||
|
||||
frac=.95; % Slight modification from colorbrewer here to make the yellows in the center just a bit darker
|
||||
cmapp = [158, 1, 66; 213, 62, 79; 244, 109, 67; 253, 174, 97; 254, 224, 139; 255*frac, 255*frac, 191*frac; 230, 245, 152; 171, 221, 164; 102, 194, 165; 50, 136, 189; 94, 79, 162];
|
||||
x = linspace(1,n,size(cmapp,1));
|
||||
xi = 1:n;
|
||||
cmap = zeros(n,3);
|
||||
for ii=1:3
|
||||
cmap(:,ii) = pchip(x,cmapp(:,ii),xi);
|
||||
end
|
||||
cmap = flipud(cmap/255);
|
||||
end
|
||||
|
||||
function cmap = whiteFade(varargin)
|
||||
n = 100;
|
||||
if nargin>0
|
||||
n = varargin{1};
|
||||
end
|
||||
|
||||
thisColor = 'blue';
|
||||
|
||||
if nargin>1
|
||||
thisColor = varargin{2};
|
||||
end
|
||||
switch thisColor
|
||||
case {'gray','grey'}
|
||||
cmapp = [255,255,255;240,240,240;217,217,217;189,189,189;150,150,150;115,115,115;82,82,82;37,37,37;0,0,0];
|
||||
case 'green'
|
||||
cmapp = [247,252,245;229,245,224;199,233,192;161,217,155;116,196,118;65,171,93;35,139,69;0,109,44;0,68,27];
|
||||
case 'blue'
|
||||
cmapp = [247,251,255;222,235,247;198,219,239;158,202,225;107,174,214;66,146,198;33,113,181;8,81,156;8,48,107];
|
||||
case 'red'
|
||||
cmapp = [255,245,240;254,224,210;252,187,161;252,146,114;251,106,74;239,59,44;203,24,29;165,15,21;103,0,13];
|
||||
otherwise
|
||||
warning(['sorry your color argument ' thisColor ' was not recognized']);
|
||||
end
|
||||
|
||||
cmap = interpomap(n,cmapp);
|
||||
end
|
||||
|
||||
% Eat a approximate colormap, then interpolate the rest of it up.
|
||||
function cmap = interpomap(n,cmapp)
|
||||
x = linspace(1,n,size(cmapp,1));
|
||||
xi = 1:n;
|
||||
cmap = zeros(n,3);
|
||||
for ii=1:3
|
||||
cmap(:,ii) = pchip(x,cmapp(:,ii),xi);
|
||||
end
|
||||
cmap = (cmap/255); % flipud??
|
||||
end
|
||||
|
||||
|
||||
|
||||
6
Functions/helper_functions_community/mat2tikz/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
*.sublime-workspace
|
||||
*.tap
|
||||
test/*.test.*
|
||||
*.asv
|
||||
*.m~
|
||||
octave-workspace
|
||||
16
Functions/helper_functions_community/mat2tikz/.travis.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
language: c++
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:octave/stable
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install gdb # to capture backtrace of eventual failures
|
||||
- sudo apt-get install octave
|
||||
- sudo apt-get purge libopenblas-base # fixes PPA Octave 4.0 crash on Travis
|
||||
before_script:
|
||||
- ulimit -c unlimited -S # enable core dumps for Octave crash debugging
|
||||
script:
|
||||
- ./runtests.sh /usr/bin/octave
|
||||
notifications:
|
||||
hipchat: f4c2c5f87adc85025545e5b59b3fbe@Matlab2tikz
|
||||
after_failure:
|
||||
- COREFILE=$(find . -maxdepth 1 -name "core*" | head -n 1) # find core file
|
||||
- gdb -c "$COREFILE" -ex "thread apply all bt" -ex "set pagination 0" -batch /usr/bin/octave-cli # print stack trace
|
||||
64
Functions/helper_functions_community/mat2tikz/AUTHORS.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Maintainer
|
||||
* [Egon Geerardyn](https://github.com/egeerardyn) is the current maintainer (2015 - now).
|
||||
* [Nico Schlömer](https://github.com/nschloe) designed and implemented the intial version and was the first maintainer (2008 - 2015).
|
||||
|
||||
# Contributors
|
||||
Thanks for patches, suggestions, and other contributions go to:
|
||||
|
||||
* [Ben Abbott](https://github.com/bpabbott)
|
||||
* Martijn Aben (The MathWorks)
|
||||
* [Nicolas Alt](https://github.com/nalt)
|
||||
* [Eshwar Andhavarapu](https://github.com/gontadu)
|
||||
* [Matt Bauman](https://github.com/mbauman)
|
||||
* Eike Blechschmidt
|
||||
* [Klaus Broelemann](https://github.com/Broele)
|
||||
* [Katherine Elkington](https://github.com/kelkington)
|
||||
* [Thomas Emmert](https://github.com/murmlgrmpf)
|
||||
* Andreas Gäb
|
||||
* [Egon Geerardyn](https://github.com/egeerardyn)
|
||||
* Roman Gesenhues
|
||||
* Michael Glasser (The MathWorks)
|
||||
* [David Haberthür](https://github.com/habi)
|
||||
* [Patrick Häcker](https://github.com/MagicMuscleMan)
|
||||
* [Ulrich Herter](https://github.com/ulijh)
|
||||
* [David Horsley](https://github.com/widdma)
|
||||
* Kári Hreinsson
|
||||
* [Lucas Jeub](https://github.com/LJeub)
|
||||
* [Martin Kiefel](https://github.com/mkiefel)
|
||||
* [Andreas Kloeckner](https://github.com/akloeckner)
|
||||
* Mykel Kochenderfer
|
||||
* [Oleg Komarov](https://github.com/okomarov)
|
||||
* Henk Kortier
|
||||
* [Tom Lankhorst](https://github.com/tomlankhorst)
|
||||
* [Burkart Lingner](https://github.com/burkart)
|
||||
* Theo Markettos
|
||||
* [Dragan Mitrevski](https://github.com/nidrosianDeath)
|
||||
* [Jason Monschke](https://github.com/jam4375)
|
||||
* Francesco Montorsi
|
||||
* Ricardo Santiago Mozos
|
||||
* Johannes Mueller-Roemer
|
||||
* [Ali Ozdagli](https://github.com/aliirmak)
|
||||
* [Richard Peschke](https://github.com/RPeschke)
|
||||
* [Peter Ploß](https://github.com/PeterPablo)
|
||||
* Julien Ridoux
|
||||
* [Christoph Rüdiger](https://github.com/mredd)
|
||||
* Carlos Russo
|
||||
* [Michael Schellenberger Costa](https://github.com/miscco)
|
||||
* [Manuel Schiller](https://github.com/dachziegel)
|
||||
* [Nico Schlömer](https://github.com/nschloe)
|
||||
* Johannes Schmitz
|
||||
* Michael Schoeberl
|
||||
* [Jan Taro Svejda](https://github.com/JTSvejda)
|
||||
* [José Vallet](https://github.com/josombio)
|
||||
* [Thomas Wagner](https://github.com/Aikhjarto)
|
||||
* Donghua Wang
|
||||
* [Patrick Wang](https://github.com/patrickkwang)
|
||||
* Robert Whittlesey
|
||||
* Pooya Ziraksaz
|
||||
* Bastiaan Zuurendonk (The MathWorks)
|
||||
* GitHub users: [andreas12345](https://github.com/andreas12345), [karih](https://github.com/karih), [theswitch](https://github.com/theswitch)
|
||||
|
||||
# Acknowledgements
|
||||
Matlab2tikz has once greatly profited from its ancestor: [Matfig2PGF](http://www.mathworks.com/matlabcentral/fileexchange/12962) written by Paul Wagenaars.
|
||||
|
||||
Also, the authors would like to thank [Christian Feuersänger](https://github.com/cfeuersaenger) for the [Pgfplots](http://pgfplots.sourceforge.net) package which forms the basis for the matlab2tikz output on the LaTeX side.
|
||||
439
Functions/helper_functions_community/mat2tikz/CHANGELOG.md
Normal file
@@ -0,0 +1,439 @@
|
||||
# 2016-08-15 Version 1.1.0 [Egon Geerardyn](egon.geerardyn@gmail.com)
|
||||
|
||||
* Added or improved support for:
|
||||
- Octave 4.0 (#759)
|
||||
- `scatter`, `quiver` and `errorbar` support in Octave (#669)
|
||||
- `cleanfigure` has been improved:
|
||||
* New and superior (Opheim) simplification algorithm
|
||||
* Simplification for `plot3` (3D plots) (#790)
|
||||
* Vectorized implementations (#756, #737)
|
||||
* Overall clean-up of the code (#797, #787, #776, #744)
|
||||
* Optional limitation of data precision (#791)
|
||||
* Textbox removal is being phased out (#817)
|
||||
- Quiver plots now translate to native pgfplots quivers (#679, #690)
|
||||
- Legends, especially with `plotyy`, now use `\label` (#140, #760, #773)
|
||||
- Tick labels with `datetime` (#383, #803)
|
||||
- `contourf`/`contour` plots with matrix arguments and nonstandard line widths (#592, #721, #722, #871)
|
||||
- Colored ticks and axes (#880, #908)
|
||||
- Scatter plots with different marker colors and sizes (#859, #861)
|
||||
- `colorbar` positioning and tick placement (#933, #937, #941)
|
||||
- The self-updater has been improved
|
||||
* New parameters:
|
||||
- `arrowHeadSizeFactor` for tweaking the size of arrowheads
|
||||
- `semanticLineWidths` for tweaking semantic line width conversion (e.g. `thick` instead of `0.8pt`)
|
||||
* Extra requirements:
|
||||
- Quiver plots require `\usetikzlibrary{arrows.meta}`
|
||||
* Bug fixes:
|
||||
- Errorbars without lines & markers (#813)
|
||||
- `light`/`camera` objects are now ignored (#684)
|
||||
- Draw baseline in bar/stem plots (#798)
|
||||
- Multiple annotation containers (#728, #730)
|
||||
- Legends of bode plots (#700, #702)
|
||||
- Titles of bode plots (#715, #716, #753)
|
||||
- Patch without fill/edge color (#682, #701, #740)
|
||||
- Warn about usage of faceted interp shader (#699)
|
||||
- Tick labels are properly escaped now (#711)
|
||||
- Swapped image dimensions (#714)
|
||||
- Width of bar plots was incorrect (#727, #696)
|
||||
- Stacking and placement of bar plots (#851, #845, #840, #785, #903)
|
||||
- Handling of tick labels when `parseStrings=false` (#86, #871)
|
||||
- Properly escape tick labels for LaTeX (#710, #711, #820, #821)
|
||||
- Respect edge color in `scatter` plots (#900)
|
||||
- Output directory is created automatically (#889, #929)
|
||||
- TikZ output format has been improved slightly (#936, #921, #801)
|
||||
* For developers:
|
||||
- Please check out the (guidelines)[CONTRIBUTING.md]
|
||||
- We now use `allchild` and `findall` (#718)
|
||||
- SublimeText project files
|
||||
- Test hashes can be saved selectively (#720)
|
||||
- Continuous testing for MATLAB and Octave 3.8 with Jenkins
|
||||
- Test suite timing is tracked (#738)
|
||||
- The testing reports have been improved for GitHub (#708)
|
||||
- Testing can output to different directories (#818)
|
||||
- A new tool to help track regressions (#814)
|
||||
- A new tool to consistently format the code (#808, #809)
|
||||
- `figure2dot` updated for HG2
|
||||
|
||||
# 2015-06-15 Version 1.0.0 [Egon Geerardyn](egon.geerardyn@gmail.com)
|
||||
|
||||
* Added support for:
|
||||
- Annotations (except arrows) in R2014b (#534)
|
||||
- `Histogram` in R2014b (#525)
|
||||
- Filled contour plots in R2014b (#379, #500)
|
||||
- Contour plots with color maps in R2014b (#380, #500)
|
||||
- Axes background color and overlap (#6, #509, #510)
|
||||
- Horizontal/Vertical text alignment (#491)
|
||||
* Extra requirements:
|
||||
- Patch plots now require `\usepgfplotslibrary{patchplots}` (#386, #497)
|
||||
* Bug fixes:
|
||||
- Pgfplots 1.12 (`row sep=crcr`) in combination with `externalData==true` (#548)
|
||||
- Updater has been fixed (#502)
|
||||
- 3D plot sizing takes viewing angle into account (#560, #630, #631)
|
||||
- Alpha channel (transparency) in images (#561)
|
||||
- Colorbar labels in R2014b (#429, #488)
|
||||
- Scaling of color data at axes level (#486)
|
||||
- Text formatting (for `TeX` parser) is improved (#417)
|
||||
- Support for `|` character in labels (#587, #589)
|
||||
- Legends for `stairs` and `area` plots (#601, #602)
|
||||
- `cleanfigure()` removes points outside of the axes for `stairs` plots (#226, #533)
|
||||
- `cleanfigure()` removes points outside of the axes better (#392, #400, #547)
|
||||
- Support `>` and `<` in text (#522)
|
||||
- Better text positioning (#518)
|
||||
- Text boxes on 3D graphs (#528)
|
||||
- File closing is more robust (#496, #555)
|
||||
- TikZ picture output, i.e.`imageAsPng==false`, improved (#581, #596)
|
||||
- `standalone==true` sets the font and input encoding in LaTeX (#590)
|
||||
- Legend text alignment in Octave (#668)
|
||||
- Improved Octave legend if not all lines have an entry (#607, #619, #653)
|
||||
- Legend without a drawn box in R2014b+ (#652)
|
||||
- Misc. fixes: #426, #513, #520, #665
|
||||
* For developers:
|
||||
- The testing framework has been revamped (see also `test/README.md`)
|
||||
- A lot of the tests have been updated (#604, #614, #638, ...)
|
||||
- Cyclomatic complexity of the code has been reduced (#391)
|
||||
- Repository has been moved to [matlab2tikz/matlab2tikz](https://github.com/matlab2tikz/matlab2tikz)
|
||||
- Extra files have been pruned (#616)
|
||||
|
||||
# 2014-11-02 Version 0.6.0 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Annotation support in R2014a and earlier
|
||||
* New subplot positioning approach (by Klaus Broelemann) that uses absolute instead of relative positions.
|
||||
* Support stacked bar plots and others in the same axes (needs pgfplots 1.11).
|
||||
* Support legends with multiline entries.
|
||||
* Support for the alpha channel in PNG output.
|
||||
* Test framework updated and doesn't display figures by default.
|
||||
* Major code clean-up and code complexity checks.
|
||||
* Bug fixes:
|
||||
- Cycle paths only when needed (#317, #49, #404)
|
||||
- Don't use infinite xmin/max, etc. (#436)
|
||||
- Warn about the `noSize` parameter (#431)
|
||||
- Images aren't flipped anymore (#401)
|
||||
- No scientific notation in width/height (#396)
|
||||
- Axes with custom colors (#376)
|
||||
- Mesh plots are exported properly (#382)
|
||||
- Legend colors are handled better (#389)
|
||||
- Handle Z axis properties for quiver3 (#406)
|
||||
- Better text handling, e.g. degrees (#402)
|
||||
- Don't output absolute paths into TikZ by default
|
||||
- ...
|
||||
|
||||
# 2014-10-20 Version 0.5.0 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Support for MATLAB 2014b (with it's substantial graphics changes).
|
||||
All credit goes to Egon Geerardyn.
|
||||
* Bugfixes:
|
||||
- single bar width
|
||||
- invisible bar plots
|
||||
- surface options
|
||||
- patch plots and cycling
|
||||
- patches with literal colors
|
||||
|
||||
# 2014-03-07 Version 0.4.7 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Acid tests: Remove MATLAB-based `eps2pdf`.
|
||||
* Bugfixes:
|
||||
- multiple patches
|
||||
- log plot with nonzero baseline
|
||||
- marker options for scatter plots
|
||||
- table data formatting
|
||||
- several fixes for Octave
|
||||
|
||||
# 2014-02-07 Version 0.4.6 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Set `externalData` default to `false`.
|
||||
* Properly check for required Pgfplots version.
|
||||
* Marker scaling in scatter plots.
|
||||
|
||||
# 2014-02-02 Version 0.4.5 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Arrange data in tables.
|
||||
* Optionally define custom colors.
|
||||
* Allow for strict setting of font sizes.
|
||||
* Bugfixes:
|
||||
- tick labels for log plots
|
||||
- tick labels with commas
|
||||
|
||||
# 2014-01-02 Version 0.4.4 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Support for color maps with scatter plots.
|
||||
* Support for different-length up-down error bars.
|
||||
* Input options validation.
|
||||
* Bugfixes:
|
||||
- legends for both area and line plots
|
||||
- invisible text fields
|
||||
|
||||
# 2013-10-20 Version 0.4.3 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Support for 3D quiver plots.
|
||||
* Extended support for colorbar axis options.
|
||||
* New logo!
|
||||
* Bugfixes:
|
||||
- text generation
|
||||
- extraCode option
|
||||
- join strings
|
||||
- ...
|
||||
|
||||
# 2013-09-12 Version 0.4.2 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Support for explicit color specification in 3D plots.
|
||||
* Better color handling for patch plots.
|
||||
* Support for various unicode characters.
|
||||
* Bugfixes:
|
||||
- edge colors for bar plots
|
||||
- multiple color bars
|
||||
- ...
|
||||
|
||||
# 2013-08-14 Version 0.4.1 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Replaced option `extraTikzpictureCode` by `extraCode`
|
||||
for inserting code at the beginning of the file.
|
||||
* Support for relative text positioning.
|
||||
* Improved documentation.
|
||||
* Code cleanup: moved all figure manipulations over to cleanfigure()
|
||||
* Bugfixes:
|
||||
- error bars
|
||||
- empty tick labels
|
||||
- ...
|
||||
|
||||
# 2013-06-26 Version 0.4.0 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Added `cleanfigure()` for removing unwanted entities from a plot
|
||||
before conversion
|
||||
* Add option `floatFormat` to allow for custom specification of the format
|
||||
of float numbers
|
||||
* Bugfixes:
|
||||
- linewidth for patches
|
||||
- ...
|
||||
|
||||
# 2013-04-13 Version 0.3.3 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Support for:
|
||||
- pictures in LaTeX subfloats
|
||||
* Bugfixes:
|
||||
- axes labels
|
||||
- extra* options
|
||||
- logscaled axes
|
||||
- ...
|
||||
|
||||
# 2013-03-14 Version 0.3.2 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Support for:
|
||||
- waterfall plots
|
||||
* Bugfixes:
|
||||
- axis locations
|
||||
- color handling
|
||||
- stacked bars
|
||||
- ...
|
||||
|
||||
# 2013-02-15 Version 0.3.1 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Use `table{}` for plots for cleaner output files.
|
||||
* Support for:
|
||||
- hg transformations
|
||||
- pcolor plots
|
||||
* Removed command line options:
|
||||
- `minimumPointsDistance`
|
||||
* Bugfixes:
|
||||
- legend positioning and alignment
|
||||
- tick labels
|
||||
- a bunch of fixed for Octave
|
||||
- line width for markers
|
||||
- axis labels for color bars
|
||||
- image trimming
|
||||
- subplots with bars
|
||||
- ...
|
||||
|
||||
# 2012-11-19 Version 0.3.0 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Support for:
|
||||
- area plots
|
||||
- legend position
|
||||
- inner color bars
|
||||
- log-scaled color bars
|
||||
* New command line options:
|
||||
- `standalone` (create compilable TeX file)
|
||||
- `checkForUpdates`
|
||||
* `mlint` cleanups.
|
||||
* Removed deprecated options.
|
||||
* Bugfixes:
|
||||
- colorbar-axis association
|
||||
- option parsing
|
||||
- automatic updater
|
||||
- unit 'px'
|
||||
- ...
|
||||
|
||||
# 2012-09-01 Version 0.2.3 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Multiline text for all entities.
|
||||
* Support for logical images.
|
||||
* Support for multiple legends (legends in subplots).
|
||||
* Fixed version check bug.
|
||||
* Fix `minimumPointsDistance`.
|
||||
|
||||
# 2012-07-19 Version 0.2.2 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Support for multiline titles and axis labels.
|
||||
* Respect log-scaled axes for `minimumPointsDistance`.
|
||||
* Add support for automatic graph labels via new option.
|
||||
* About 5 bugfixes.
|
||||
|
||||
# 2012-05-04 Version 0.2.1 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Support for color maps.
|
||||
* Support for native color bars.
|
||||
* Partial support for hist3 plots.
|
||||
* Support for spectrogram plots.
|
||||
* Support for rotated text.
|
||||
* Native handling of `Inf`s and `NaN`s.
|
||||
* Better info text.
|
||||
* matlab2tikz version checking.
|
||||
* Line plotting code cleanup.
|
||||
* About 10 bugfixes.
|
||||
|
||||
# 2012-03-17 Version 0.2.0 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Greatly overhauled text handling. (Burkhart Lingner)
|
||||
* Added option `tikzFileComment`.
|
||||
* Added option `parseStrings`.
|
||||
* Added option `extraTikzpictureSettings`.
|
||||
* Added proper documetion (for `help matlab2tikz`).
|
||||
* Improved legend positioning, orientation.
|
||||
* Support for horizontal bar plots.
|
||||
* Get bar widths right.
|
||||
* Doubles are plottet with 15-digit precision now.
|
||||
* Support for rectangle objects.
|
||||
* Better color handling.
|
||||
* Testing framework improvements.
|
||||
* Several bugfixes:
|
||||
- ticks handled more concisely
|
||||
- line splitting bugs
|
||||
- ...
|
||||
|
||||
# 2011-11-22 Version 0.1.4 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Support for scatter 3D plots.
|
||||
* Support for 3D parameter curves.
|
||||
* Support for 3D patches.
|
||||
* Support for minor ticks.
|
||||
* Add option `interpretTickLabelsAsTex` (default `false`).
|
||||
* Several bugfixes:
|
||||
- `%` sign in annotations
|
||||
- fixed `\omega` and friends in annotations
|
||||
- proper legend for bar plots
|
||||
- don't override PNG files if there is more than one image plot
|
||||
- don't always close patch paths
|
||||
|
||||
# 2011-08-22 Version 0.1.3 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Greatly overhauled text handling.
|
||||
* Better Octave compatibility.
|
||||
* Several bugfixes:
|
||||
- subplot order
|
||||
- environment detection
|
||||
|
||||
|
||||
# 2011-06-02 Version 0.1.2 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Support for logscaled color bar.
|
||||
* Support for truecolor images.
|
||||
* Initial support for text handles.
|
||||
* Speed up processing for line plots.
|
||||
* Several bugfixes:
|
||||
- axis labels, tick labels, etc. for z-axis
|
||||
- marker handling for scatter plots
|
||||
- fix for unicolor scatter plots
|
||||
|
||||
# 2011-04-06 Version 0.1.1 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Improved Octave compatibility.
|
||||
* Several bugfixes:
|
||||
- input parser
|
||||
|
||||
# 2011-01-31 Version 0.1.0 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Basic Octave compatibility.
|
||||
* Several bugfixes:
|
||||
- bar plots fix (thanks to Christoph Rüdiger)
|
||||
- fix legends with split graphs
|
||||
|
||||
# 2010-09-10 Version 0.0.7 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Compatibility fixes for older MATLAB installations.
|
||||
* Several bugfixes:
|
||||
- line plots with only one point
|
||||
- certain surface plots
|
||||
- orientation of triangle markers (`<` vs. `>`)
|
||||
- display of the color `purple`
|
||||
|
||||
# 2010-05-06 Version 0.0.6 [Nico Schlömer](nico.schloemer@gmail.com)
|
||||
|
||||
* Support for scatter plots.
|
||||
* Preliminary support for surface plots; thanks to Pooya.
|
||||
* Large changes in the codebase:
|
||||
- next to `matlab2tikz.m`, the file `pgfplotsEnvironment.m` is now needed as well; it provides a much better structured approach to storing and writing environments when parsing the MATLAB(R) figure
|
||||
* proper MATLAB(R) version check
|
||||
* lots of small fixes
|
||||
|
||||
# 2009-12-21 Version 0.0.5 [Nico Schlömer](nico.schloemer@ua.ac.be)
|
||||
|
||||
* Improvements in axis handling:
|
||||
- colored axes
|
||||
- allow different left and right ordinates
|
||||
* Improvements for line plots:
|
||||
- far outliers are moved toward the plot,
|
||||
avoiding `Dimension too large`-type errors in LaTeX
|
||||
- optional point reduction by new option `minimumPointsDistance`
|
||||
* Improvements for image handling:
|
||||
- creation of a PNG file, added by `\addplot graphics`
|
||||
- fixed axis orientation bug
|
||||
* Bugfixes for:
|
||||
- multiple axes
|
||||
- CMYK colors
|
||||
- legend text alignment (thanks Dragan Mitrevski)
|
||||
- transparent patches (thanks Carlos Russo)
|
||||
* Added support for:
|
||||
- background color
|
||||
- Bode plots
|
||||
- zplane plots
|
||||
- freqz plots
|
||||
|
||||
# 2009-06-09 Version 0.0.4 [Nico Schlömer](nico.schloemer@ua.ac.be)
|
||||
|
||||
* Added support for:
|
||||
- error bars (thanks Robert Whittlesey for the suggestion)
|
||||
* Improvents in:
|
||||
- legends (thanks Theo Markettos for the patch),
|
||||
- images,
|
||||
- quiver plots (thanks Robert for spotting this).
|
||||
* Improved options handling.
|
||||
* Allow for custom file encoding (thanks Donghua Wang for the suggestion).
|
||||
* Numerous bugfixes (thanks Andreas Gäb).
|
||||
|
||||
# 2009-03-08 Version 0.0.3 [Nico Schlömer](nico.schloemer@ua.ac.be)
|
||||
|
||||
* Added support for:
|
||||
- subplots
|
||||
- reverse axes
|
||||
* Completed support for:
|
||||
- images
|
||||
|
||||
# 2009-01-08 Version 0.0.2 [Nico Schlömer](nico.schloemer@ua.ac.be)
|
||||
|
||||
* Added support for:
|
||||
- quiver (arrow) plots
|
||||
- bar plots
|
||||
- stem plots
|
||||
- stairs plots
|
||||
* Added preliminary support for:
|
||||
- images
|
||||
- rose plots
|
||||
- compass plots
|
||||
- polar plots
|
||||
* Moreover, large code improvement have been introduced, notably:
|
||||
- aspect ratio handling
|
||||
- color handling
|
||||
- plot options handling
|
||||
|
||||
# 2008-11-07 Version 0.0.1 [Nico Schlömer](nico.schloemer@ua.ac.be)
|
||||
|
||||
* Initial version
|
||||
@@ -0,0 +1,66 @@
|
||||
# Contributing to matlab2tikz
|
||||
|
||||
You can contribute in many ways to `matlab2tikz`:
|
||||
|
||||
- report bugs,
|
||||
- suggest new features,
|
||||
- write documentation,
|
||||
- fix some of our bugs and implement new features.
|
||||
|
||||
The first part of this document is geared more towards users of `matlab2tikz`.
|
||||
The latter part is only relevant if you want to write some code for `matlab2tikz`.
|
||||
|
||||
## How to report a bug or ask for help
|
||||
|
||||
1. Make sure you are using the [latest release](https://github.com/matlab2tikz/matlab2tikz/releases/latest) or even the [development version](https://github.com/matlab2tikz/matlab2tikz/tree/develop) of `matlab2tikz` and check that the problem still exists.
|
||||
2. Also make sure you are using a recent version of the required LaTeX packages (especially [`pgfplots`](http://ctan.org/pkg/pgfplots) and the [`TikZ`](http://ctan.org/pkg/pgf) libraries)
|
||||
3. You can submit your bug report or question to our [issue tracker](https://github.com/matlab2tikz/matlab2tikz/issues).
|
||||
Please, have a look at "[How to Ask Questions the Smart Way](http://www.catb.org/esr/faqs/smart-questions.html)" and "[Writing Better Bug Reports](http://martiancraft.com/blog/2014/07/good-bug-reports/)" for generic guidelines. In short:
|
||||
- Mention the version of MATLAB/Octave, the operating system, `matlab2tikz`, `pgfplots` and which `LaTeX` compiler you are using.
|
||||
- Choose a descriptive title for your issue report.
|
||||
- A short MATLAB code snippet that generates a plot where the problem occurs. Please limit this to what is strictly necessary to show the issue!
|
||||
- Explain what is wrong with the conversion of the figure (or what error messages you see).
|
||||
- Often it can be useful to also include a figure, `TikZ` code, ... to illustrate your point.
|
||||
|
||||
## How to request new features
|
||||
|
||||
Please check first whether the feature hasn't been [requested](https://github.com/matlab2tikz/matlab2tikz/labels/feature%20request) before and do join the relevant topic in that case or maybe it has already been implemented in the [latest development version](https://github.com/matlab2tikz/matlab2tikz/tree/develop).
|
||||
|
||||
If your feature is something new and graphical, please also have a look at the [`pgfplots`](https://www.ctan.org/pkg/pgfplots) manual to see if it supports the feature you want.
|
||||
In some cases it is more constructive to request the feature in the [`pgfplots` bug tracker](https://sourceforge.net/p/pgfplots/bugs/).
|
||||
|
||||
Please submit you feature request as any [bug report](https://github.com/matlab2tikz/matlab2tikz/labels/feature%20request) and make sure that you include enough details in your post, e.g.:
|
||||
|
||||
- What are you trying to do?
|
||||
- What should it look like or how should it work?
|
||||
- Is there a relevant section in the `pgfplots` or `MATLAB` documentation?
|
||||
|
||||
## Submitting pull requests (PRs)
|
||||
Before you start working on a bug or new feature, you might want to check that nobody else has been assigned to the relevant issue report.
|
||||
To avoid wasted hours, please just indicate your interest to tackle the issue.
|
||||
|
||||
### Recommended workflow
|
||||
[Our wiki](https://github.com/matlab2tikz/matlab2tikz/wiki/Recommended-git-workflow) contains more elaborate details on this process. Here is the gist:
|
||||
|
||||
- It is highly recommended to start a feature branch for your work.
|
||||
- Once you have finished the work, please try to run the test suite and report on the outcome in your PR (see below).
|
||||
- Make sure that you file your pull request against the `develop` branch and *not* the `master` branch!
|
||||
- Once you have filed your PR, the review process starts. Everybody is free to join this discussion.
|
||||
- At least one other developer will review the code and signal their approval (often using a thumbs-up, :+1:) before the PR gets pulled into `develop`.
|
||||
- Once you have addressed all comments, one of the developers will merge your code into the `develop` branch.
|
||||
|
||||
If you still feel uncomfortable with `git`, please have a look at [this page](https://github.com/matlab2tikz/matlab2tikz/wiki/Learning-git) for a quick start.
|
||||
|
||||
### Running the test suite
|
||||
We know that at first the test suite can seem a bit intimidating, so we tend to be lenient during your first few PRs. However, we encourage you to run the test suite on your local computer and report on the results in your PR if any failures pop up.
|
||||
To run the test suite, please consult its [README](https://github.com/matlab2tikz/matlab2tikz/blob/develop/test/README.md).
|
||||
|
||||
## Becoming a member of [matlab2tikz](https://github.com/matlab2tikz)
|
||||
|
||||
Once you have submitted your first pull request that is of reasonable quality, you may get invited to join the [Associate Developers](https://github.com/orgs/matlab2tikz/teams/associate-developers) group.
|
||||
This group comes with *no* responsibility whatsoever and merely serves to make it easier for you to "claim" the features you want to work on.
|
||||
|
||||
Once you have gained some experience (with `git`/GitHub, our codebase, ...) and have contributed your fair share of great material, you will get invited to join the [Developers](https://github.com/orgs/matlab2tikz/teams/developers) team.
|
||||
This status gives you push access to our repository and hence comes with the responsibility to not abuse your push access.
|
||||
|
||||
If you feel you should have gotten an invite for a team, feel free to contact one of the [owners](https://github.com/orgs/matlab2tikz/teams/owners).
|
||||
24
Functions/helper_functions_community/mat2tikz/LICENSE.md
Normal file
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2008--2016 Nico Schlömer
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
95
Functions/helper_functions_community/mat2tikz/README.md
Normal file
@@ -0,0 +1,95 @@
|
||||
**The updater in matlab2tikz 0.6.0 (and older) no longer works.**
|
||||
**Please [update manually](http://www.mathworks.com/matlabcentral/fileexchange/22022-matlab2tikz-matlab2tikz?download=true) if you are not using matlab2tikz 1.0.0 or newer!**
|
||||
|
||||
[](https://travis-ci.org/matlab2tikz/matlab2tikz) [](http://dx.doi.org/10.5281/zenodo.18605)
|
||||

|
||||
|
||||
`matlab2tikz` is a MATLAB(R) script to convert native MATLAB(R) figures to TikZ/Pgfplots figures that integrate seamlessly in LaTeX documents.
|
||||
|
||||
To download the official releases and rate `matlab2tikz`, please visit its page on [FileExchange](http://www.mathworks.com/matlabcentral/fileexchange/22022).
|
||||
|
||||
`matlab2tikz` converts most MATLAB(R) figures, including 2D and 3D plots.
|
||||
For plots constructed with third-party packages, however, your mileage may vary.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
1. Extract the ZIP file (or clone the git repository) somewhere you can easily reach it.
|
||||
2. Add the `src/` folder to your path in MATLAB/Octave: e.g.
|
||||
- using the "Set Path" dialog in MATLAB, or
|
||||
- by running the `addpath` function from your command window or `startup` script.
|
||||
|
||||
Make sure that your LaTeX installation is up-to-date and includes:
|
||||
|
||||
* [TikZ/PGF](http://www.ctan.org/pkg/pgf) version 3.0 or higher
|
||||
* [Pgfplots](http://www.ctan.org/pkg/pgfplots) version 1.13 or higher
|
||||
* [Amsmath](https://www.ctan.org/pkg/amsmath) version 2.14 or higher
|
||||
* [Standalone](http://www.ctan.org/pkg/standalone) (optional)
|
||||
|
||||
It is recommended to use the latest stable version of these packages.
|
||||
Older versions may work depending on the actual MATLAB(R) figure you are converting.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Typical usage of `matlab2tikz` consists of converting your MATLAB plot to a TikZ/LaTeX file and then running a LaTeX compiler to produce your document.
|
||||
|
||||
MATLAB
|
||||
------
|
||||
1. Generate your plot in MATLAB(R).
|
||||
|
||||
2. Run `matlab2tikz`, e.g. using
|
||||
|
||||
```matlab
|
||||
matlab2tikz('myfile.tex');
|
||||
```
|
||||
|
||||
LaTeX
|
||||
-----
|
||||
Add the contents of `myfile.tex` into your LaTeX source code, for example using `\input{myfile.tex}`.
|
||||
Make sure that the required packages (such as `pgfplots`) are loaded in the preamble of your document as in the example:
|
||||
|
||||
```latex
|
||||
\documentclass{article}
|
||||
|
||||
\usepackage{pgfplots}
|
||||
\pgfplotsset{compat=newest}
|
||||
%% the following commands are needed for some matlab2tikz features
|
||||
\usetikzlibrary{plotmarks}
|
||||
\usetikzlibrary{arrows.meta}
|
||||
\usepgfplotslibrary{patchplots}
|
||||
\usepackage{grffile}
|
||||
\usepackage{amsmath}
|
||||
|
||||
%% you may also want the following commands
|
||||
%\pgfplotsset{plot coordinates/math parser=false}
|
||||
%\newlength\figureheight
|
||||
%\newlength\figurewidth
|
||||
|
||||
\begin{document}
|
||||
\input{myfile.tex}
|
||||
\end{document}
|
||||
```
|
||||
|
||||
Remarks
|
||||
-------
|
||||
Most functions accept numerous options; you can check them out by inspecting their help:
|
||||
|
||||
```matlab
|
||||
help matlab2tikz
|
||||
```
|
||||
|
||||
Sometimes, MATLAB(R) plots contain some features that impede conversion to LaTeX; e.g. points that are far outside of the actual bounding box.
|
||||
You can invoke the `cleanfigure` function to remove such unwanted entities before calling `matlab2tikz`:
|
||||
|
||||
```matlab
|
||||
cleanfigure;
|
||||
matlab2tikz('myfile.tex');
|
||||
```
|
||||
|
||||
More information
|
||||
================
|
||||
|
||||
* For more information about `matlab2tikz`, have a look at our [GitHub repository](https://github.com/matlab2tikz/matlab2tikz). If you are a good MATLAB(R) programmer or LaTeX writer, you are always welcome to help improving `matlab2tikz`!
|
||||
* Some common problems and pit-falls are documented in our [wiki](https://github.com/matlab2tikz/matlab2tikz/wiki/Common-problems).
|
||||
* If you experience (other) bugs or would like to request a feature, please visit our [issue tracker](https://github.com/matlab2tikz/matlab2tikz/issues).
|
||||
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="2083.4766"
|
||||
height="856.6734"
|
||||
id="svg3051"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="matlab2tikz.svg">
|
||||
<defs
|
||||
id="defs3053" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.5"
|
||||
inkscape:cx="1424.8959"
|
||||
inkscape:cy="275.08087"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="949"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
fit-margin-top="5"
|
||||
fit-margin-left="5"
|
||||
fit-margin-right="5"
|
||||
fit-margin-bottom="5" />
|
||||
<metadata
|
||||
id="metadata3056">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(96.763877,-104.02549)">
|
||||
<path
|
||||
style="fill:#ef8200;fill-opacity:1;stroke:none"
|
||||
d="m 229.79347,889.91953 c -51.20296,-69.53548 -110.45905,-150.5284 -117.8477,-161.07762 -3.66043,-5.22621 -4.15923,-6.45766 -2.93039,-7.23468 0.81449,-0.51503 2.1559,-0.94763 2.9809,-0.96134 4.45183,-0.074 21.84491,-16.50352 39.70528,-37.5057 64.93246,-76.3547 212.14442,-292.5117 313.27925,-460 28.45805,-47.12908 55.23448,-94.70724 59.01417,-107.81682 2.21373,-7.67817 3.30364,-4.58186 5.54982,7.259 0.84717,4.46595 9.42069,39.94343 19.05225,78.83886 61.4356,248.09709 88.96885,376.22196 95.45994,444.21896 1.34274,14.06576 0.80116,31.67542 -1.06339,34.57694 -0.67969,1.05768 -29.41344,23.07306 -63.85279,48.92306 -46.63668,35.00526 -216.41083,162.82778 -297.77739,224.19582 l -3.13285,2.36286 z"
|
||||
id="path3072"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#ffd912;fill-opacity:1"
|
||||
d="M 828.49628,790.87316 C 751.45425,746.41551 656.62349,689.46978 647.33146,682.08395 c -2.47911,-1.97053 -2.52321,-2.17947 -1.05805,-5.01277 3.18772,-6.16438 4.02557,-14.85566 3.44538,-35.74002 -0.80529,-28.98647 -5.98761,-65.55929 -17.38517,-122.69097 -18.80756,-94.27528 -55.9766,-241.89492 -91.4729,-363.29152 -4.95189,-16.93533 -13.8484,-44.15875 -13.64905,-44.7568 0.19935,-0.59804 7.77507,16.91106 10.71396,23.16944 14.72516,31.35732 169.10504,368.5638 262.04653,572.37888 18.81036,41.25 35.965,78.78344 38.1214,83.40766 2.15641,4.62421 3.80419,8.50202 3.66173,8.61735 -0.14245,0.11533 -6.10901,-3.16608 -13.25901,-7.29204 z"
|
||||
id="path3070"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#00b0cf;fill-opacity:1"
|
||||
d="M 98.496283,712.93087 C 76.224153,691.69469 25.659453,651.42885 -55.133796,590.59166 l -36.630081,-27.58239 14.630081,-4.80606 C 1.4604828e-5,532.86436 84.848253,489.14509 155.49628,438.33721 c 90.71369,-65.23848 211.18904,-171.14032 339.75,-298.65155 14.7125,-14.59237 30.24771,-31.09621 30.24771,-30.65137 0,1.46965 -5.56006,9.74411 -33.50167,53.6059 -117.938,185.13504 -236.74752,364.94776 -300.3065,454.5 -22.45559,31.6391 -46.86362,64.24839 -58.75719,78.5 -10.15154,12.16419 -23.13943,25.02746 -25.20109,24.95928 -0.6772,-0.0224 -4.83126,-3.47326 -9.231257,-7.6686 z"
|
||||
id="path2987"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:256.08959961px;line-height:125%;font-family:'Monotype Corsiva';-inkscape-font-specification:'Monotype Corsiva Bold Italic';letter-spacing:0px;word-spacing:0px;fill:#ef8200;fill-opacity:1;stroke:none"
|
||||
x="835.56165"
|
||||
y="469.78217"
|
||||
id="text3863"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3865"
|
||||
x="835.56165"
|
||||
y="469.78217"
|
||||
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans Italic';fill:#000000;fill-opacity:1"><tspan
|
||||
style="font-style:normal;-inkscape-font-specification:'Liberation Sans'"
|
||||
id="tspan2999">MATLAB</tspan><tspan
|
||||
style="font-style:italic;font-weight:bold;-inkscape-font-specification:'Liberation Sans Italic'"
|
||||
id="tspan2997">2</tspan></tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="835.56165"
|
||||
y="789.89417"
|
||||
id="tspan3867"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';fill:#ef8200;fill-opacity:1"><tspan
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';fill:#000000"
|
||||
id="tspan3875">Ti</tspan><tspan
|
||||
style="font-style:italic;-inkscape-font-specification:'Liberation Sans Italic'"
|
||||
id="tspan2995">k</tspan><tspan
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';fill:#000000"
|
||||
id="tspan3873">Z</tspan></tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"folders":
|
||||
[
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"build_systems":
|
||||
[
|
||||
{
|
||||
"name": "CI tests (Octave)",
|
||||
"selector": "source.matlab",
|
||||
"working_dir": "${project_path}",
|
||||
"cmd": ["./runtests.sh", "octave"]
|
||||
},
|
||||
{
|
||||
"name": "CI tests (MATLAB)",
|
||||
"selector": "source.matlab",
|
||||
"working_dir": "${project_path}",
|
||||
"cmd": ["./runtests.sh", "matlab"]
|
||||
},
|
||||
{
|
||||
"name": "CI tests (MATLAB HG1)",
|
||||
"selector": "source.matlab",
|
||||
"working_dir": "${project_path}",
|
||||
"cmd": ["./runtests.sh", "matlab-hg1"]
|
||||
},
|
||||
{
|
||||
"name": "CI tests (MATLAB HG2)",
|
||||
"selector": "source.matlab",
|
||||
"working_dir": "${project_path}",
|
||||
"cmd": ["./runtests.sh", "matlab-hg2"]
|
||||
},
|
||||
{
|
||||
"name": "ACID: make",
|
||||
"working_dir": "${project_path}/test/tex",
|
||||
"cmd": ["make","-j8"]
|
||||
},
|
||||
{
|
||||
"name": "ACID: distclean",
|
||||
"working_dir": "${project_path}/test/tex",
|
||||
"cmd": ["make","distclean"]
|
||||
}
|
||||
],
|
||||
"settings":
|
||||
{
|
||||
"FuzzyFilePath":{}
|
||||
}
|
||||
}
|
||||
86
Functions/helper_functions_community/mat2tikz/runtests.sh
Normal file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test script runner for MATLAB2TIKZ continuous integration
|
||||
#
|
||||
# You can influence the execution by passing one or two parameters
|
||||
# to this function, as
|
||||
#
|
||||
# ./runtests.sh RUNNER SWITCHES
|
||||
#
|
||||
# Arguments:
|
||||
# - RUNNER: (path of) the binary you want to use to execute the tests
|
||||
# default value: "octave"
|
||||
# - SWITCHES: switches you want to pass to the executable
|
||||
# default value: * "-nodesktop -r" if runner contains "matlab"
|
||||
# * "--no-gui --eval" if runner contains "octave" and otherwise
|
||||
#
|
||||
|
||||
# Used resources:
|
||||
# - http://askubuntu.com/questions/299710/how-to-determine-if-a-string-is-a-substring-of-another-in-bash
|
||||
# - http://www.thegeekstuff.com/2010/07/bash-case-statement/
|
||||
# - http://stackoverflow.com/questions/229551/string-contains-in-bash
|
||||
# - http://stackoverflow.com/questions/2870992/automatic-exit-from-bash-shell-script-on-error
|
||||
# - http://www.davidpashley.com/articles/writing-robust-shell-scripts/
|
||||
# - http://stackoverflow.com/questions/13998941/how-can-i-propagate-an-exit-status-from-expect-to-its-parent-bash-script
|
||||
# - http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-8.html
|
||||
|
||||
## Make sure some failures are detected by the CI runners
|
||||
function exitIfError {
|
||||
# pass "$?" as argument: i.e. the exit status of the last call
|
||||
if [ "$1" -ne 0 ]; then
|
||||
exit $1;
|
||||
fi
|
||||
}
|
||||
|
||||
## Handle Runner and Switches variables
|
||||
Runner=$1
|
||||
Switches=$2
|
||||
if [ -z "$Runner" ] ; then
|
||||
Runner="octave"
|
||||
fi
|
||||
if [ -z "$Switches" ] ; then
|
||||
case "$Runner" in
|
||||
*matlab* )
|
||||
Switches="-nodesktop -r"
|
||||
;;
|
||||
|
||||
*octave* )
|
||||
Switches="--no-gui --eval"
|
||||
;;
|
||||
|
||||
* )
|
||||
# Fall back to Octave switches
|
||||
Switches="--no-gui --eval"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
## Make sure MATLAB/Octave know the intent
|
||||
# note: the export is required
|
||||
export CONTINUOUS_INTEGRATION=true
|
||||
export CI=true
|
||||
|
||||
## Actually run the test suite
|
||||
cd test
|
||||
TESTDIR=`pwd`
|
||||
# also CD in MATLAB/Octave to make sure that startup files
|
||||
# cannot play any role in setting the path
|
||||
${Runner} ${Switches} "cd('${TESTDIR}'); runMatlab2TikzTests"
|
||||
exitIfError $?
|
||||
cd ..
|
||||
|
||||
## Post-processing
|
||||
|
||||
# convert MD report into HTML using pandoc if available
|
||||
MDFILE="test/results.test.md"
|
||||
if [ ! -z `which pandoc` ]; then
|
||||
if [ -f $MDFILE ]; then
|
||||
HTMLFILE=${MDFILE/md/html}
|
||||
# replace the emoji while we're at it
|
||||
pandoc -f markdown -t html $MDFILE -o $HTMLFILE
|
||||
sed -i -- 's/:heavy_exclamation_mark:/❗️/g' $HTMLFILE
|
||||
sed -i -- 's/:white_check_mark:/✅/g' $HTMLFILE
|
||||
sed -i -- 's/:grey_question:/❔/g' $HTMLFILE
|
||||
fi
|
||||
fi
|
||||
|
||||
1294
Functions/helper_functions_community/mat2tikz/src/cleanfigure.m
Normal file
@@ -0,0 +1,87 @@
|
||||
function formatWhitespace(filename)
|
||||
% FORMATWHITESPACE Formats whitespace and indentation of a document
|
||||
%
|
||||
% FORMATWHITESPACE(FILENAME)
|
||||
% Indents currently active document if FILENAME is empty or not
|
||||
% specified. FILENAME must be the name of an open document in the
|
||||
% editor.
|
||||
%
|
||||
% Rules:
|
||||
% - Smart-indent with all function indent option
|
||||
% - Indentation is 4 spaces
|
||||
% - Remove whitespace in empty lines
|
||||
% - Preserve indentantion after line continuations, i.e. ...
|
||||
%
|
||||
import matlab.desktop.editor.*
|
||||
|
||||
if nargin < 1, filename = ''; end
|
||||
|
||||
d = getDoc(filename);
|
||||
oldLines = textToLines(d.Text);
|
||||
|
||||
% Smart indent as AllFunctionIndent
|
||||
% Using undocumented feature from http://undocumentedmatlab.com/blog/changing-system-preferences-programmatically
|
||||
editorProp = 'EditorMFunctionIndentType';
|
||||
oldVal = com.mathworks.services.Prefs.getStringPref(editorProp);
|
||||
com.mathworks.services.Prefs.setStringPref(editorProp, 'AllFunctionIndent');
|
||||
restoreSettings = onCleanup(@() com.mathworks.services.Prefs.setStringPref(editorProp, oldVal));
|
||||
d.smartIndentContents()
|
||||
|
||||
% Preserve crafted continuations of line
|
||||
lines = textToLines(d.Text);
|
||||
iContinuation = ~cellfun('isempty',strfind(lines, '...'));
|
||||
iComment = ~cellfun('isempty',regexp(lines, '^ *%([^%]|$)','once'));
|
||||
pAfterDots = find(iContinuation & ~iComment)+1;
|
||||
for ii = 1:numel(pAfterDots)
|
||||
% Carry over the change in space due to smart-indenting from the
|
||||
% first continuation line to the last
|
||||
p = pAfterDots(ii);
|
||||
nWhiteBefore = find(~isspace(oldLines{p-1}),1,'first');
|
||||
nWhiteAfter = find(~isspace(lines{p-1}),1,'first');
|
||||
df = nWhiteAfter - nWhiteBefore;
|
||||
if df > 0
|
||||
lines{p} = [blanks(df) oldLines{p}];
|
||||
elseif df < 0
|
||||
df = min(abs(df)+1, find(~isspace(oldLines{p}),1,'first'));
|
||||
lines{p} = oldLines{p}(df:end);
|
||||
else
|
||||
lines{p} = oldLines{p};
|
||||
end
|
||||
end
|
||||
|
||||
% Remove whitespace lines
|
||||
idx = cellfun('isempty',regexp(lines, '[^ \t\n]','once'));
|
||||
lines(idx) = {''};
|
||||
|
||||
d.Text = linesToText(lines);
|
||||
end
|
||||
|
||||
function d = getDoc(filename)
|
||||
import matlab.desktop.editor.*
|
||||
|
||||
if ~ischar(filename)
|
||||
error('formatWhitespace:charFilename','The FILENAME should be a char.')
|
||||
end
|
||||
|
||||
try
|
||||
isEditorAvailable();
|
||||
catch
|
||||
error('formatWhitespace:noEditorApi','Check that the Editor API is available.')
|
||||
end
|
||||
|
||||
if isempty(filename)
|
||||
d = getActive();
|
||||
else
|
||||
% TODO: open file if it isn't open in the editor already
|
||||
d = findOpenDocument(filename);
|
||||
try
|
||||
[~,filenameFound] = fileparts(d.Filename);
|
||||
catch
|
||||
filenameFound = '';
|
||||
end
|
||||
isExactMatch = strcmp(filename, filenameFound);
|
||||
if ~isExactMatch
|
||||
error('formatWhitespace:filenameNotFound','Filename "%s" not found in the editor.', filename)
|
||||
end
|
||||
end
|
||||
end
|
||||
123
Functions/helper_functions_community/mat2tikz/src/figure2dot.m
Normal file
@@ -0,0 +1,123 @@
|
||||
function figure2dot(filename, varargin)
|
||||
%FIGURE2DOT Save figure in Graphviz (.dot) file.
|
||||
% FIGURE2DOT(filename) saves the current figure as dot-file.
|
||||
%
|
||||
% FIGURE2DOT(filename, 'object', HGOBJECT) constructs the graph representation
|
||||
% of the specified object (default: gcf)
|
||||
%
|
||||
% You can visualize the constructed DOT file using:
|
||||
% - [GraphViz](http://www.graphviz.org) on your computer
|
||||
% - [WebGraphViz](http://www.webgraphviz.com) online
|
||||
% - [Gravizo](http://www.gravizo.com) for your markdown files
|
||||
% - and a lot of other software such as OmniGraffle
|
||||
%
|
||||
% See also: matlab2tikz, cleanfigure, uiinspect, inspect
|
||||
|
||||
ipp = m2tInputParser();
|
||||
ipp = ipp.addRequired(ipp, 'filename', @ischar);
|
||||
ipp = ipp.addParamValue(ipp, 'object', gcf, @ishghandle);
|
||||
ipp = ipp.parse(ipp, filename, varargin{:});
|
||||
args = ipp.Results;
|
||||
|
||||
filehandle = fopen(args.filename, 'w');
|
||||
finally_fclose_filehandle = onCleanup(@() fclose(filehandle));
|
||||
|
||||
% start printing
|
||||
fprintf(filehandle, 'digraph simple_hierarchy {\n\n');
|
||||
fprintf(filehandle, 'node[shape=box];\n\n');
|
||||
|
||||
% define the root node
|
||||
node_number = 0;
|
||||
p = get(args.object, 'Parent');
|
||||
% define root element
|
||||
type = get(p, 'Type');
|
||||
fprintf(filehandle, 'N%d [label="%s"]\n\n', node_number, type);
|
||||
|
||||
% start recursion
|
||||
plot_children(filehandle, p, node_number);
|
||||
|
||||
% finish off
|
||||
fprintf(filehandle, '}');
|
||||
|
||||
% ----------------------------------------------------------------------------
|
||||
function plot_children(fh, h, parent_node)
|
||||
|
||||
children = allchild(h);
|
||||
|
||||
for h = children(:)'
|
||||
if shouldSkip(h), continue, end;
|
||||
node_number = node_number + 1;
|
||||
|
||||
label = {};
|
||||
label = addHGProperty(label, h, 'Type', '');
|
||||
try
|
||||
hClass = class(handle(h));
|
||||
label = addProperty(label, 'Class', hClass);
|
||||
catch
|
||||
% don't do anything
|
||||
end
|
||||
label = addProperty(label, 'Handle', sprintf('%g', double(h)));
|
||||
label = addHGProperty(label, h, 'Title', '');
|
||||
label = addHGProperty(label, h, 'Axes', []);
|
||||
label = addHGProperty(label, h, 'String', '');
|
||||
label = addHGProperty(label, h, 'Tag', '');
|
||||
label = addHGProperty(label, h, 'DisplayName', '');
|
||||
label = addHGProperty(label, h, 'Visible', 'on');
|
||||
label = addHGProperty(label, h, 'HandleVisibility', 'on');
|
||||
|
||||
% print node
|
||||
fprintf(fh, 'N%d [label="%s"]\n', ...
|
||||
node_number, m2tstrjoin(label, '\n'));
|
||||
|
||||
% connect to the child
|
||||
fprintf(fh, 'N%d -> N%d;\n\n', parent_node, node_number);
|
||||
|
||||
% recurse
|
||||
plot_children(fh, h, node_number);
|
||||
end
|
||||
end
|
||||
end
|
||||
% ==============================================================================
|
||||
function bool = shouldSkip(h)
|
||||
% returns TRUE for objects that can be skipped
|
||||
objType = get(h, 'Type');
|
||||
bool = ismember(lower(objType), guitypes());
|
||||
end
|
||||
% ==============================================================================
|
||||
function label = addHGProperty(label, h, propName, default)
|
||||
% get a HG property and assign it to a GraphViz node label
|
||||
if ~exist('default','var') || isempty(default)
|
||||
shouldOmit = @isempty;
|
||||
elseif isa(default, 'function_handle')
|
||||
shouldOmit = default;
|
||||
else
|
||||
shouldOmit = @(v) isequal(v,default);
|
||||
end
|
||||
|
||||
if isprop(h, propName)
|
||||
propValue = get(h, propName);
|
||||
if numel(propValue) == 1 && ishghandle(propValue) && isprop(propValue, 'String')
|
||||
% dereference Titles, labels, ...
|
||||
propValue = get(propValue, 'String');
|
||||
elseif ishghandle(propValue)
|
||||
% dereference other HG objects to their raw handle value (double)
|
||||
propValue = double(propValue);
|
||||
elseif iscell(propValue)
|
||||
propValue = ['{' m2tstrjoin(propValue,',') '}'];
|
||||
end
|
||||
|
||||
if ~shouldOmit(propValue)
|
||||
label = addProperty(label, propName, propValue);
|
||||
end
|
||||
end
|
||||
end
|
||||
function label = addProperty(label, propName, propValue)
|
||||
% add a property to a GraphViz node label
|
||||
if isnumeric(propValue)
|
||||
propValue = num2str(propValue);
|
||||
elseif iscell(propValue)
|
||||
propValue = m2tstrjoin(propValue,sprintf('\n'));
|
||||
end
|
||||
label = [label, sprintf('%s: %s', propName, propValue)];
|
||||
end
|
||||
% ==============================================================================
|
||||
@@ -0,0 +1,231 @@
|
||||
function parser = m2tInputParser()
|
||||
%MATLAB2TIKZINPUTPARSER Input parsing for matlab2tikz.
|
||||
% This implementation exists because Octave is lacking one.
|
||||
|
||||
% Initialize the structure.
|
||||
parser = struct ();
|
||||
% Public Properties
|
||||
parser.Results = {};
|
||||
% Enabel/disable parameters case sensitivity.
|
||||
parser.CaseSensitive = false;
|
||||
% Keep parameters not defined by the constructor.
|
||||
parser.KeepUnmatched = false;
|
||||
% Enable/disable warning for parameters not defined by the constructor.
|
||||
parser.WarnUnmatched = true;
|
||||
% Enable/disable passing arguments in a structure.
|
||||
parser.StructExpand = true;
|
||||
% Names of parameters defined in input parser constructor.
|
||||
parser.Parameters = {};
|
||||
% Names of parameters not defined in the constructor.
|
||||
parser.Unmatched = struct ();
|
||||
% Names of parameters using default values.
|
||||
parser.UsingDefaults = {};
|
||||
% Names of deprecated parameters and their alternatives
|
||||
parser.DeprecatedParameters = struct();
|
||||
|
||||
% Handles for functions that act on the object.
|
||||
parser.addRequired = @addRequired;
|
||||
parser.addOptional = @addOptional;
|
||||
parser.addParamValue = @addParamValue;
|
||||
parser.deprecateParam = @deprecateParam;
|
||||
parser.parse = @parse;
|
||||
|
||||
% Initialize the parser plan
|
||||
parser.plan = {};
|
||||
end
|
||||
% =========================================================================
|
||||
function p = parser_plan (q, arg_type, name, default, validator)
|
||||
p = q;
|
||||
plan = p.plan;
|
||||
if (isempty (plan))
|
||||
plan = struct ();
|
||||
n = 1;
|
||||
else
|
||||
n = numel (plan) + 1;
|
||||
end
|
||||
plan(n).type = arg_type;
|
||||
plan(n).name = name;
|
||||
plan(n).default = default;
|
||||
plan(n).validator = validator;
|
||||
p.plan = plan;
|
||||
end
|
||||
% =========================================================================
|
||||
function p = addRequired (p, name, validator)
|
||||
p = parser_plan (p, 'required', name, [], validator);
|
||||
end
|
||||
% =========================================================================
|
||||
function p = addOptional (p, name, default, validator)
|
||||
p = parser_plan (p, 'optional', name, default, validator);
|
||||
end
|
||||
% =========================================================================
|
||||
function p = addParamValue (p, name, default, validator)
|
||||
p = parser_plan (p, 'paramvalue', name, default, validator);
|
||||
end
|
||||
% =========================================================================
|
||||
function p = deprecateParam (p, name, alternatives)
|
||||
if isempty(alternatives)
|
||||
alternatives = {};
|
||||
elseif ischar(alternatives)
|
||||
alternatives = {alternatives}; % make cellstr
|
||||
elseif ~iscellstr(alternatives)
|
||||
error('m2tInputParser:BadAlternatives',...
|
||||
'Alternatives for a deprecated parameter must be a char or cellstr');
|
||||
end
|
||||
p.DeprecatedParameters.(name) = alternatives;
|
||||
end
|
||||
% =========================================================================
|
||||
function p = parse (p, varargin)
|
||||
plan = p.plan;
|
||||
results = p.Results;
|
||||
using_defaults = {};
|
||||
if (p.CaseSensitive)
|
||||
name_cmp = @strcmp;
|
||||
else
|
||||
name_cmp = @strcmpi;
|
||||
end
|
||||
if (p.StructExpand)
|
||||
k = find (cellfun (@isstruct, varargin));
|
||||
for m = numel(k):-1:1
|
||||
n = k(m);
|
||||
s = varargin{n};
|
||||
c = [fieldnames(s).'; struct2cell(s).'];
|
||||
c = c(:).';
|
||||
if (n > 1 && n < numel (varargin))
|
||||
varargin = horzcat (varargin(1:n-1), c, varargin(n+1:end));
|
||||
elseif (numel (varargin) == 1)
|
||||
varargin = c;
|
||||
elseif (n == 1);
|
||||
varargin = horzcat (c, varargin(n+1:end));
|
||||
else % n == numel (varargin)
|
||||
varargin = horzcat (varargin(1:n-1), c);
|
||||
end
|
||||
end
|
||||
end
|
||||
if (isempty (results))
|
||||
results = struct ();
|
||||
end
|
||||
type = {plan.type};
|
||||
n = find( strcmp( type, 'paramvalue' ) );
|
||||
m = setdiff (1:numel( plan ), n );
|
||||
plan = plan ([n,m]);
|
||||
for n = 1 : numel (plan)
|
||||
found = false;
|
||||
results.(plan(n).name) = plan(n).default;
|
||||
if (~ isempty (varargin))
|
||||
switch plan(n).type
|
||||
case 'required'
|
||||
found = true;
|
||||
if (strcmpi (varargin{1}, plan(n).name))
|
||||
varargin(1) = [];
|
||||
end
|
||||
value = varargin{1};
|
||||
varargin(1) = [];
|
||||
case 'optional'
|
||||
m = find (cellfun (@ischar, varargin));
|
||||
k = find (name_cmp (plan(n).name, varargin(m)));
|
||||
if (isempty (k) && validate_arg (plan(n).validator, varargin{1}))
|
||||
found = true;
|
||||
value = varargin{1};
|
||||
varargin(1) = [];
|
||||
elseif (~ isempty (k))
|
||||
m = m(k);
|
||||
found = true;
|
||||
value = varargin{max(m)+1};
|
||||
varargin(union(m,m+1)) = [];
|
||||
end
|
||||
case 'paramvalue'
|
||||
m = find( cellfun (@ischar, varargin) );
|
||||
k = find (name_cmp (plan(n).name, varargin(m)));
|
||||
if (~ isempty (k))
|
||||
found = true;
|
||||
m = m(k);
|
||||
value = varargin{max(m)+1};
|
||||
varargin(union(m,m+1)) = [];
|
||||
end
|
||||
otherwise
|
||||
error( sprintf ('%s:parse', mfilename), ...
|
||||
'parse (%s): Invalid argument type.', mfilename ...
|
||||
)
|
||||
end
|
||||
end
|
||||
if (found)
|
||||
if (validate_arg (plan(n).validator, value))
|
||||
results.(plan(n).name) = value;
|
||||
else
|
||||
error( sprintf ('%s:invalidinput', mfilename), ...
|
||||
'%s: Input argument ''%s'' has invalid value.\n', mfilename, plan(n).name ...
|
||||
);
|
||||
end
|
||||
p.Parameters = union (p.Parameters, {plan(n).name});
|
||||
elseif (strcmp (plan(n).type, 'required'))
|
||||
error( sprintf ('%s:missinginput', mfilename), ...
|
||||
'%s: input ''%s'' is missing.\n', mfilename, plan(n).name ...
|
||||
);
|
||||
else
|
||||
using_defaults = union (using_defaults, {plan(n).name});
|
||||
end
|
||||
end
|
||||
|
||||
if ~isempty(varargin)
|
||||
% Include properties that do not match specified properties
|
||||
for n = 1:2:numel(varargin)
|
||||
if ischar(varargin{n})
|
||||
if p.KeepUnmatched
|
||||
results.(varargin{n}) = varargin{n+1};
|
||||
end
|
||||
if p.WarnUnmatched
|
||||
warning(sprintf('%s:unmatchedArgument',mfilename), ...
|
||||
'Ignoring unknown argument "%s"', varargin{n});
|
||||
end
|
||||
p.Unmatched.(varargin{n}) = varargin{n+1};
|
||||
else
|
||||
error (sprintf ('%s:invalidinput', mfilename), ...
|
||||
'%s: invalid input', mfilename)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
% Store the results of the parsing
|
||||
p.Results = results;
|
||||
p.UsingDefaults = using_defaults;
|
||||
|
||||
warnForDeprecatedParameters(p);
|
||||
end
|
||||
% =========================================================================
|
||||
function result = validate_arg (validator, arg)
|
||||
try
|
||||
result = validator (arg);
|
||||
catch %#ok
|
||||
result = false;
|
||||
end
|
||||
end
|
||||
% =========================================================================
|
||||
function warnForDeprecatedParameters(p)
|
||||
usedDeprecatedParameters = intersect(p.Parameters, fieldnames(p.DeprecatedParameters));
|
||||
|
||||
for iParam = 1:numel(usedDeprecatedParameters)
|
||||
oldParameter = usedDeprecatedParameters{iParam};
|
||||
alternatives = p.DeprecatedParameters.(oldParameter);
|
||||
|
||||
switch numel(alternatives)
|
||||
case 0
|
||||
replacements = '';
|
||||
case 1
|
||||
replacements = ['''' alternatives{1} ''''];
|
||||
otherwise
|
||||
replacements = deblank(sprintf('''%s'' and ',alternatives{:}));
|
||||
replacements = regexprep(replacements,' and$','');
|
||||
end
|
||||
if ~isempty(replacements)
|
||||
replacements = sprintf('From now on, please use %s to control the output.\n',replacements);
|
||||
end
|
||||
|
||||
message = ['\n===============================================================================\n', ...
|
||||
'You are using the deprecated parameter ''%s''.\n', ...
|
||||
'%s', ...
|
||||
'==============================================================================='];
|
||||
warning('matlab2tikz:deprecatedParameter', ...
|
||||
message, oldParameter, replacements);
|
||||
|
||||
end
|
||||
end
|
||||
216
Functions/helper_functions_community/mat2tikz/src/m2tcustom.m
Normal file
@@ -0,0 +1,216 @@
|
||||
function [value] = m2tcustom(handle, varargin)
|
||||
% M2TCUSTOM creates user-defined options for matlab2tikz output
|
||||
%
|
||||
% M2TCUSTOM can be used to create, get and set a properly formatted data
|
||||
% structure to customize the conversion of MATLAB figures to TikZ using
|
||||
% matlab2tikz. In particular, it allows to:
|
||||
%
|
||||
% * add blocks of LaTeX/TikZ code around any HG object,
|
||||
% * add blocks of comments around any HG object,
|
||||
% * add TikZ options to any HG object,
|
||||
% * add LaTeX/TikZ code inside some HG objects (e.g. axes),
|
||||
% * provide a custom handler to convert a particular HG object.
|
||||
%
|
||||
% Note that this provides advanced functionality. Only very basic
|
||||
% sanity checks are performed such that injudicious use may produce
|
||||
% broken TikZ figures!
|
||||
%
|
||||
% It is HIGHLY recommended that you are comfortable with:
|
||||
%
|
||||
% * writing pgfplots, TikZ and LaTeX code,
|
||||
% * using the Handle Graphics (HG) framework in MATLAB/Octave, and
|
||||
% * the inner working of matlab2tikz (for custom handlers)
|
||||
%
|
||||
% when you use this function. I.e. you should know what you are doing.
|
||||
%
|
||||
%
|
||||
% Usage as a GETTER:
|
||||
% ------------------
|
||||
%
|
||||
% value = M2TCUSTOM(handle)
|
||||
% retrieves the current custom data structure from the HG object "handle"
|
||||
%
|
||||
%
|
||||
% Usage as a SETTER:
|
||||
% ------------------
|
||||
%
|
||||
% M2TCUSTOM(handle, ...)
|
||||
% value = M2TCUSTOM(handle, ...)
|
||||
% will construct the proper data structure and try to set it to the object
|
||||
% |handle| if possible. The arguments (see below) are specified in
|
||||
% key-value pairs akin to a normal |struct|, but here we do a few checks
|
||||
% and data normalization.
|
||||
%
|
||||
% If we denote BLOCK to mean either a |char| or a |cellstr|, the following
|
||||
% options can be passed. Different entries in a cellstr are assumed
|
||||
% separated by a newline. The default values are empty.
|
||||
%
|
||||
% M2TCUSTOM(handle, 'commentBefore', BLOCK, ...)
|
||||
% M2TCUSTOM(handle, 'commentAfter' , BLOCK, ...)
|
||||
% to add comments before/after the object. Our code translates newlines
|
||||
% and adds the percentage signs for you.
|
||||
%
|
||||
% M2TCUSTOM(handle, 'codeBefore', BLOCK, ...)
|
||||
% M2TCUSTOM(handle, 'codeAfter', BLOCK, ...)
|
||||
% M2TCUSTOM(handle, 'codeInsideFirst', BLOCK, ...)
|
||||
% M2TCUSTOM(handle, 'codeInsideLast', BLOCK, ...)
|
||||
% to add raw LaTeX/TikZ code respectively before, after, as first thing
|
||||
% inside or as last thing inside the pgfplots representation of the object.
|
||||
% Note that for some HG objects, (e.g. line objects), |codeInsideFirst|
|
||||
% and |codeInsideLast| do not make any sense and are hence ignored.
|
||||
%
|
||||
% M2TCUSTOM(handle, 'extraOptions', OPTIONS, ...)
|
||||
% adds extra pgfplots/TikZ options to the end of the option list. Here,
|
||||
% OPTIONS is properly formatted TikZ code in
|
||||
% - a |char| (e.g. 'color=red, line width=1pt' )
|
||||
% - a |cellstr| (e.g. {'color=red','line width=1pt'})
|
||||
%
|
||||
% M2TCUSTOM(handle, 'customHandler', FUNCTION_HANDLE, ...)
|
||||
% allows you to replace the default matlab2tikz handler for this object.
|
||||
% This is not for the faint of heart and requires intimate knowledge of
|
||||
% the matlab2tikz code base! We expect a function (either as |char| or
|
||||
% function handle) that will be called as
|
||||
%
|
||||
% [m2t, str] = feval(handler, m2t, handle, custom)
|
||||
%
|
||||
% such that the expected function signature is:
|
||||
%
|
||||
% function [m2t, str] = handler(m2t, handle, custom)
|
||||
%
|
||||
% where |m2t| is an undocumented/unstable data structure,
|
||||
% |str| is a char containing TikZ code representing the
|
||||
% HG object |handle| as generated by your handler,
|
||||
% |custom| is a structure as returned by |m2tcustom|
|
||||
% from which you only need to handle |extraOptions|,
|
||||
% |codeInsideFirst| and |codeInsideLast| when applicable.
|
||||
% A particularly useful value for |customHandler| is 'drawNothing',
|
||||
% which remove the object from the output.
|
||||
%
|
||||
%
|
||||
% Example:
|
||||
% --------
|
||||
%
|
||||
% Executing the following MATLAB code fragment:
|
||||
%
|
||||
% figure;
|
||||
% plot(1:10);
|
||||
% EOL = sprintf('\n');
|
||||
% m2tCustom(gca, 'codeBefore' , ['<codeBefore>' EOL] , ...
|
||||
% 'codeAfter' , ['<codeAfter>' EOL] , ...
|
||||
% 'commentsBefore' , '<commentsBefore>' , ...
|
||||
% 'commentsAfter' , '<commentsAfter>' , ...
|
||||
% 'codeInsideFirst' , ['<codeInsideFirst>' EOL], ...
|
||||
% 'codeInsideLast' , ['<codeInsideLast>' EOL], ...
|
||||
% 'extraOptions' , '<extraOptions>');
|
||||
%
|
||||
% matlab2tikz('test.tikz')
|
||||
%
|
||||
% Should result in a |test.tikz| file with contents that look somewhat
|
||||
% like this:
|
||||
%
|
||||
% \begin{tikzpicture}
|
||||
% %<commentsBefore>
|
||||
% <codeBefore>
|
||||
% \begin{axis}[..., <extraOptions>]
|
||||
% <codeInsideFirst>
|
||||
% \addplot{...};
|
||||
% <codeInsideLast>
|
||||
% \end{axis}
|
||||
% %<commentsAfter>
|
||||
% <codeAfter>
|
||||
% \end{tikzpicture}
|
||||
%
|
||||
% See also: matlab2tikz, setappdata, getappdata
|
||||
|
||||
%% arguments specific to this constructor function
|
||||
ipp = m2tInputParser();
|
||||
ipp = ipp.addRequired(ipp, 'handle', @isHgObject);
|
||||
|
||||
%% Declaration of the custom data structure
|
||||
ipp = ipp.addParamValue(ipp, 'codeBefore', '', @isCellstrOrChar);
|
||||
ipp = ipp.addParamValue(ipp, 'codeAfter', '', @isCellstrOrChar);
|
||||
|
||||
ipp = ipp.addParamValue(ipp, 'commentsBefore', '', @isCellstrOrChar);
|
||||
ipp = ipp.addParamValue(ipp, 'commentsAfter', '', @isCellstrOrChar);
|
||||
|
||||
ipp = ipp.addParamValue(ipp, 'codeInsideFirst', '', @isCellstrOrChar);
|
||||
ipp = ipp.addParamValue(ipp, 'codeInsideLast', '', @isCellstrOrChar);
|
||||
|
||||
ipp = ipp.addParamValue(ipp, 'extraOptions', '', @isCellstrOrChar);
|
||||
ipp = ipp.addParamValue(ipp, 'customHandler', '', @isHandler);
|
||||
|
||||
%% Parse the arguments
|
||||
ipp = ipp.parse(ipp, handle, varargin{:});
|
||||
|
||||
%% Construct custom data structure
|
||||
% We leverage the results from the input parser. It provides us
|
||||
% with validation already. We just need to remove bookkeeping fields
|
||||
value = ipp.Results;
|
||||
value = rmfield(value, {'handle'});
|
||||
|
||||
%% Normalize the actual values
|
||||
value.codeBefore = cellstr2char(value.codeBefore);
|
||||
value.codeAfter = cellstr2char(value.codeAfter);
|
||||
value.codeInsideFirst = cellstr2char(value.codeInsideFirst);
|
||||
value.codeInsideLast = cellstr2char(value.codeInsideLast);
|
||||
value.commentsBefore = cellstr2char(value.commentsBefore);
|
||||
value.commentsAfter = cellstr2char(value.commentsAfter);
|
||||
if isempty(value.customHandler)
|
||||
value = rmfield(value, 'customHandler');
|
||||
end
|
||||
% extraOptions gets normalized by |opts_append_userdefined|
|
||||
|
||||
%% Different Usage modes
|
||||
MATLAB2TIKZ = 'matlab2tikz'; % key used for application data storage
|
||||
if numel(varargin) == 0
|
||||
%% GETTER MODE
|
||||
% syntax: value = m2tcustom(h);
|
||||
if ~isempty(handle)
|
||||
object = getappdata(handle, MATLAB2TIKZ);
|
||||
else
|
||||
object = [];
|
||||
end
|
||||
if ~isempty(object)
|
||||
value = object;
|
||||
else
|
||||
% |value| contains all default (empty) values
|
||||
end
|
||||
else
|
||||
%% SETTER MODE
|
||||
% syntax: m2tcustom(h , key1, val1, ...)
|
||||
% syntax: value = m2tcustom([], key1, val1, ...)
|
||||
if ~isempty(handle)
|
||||
setappdata(handle, MATLAB2TIKZ, value);
|
||||
end
|
||||
end
|
||||
end
|
||||
% == INPUT VALIDATORS ==========================================================
|
||||
function bool = isHgObject(value)
|
||||
% true for HG object or empty (or numeric for backwards compatibility)
|
||||
bool = isempty(value) || ishghandle(value) || isnumeric(value);
|
||||
end
|
||||
function bool = isCellstrOrChar(value)
|
||||
% true for cellstr or char
|
||||
bool = ischar(value) || iscellstr(value);
|
||||
end
|
||||
function bool = isHandler(value)
|
||||
% true for char or function handle of the form [m2t, str] = f(m2t, h, opts)
|
||||
bool = isempty(value) || ischar(value) || ...
|
||||
(isa(value, 'function_handle') && ...
|
||||
atLeastOrUnknown(nargin(value), 3) && ...
|
||||
atLeastOrUnknown(nargout(value), 2));
|
||||
end
|
||||
function bool = atLeastOrUnknown(nargs, limit)
|
||||
% checks for |nargin| and |nargout| >= |limit| (or equal to -1)
|
||||
UNKNOWN = -1;
|
||||
bool = (nargs == UNKNOWN) || nargs >= limit;
|
||||
end
|
||||
% == FIELD NORMALIZATION =======================================================
|
||||
function value = cellstr2char(value)
|
||||
% convert cellstr to char (and keep char unaffected)
|
||||
if iscellstr(value)
|
||||
EOL = sprintf('\n');
|
||||
value = m2tstrjoin(value, EOL);
|
||||
end
|
||||
end
|
||||
% ==============================================================================
|
||||
7167
Functions/helper_functions_community/mat2tikz/src/matlab2tikz.m
Normal file
@@ -0,0 +1,5 @@
|
||||
function errorUnknownEnvironment()
|
||||
% Throw an error to indicate an unknwon environment (i.e. not MATLAB/Octave).
|
||||
error('matlab2tikz:unknownEnvironment',...
|
||||
'Unknown environment "%s". Need MATLAB(R) or Octave.', getEnvironment);
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
function [env, versionString] = getEnvironment()
|
||||
% Determine environment (Octave, MATLAB) and version string
|
||||
% TODO: Unify private `getEnvironment` functions
|
||||
persistent cache
|
||||
|
||||
if isempty(cache)
|
||||
isOctave = exist('OCTAVE_VERSION', 'builtin') ~= 0;
|
||||
if isOctave
|
||||
env = 'Octave';
|
||||
versionString = OCTAVE_VERSION;
|
||||
else
|
||||
env = 'MATLAB';
|
||||
vData = ver(env);
|
||||
versionString = vData.Version;
|
||||
end
|
||||
|
||||
% store in cache
|
||||
cache.env = env;
|
||||
cache.versionString = versionString;
|
||||
|
||||
else
|
||||
env = cache.env;
|
||||
versionString = cache.versionString;
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
function types = guitypes()
|
||||
% GUITYPES returns a cell array of MATLAB/Octave GUI object types
|
||||
%
|
||||
% Syntax
|
||||
% types = guitypes()
|
||||
%
|
||||
% These types are ignored by matlab2tikz and figure2dot.
|
||||
%
|
||||
% See also: matlab2tikz, figure2dot
|
||||
|
||||
types = {'uitoolbar', 'uimenu', 'uicontextmenu', 'uitoggletool',...
|
||||
'uitogglesplittool', 'uipushtool', 'hgjavacomponent',...
|
||||
'matlab.graphics.shape.internal.Button', ...
|
||||
'matlab.ui.controls.ToolbarPushButton', ...
|
||||
'matlab.ui.controls.ToolbarStateButton', ...
|
||||
'matlab.ui.controls.ToolbarDropdown', ...
|
||||
'matlab.ui.controls.AxesToolbar', ...
|
||||
};
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
function bool = isAxis3D(axisHandle)
|
||||
% Check if elevation is not orthogonal to xy plane
|
||||
axisView = get(axisHandle,'view');
|
||||
bool = ~ismember(axisView(2),[90,-90]);
|
||||
end
|
||||
@@ -0,0 +1,13 @@
|
||||
function isBelow = isVersionBelow(versionA, versionB)
|
||||
% Checks if versionA is smaller than versionB
|
||||
vA = versionArray(versionA);
|
||||
vB = versionArray(versionB);
|
||||
n = min(length(vA), length(vB));
|
||||
deltaAB = vA(1:n) - vB(1:n);
|
||||
difference = find(deltaAB, 1, 'first');
|
||||
if isempty(difference)
|
||||
isBelow = false; % equal versions
|
||||
else
|
||||
isBelow = (deltaAB(difference) < 0);
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,320 @@
|
||||
function m2tUpdater(about, verbose)
|
||||
%UPDATER Auto-update matlab2tikz.
|
||||
% Only for internal usage.
|
||||
|
||||
% Copyright (c) 2012--2014, Nico Schlömer <nico.schloemer@gmail.com>
|
||||
% All rights reserved.
|
||||
%
|
||||
% Redistribution and use in source and binary forms, with or without
|
||||
% modification, are permitted provided that the following conditions are
|
||||
% met:
|
||||
%
|
||||
% * Redistributions of source code must retain the above copyright
|
||||
% notice, this list of conditions and the following disclaimer.
|
||||
% * Redistributions in binary form must reproduce the above copyright
|
||||
% notice, this list of conditions and the following disclaimer in
|
||||
% the documentation and/or other materials provided with the distribution
|
||||
%
|
||||
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
% POSSIBILITY OF SUCH DAMAGE.
|
||||
% =========================================================================
|
||||
fileExchangeUrl = about.website;
|
||||
version = about.version;
|
||||
|
||||
mostRecentVersion = determineLatestRelease(version, fileExchangeUrl);
|
||||
if askToUpgrade(mostRecentVersion, version, verbose)
|
||||
tryToUpgrade(fileExchangeUrl, verbose);
|
||||
userInfo(verbose, '');
|
||||
end
|
||||
end
|
||||
% ==============================================================================
|
||||
function shouldUpgrade = askToUpgrade(mostRecentVersion, version, verbose)
|
||||
shouldUpgrade = false;
|
||||
if ~isempty(mostRecentVersion)
|
||||
userInfo(verbose, '**********************************************\n');
|
||||
userInfo(verbose, 'New version (%s) available!\n', mostRecentVersion);
|
||||
userInfo(verbose, '**********************************************\n');
|
||||
|
||||
warnAboutUpgradeImplications(version, mostRecentVersion, verbose);
|
||||
askToShowChangelog(version);
|
||||
reply = input(' *** Would you like to upgrade? y/n [n]:','s');
|
||||
shouldUpgrade = ~isempty(reply) && strcmpi(reply(1),'y');
|
||||
if ~shouldUpgrade
|
||||
userInfo(verbose, ['\nTo disable the self-updater in the future, add ' ...
|
||||
'"''checkForUpdates'',false" to the parameters.\n'] );
|
||||
end
|
||||
end
|
||||
end
|
||||
% ==============================================================================
|
||||
function tryToUpgrade(fileExchangeUrl, verbose)
|
||||
% Download the files and unzip its contents into two folders
|
||||
% above the folder that contains the current script.
|
||||
% This assumes that the file structure is something like
|
||||
%
|
||||
% src/matlab2tikz.m
|
||||
% src/[...]
|
||||
% src/private/m2tUpdater
|
||||
% src/private/[...]
|
||||
% AUTHORS
|
||||
% ChangeLog
|
||||
% [...]
|
||||
%
|
||||
% on the hard drive and the zip file. In particular, this assumes
|
||||
% that the folder on the hard drive is writable by the user
|
||||
% and that matlab2tikz.m is not symlinked from some other place.
|
||||
pathstr = fileparts(mfilename('fullpath'));
|
||||
targetPath = fullfile(pathstr, '..', '..');
|
||||
|
||||
% Let the user know where the .zip is downloaded to
|
||||
userInfo(verbose, 'Downloading and unzipping to ''%s'' ...', targetPath);
|
||||
|
||||
% Try upgrading
|
||||
try
|
||||
% List current folder structure. Will use last for cleanup
|
||||
currentFolderFiles = rdirfiles(targetPath);
|
||||
|
||||
% The FEX now forwards the download request to Github.
|
||||
% Go through the forwarding to update the download count and
|
||||
% unzip
|
||||
html = urlread([fileExchangeUrl, '?download=true']);
|
||||
expression = '(?<=\<a href=")[\w\-\/:\.]+(?=">redirected)';
|
||||
url = regexp(html, expression,'match','once');
|
||||
unzippedFiles = unzip(url, targetPath);
|
||||
|
||||
% The folder structure is additionally packed into the
|
||||
% 'MATLAB Search Path' folder defined in FEX. Retrieve the
|
||||
% top folder name
|
||||
tmp = strrep(unzippedFiles,[targetPath, filesep],'');
|
||||
tmp = regexp(tmp, filesep,'split','once');
|
||||
tmp = cat(1,tmp{:});
|
||||
topZipFolder = unique(tmp(:,1));
|
||||
|
||||
% If packed into the top folder, overwrite files into m2t
|
||||
% main directory
|
||||
if numel(topZipFolder) == 1
|
||||
unzippedFilesTarget = fullfile(targetPath, tmp(:,2));
|
||||
for ii = 1:numel(unzippedFiles)
|
||||
movefile(unzippedFiles{ii}, unzippedFilesTarget{ii})
|
||||
end
|
||||
% Add topZipFolder to current folder structure
|
||||
currentFolderFiles = [currentFolderFiles; fullfile(targetPath, topZipFolder{1})];
|
||||
end
|
||||
|
||||
cleanupOldFiles(currentFolderFiles, unzippedFilesTarget);
|
||||
|
||||
userInfo(verbose, 'Upgrade has completed successfully.');
|
||||
catch
|
||||
err = lasterror(); %#ok needed for Octave
|
||||
|
||||
userInfo(verbose, ...
|
||||
['Upgrade has failed with error message "%s".\n', ...
|
||||
'Please install the latest version manually from %s !'], ...
|
||||
err.message, fileExchangeUrl);
|
||||
end
|
||||
end
|
||||
% ==============================================================================
|
||||
function cleanupOldFiles(currentFolderFiles, unzippedFilesTarget)
|
||||
% Delete files that were there in the old folder, but that are no longer
|
||||
% present in the new release.
|
||||
newFolderStructure = [getFolders(unzippedFilesTarget); unzippedFilesTarget];
|
||||
deleteFolderFiles = setdiff(currentFolderFiles, newFolderStructure);
|
||||
for ii = 1:numel(deleteFolderFiles)
|
||||
x = deleteFolderFiles{ii};
|
||||
if exist(x, 'dir') == 7
|
||||
% First check for directories since
|
||||
% `exist(x, 'file')` also checks for directories!
|
||||
rmdir(x,'s');
|
||||
elseif exist(x, 'file') == 2
|
||||
delete(x);
|
||||
end
|
||||
end
|
||||
end
|
||||
% ==============================================================================
|
||||
function mostRecentVersion = determineLatestRelease(version, fileExchangeUrl)
|
||||
% Read in the Github releases page
|
||||
url = 'https://github.com/matlab2tikz/matlab2tikz/releases/';
|
||||
try
|
||||
html = urlread(url);
|
||||
catch %#ok
|
||||
% Couldn't load the URL -- never mind.
|
||||
html = '';
|
||||
warning('m2tUpdate:siteNotFound', ...
|
||||
['Cannot determine the latest version.\n', ...
|
||||
'Either your internet is down or something went wrong.\n', ...
|
||||
'You might want to check for updates by hand at %s.\n'], ...
|
||||
fileExchangeUrl);
|
||||
end
|
||||
|
||||
% Parse tag names which are the version number in the format ##.##.##
|
||||
% It assumes that releases will always be tagged with the version number
|
||||
expression = '(?<=matlab2tikz\/matlab2tikz\/releases\/tag\/)\d+\.\d+\.\d+';
|
||||
tags = regexp(html, expression, 'match');
|
||||
ntags = numel(tags);
|
||||
|
||||
% Keep only new releases
|
||||
inew = false(ntags,1);
|
||||
for ii = 1:ntags
|
||||
inew(ii) = isVersionBelow(version, tags{ii});
|
||||
end
|
||||
nnew = nnz(inew);
|
||||
|
||||
% One new release
|
||||
if nnew == 1
|
||||
mostRecentVersion = tags{inew};
|
||||
% Several new release, pick latest
|
||||
elseif nnew > 1
|
||||
tags = tags(inew);
|
||||
tagnum = zeros(nnew,1);
|
||||
for ii = 1:nnew
|
||||
tagnum(ii) = [10000,100,1] * versionArray(tags{ii});
|
||||
end
|
||||
[~, imax] = max(tagnum);
|
||||
mostRecentVersion = tags{imax};
|
||||
% No new
|
||||
else
|
||||
mostRecentVersion = '';
|
||||
end
|
||||
end
|
||||
% ==============================================================================
|
||||
function askToShowChangelog(currentVersion)
|
||||
% Asks whether the user wants to see the changelog and then shows it.
|
||||
reply = input(' *** Would you like to see the changelog? y/n [y]:' ,'s');
|
||||
shouldShow = isempty(reply) || ~strcmpi(reply(1),'n') ;
|
||||
if shouldShow
|
||||
fprintf(1, '\n%s\n', changelogUntilVersion(currentVersion));
|
||||
end
|
||||
end
|
||||
% ==============================================================================
|
||||
function changelog = changelogUntilVersion(currentVersion)
|
||||
% This function retrieves the chunk of the changelog until the current version.
|
||||
URL = 'https://github.com/matlab2tikz/matlab2tikz/raw/master/CHANGELOG.md';
|
||||
changelog = urlread(URL);
|
||||
currentVersion = versionString(currentVersion);
|
||||
|
||||
% Header is "# YYYY-MM-DD Version major.minor.patch [Manager](email)"
|
||||
% Just match for the part until the version number. Here, we're actually
|
||||
% matching a tiny bit too broad due to the periods in the version number
|
||||
% but the outcome should be the same if we keep the changelog format
|
||||
% identical.
|
||||
pattern = ['\#\s*[\d-]+\s*Version\s*' currentVersion];
|
||||
idxVersion = regexpi(changelog, pattern);
|
||||
if ~isempty(idxVersion)
|
||||
changelog = changelog(1:idxVersion-1);
|
||||
else
|
||||
% Just show the whole changelog if we don't find the old version.
|
||||
end
|
||||
changelog = replaceIssuesWithUrls(changelog);
|
||||
end
|
||||
% ==============================================================================
|
||||
function changelog = replaceIssuesWithUrls(changelog)
|
||||
% Replaces GitHub issues ("#...") with URLs
|
||||
baseurl = 'https://github.com/matlab2tikz/matlab2tikz/issues/';
|
||||
if strcmpi(getEnvironment(), 'MATLAB')
|
||||
replacement = sprintf('<a href="%s$1">#$1</a>', baseurl);
|
||||
changelog = regexprep(changelog, '\#(\d+)', replacement);
|
||||
end
|
||||
end
|
||||
% ==============================================================================
|
||||
function warnAboutUpgradeImplications(currentVersion, latestVersion, verbose)
|
||||
% This warns the user about the implications of upgrading as dictated by
|
||||
% Semantic Versioning.
|
||||
switch upgradeSize(currentVersion, latestVersion);
|
||||
case 'major'
|
||||
% The API might have changed in a backwards incompatible way.
|
||||
userInfo(verbose, 'This is a MAJOR upgrade!\n');
|
||||
userInfo(verbose, ' - New features may have been introduced.');
|
||||
userInfo(verbose, ' - Some old code/options may no longer work!\n');
|
||||
|
||||
case 'minor'
|
||||
% The API may NOT have changed in a backwards incompatible way.
|
||||
userInfo(verbose, 'This is a MINOR upgrade.\n');
|
||||
userInfo(verbose, ' - New features may have been introduced.');
|
||||
userInfo(verbose, ' - Some options may have been deprecated.');
|
||||
userInfo(verbose, ' - Old code should continue to work but might produce warnings.\n');
|
||||
|
||||
case 'patch'
|
||||
% No new functionality is introduced
|
||||
userInfo(verbose, 'This is a PATCH.\n');
|
||||
userInfo(verbose, ' - Only bug fixes are included in this upgrade.');
|
||||
userInfo(verbose, ' - Old code should continue to work as before.')
|
||||
end
|
||||
userInfo(verbose, 'Please check the changelog for detailed information.\n');
|
||||
userWarn(verbose, '\n!! By upgrading you will lose any custom changes !!\n');
|
||||
end
|
||||
% ==============================================================================
|
||||
function cls = upgradeSize(currentVersion, latestVersion)
|
||||
% Determines whether the upgrade is major, minor or a patch.
|
||||
currentVersion = versionArray(currentVersion);
|
||||
latestVersion = versionArray(latestVersion);
|
||||
description = {'major', 'minor', 'patch'};
|
||||
for ii = 1:numel(description)
|
||||
if latestVersion(ii) > currentVersion(ii)
|
||||
cls = description{ii};
|
||||
return
|
||||
end
|
||||
end
|
||||
cls = 'unknown';
|
||||
end
|
||||
% ==============================================================================
|
||||
function userInfo(verbose, message, varargin)
|
||||
% Display information (i.e. to stdout)
|
||||
if verbose
|
||||
userPrint(1, message, varargin{:});
|
||||
end
|
||||
end
|
||||
function userWarn(verbose, message, varargin)
|
||||
% Display warnings (i.e. to stderr)
|
||||
if verbose
|
||||
userPrint(2, message, varargin{:});
|
||||
end
|
||||
end
|
||||
function userPrint(fid, message, varargin)
|
||||
% Print messages (info/warnings) to a stream/file.
|
||||
mess = sprintf(message, varargin{:});
|
||||
|
||||
% Replace '\n' by '\n *** ' and print.
|
||||
mess = strrep( mess, sprintf('\n'), sprintf('\n *** ') );
|
||||
fprintf(fid, ' *** %s\n', mess );
|
||||
end
|
||||
% =========================================================================
|
||||
function list = rdirfiles(rootdir)
|
||||
% Recursive files listing
|
||||
s = dir(rootdir);
|
||||
list = {s.name}';
|
||||
|
||||
% Exclude .git, .svn, . and ..
|
||||
[list, idx] = setdiff(list, {'.git','.svn','.','..'});
|
||||
|
||||
% Add root
|
||||
list = fullfile(rootdir, list);
|
||||
|
||||
% Loop for sub-directories
|
||||
pdir = find([s(idx).isdir]);
|
||||
for ii = pdir
|
||||
list = [list; rdirfiles(list{ii})]; %#ok<AGROW>
|
||||
end
|
||||
|
||||
% Drop directories
|
||||
list(pdir) = [];
|
||||
end
|
||||
% =========================================================================
|
||||
function list = getFolders(list)
|
||||
% Extract the folder structure from a list of files and folders
|
||||
|
||||
for ii = 1:numel(list)
|
||||
if exist(list{ii},'file') == 2
|
||||
list{ii} = fileparts(list{ii});
|
||||
end
|
||||
end
|
||||
list = unique(list);
|
||||
end
|
||||
% =========================================================================
|
||||
@@ -0,0 +1,35 @@
|
||||
function newstr = m2tstrjoin(cellstr, delimiter, floatFormat)
|
||||
% This function joins a cell of strings to a single string (with a
|
||||
% given delimiter in between two strings, if desired).
|
||||
if ~exist('delimiter','var') || isempty(delimiter)
|
||||
delimiter = '';
|
||||
end
|
||||
if ~exist('floatFormat','var') || isempty(floatFormat)
|
||||
floatFormat = '%g';
|
||||
end
|
||||
if isempty(cellstr)
|
||||
newstr = '';
|
||||
return
|
||||
end
|
||||
|
||||
% convert all values to strings first
|
||||
nElem = numel(cellstr);
|
||||
for k = 1:nElem
|
||||
if isnumeric(cellstr{k})
|
||||
cellstr{k} = sprintf(floatFormat, cellstr{k});
|
||||
elseif iscell(cellstr{k})
|
||||
cellstr{k} = m2tstrjoin(cellstr{k}, delimiter, floatFormat);
|
||||
% this will fail for heavily nested cells
|
||||
elseif ~ischar(cellstr{k})
|
||||
error('matlab2tikz:join:NotCellstrOrNumeric',...
|
||||
'Expected cellstr or numeric.');
|
||||
end
|
||||
end
|
||||
|
||||
% inspired by strjoin of recent versions of MATLAB
|
||||
newstr = cell(2,nElem);
|
||||
newstr(1,:) = reshape(cellstr, 1, nElem);
|
||||
newstr(2,1:nElem-1) = {delimiter}; % put delimiters in-between the elements
|
||||
newstr(2,end) = {''}; % for Octave 4 compatibility
|
||||
newstr = [newstr{:}];
|
||||
end
|
||||
@@ -0,0 +1,18 @@
|
||||
function arr = versionArray(str)
|
||||
% Converts a version string to an array.
|
||||
if ischar(str)
|
||||
% Translate version string from '2.62.8.1' to [2; 62; 8; 1].
|
||||
switch getEnvironment
|
||||
case 'MATLAB'
|
||||
split = regexp(str, '\.', 'split'); % compatibility MATLAB < R2013a
|
||||
case 'Octave'
|
||||
split = strsplit(str, '.');
|
||||
otherwise
|
||||
errorUnknownEnvironment();
|
||||
end
|
||||
arr = str2num(char(split)); %#ok
|
||||
else
|
||||
arr = str;
|
||||
end
|
||||
arr = arr(:)';
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
function str = versionString(arr)
|
||||
% Converts a version array to string
|
||||
if ischar(arr)
|
||||
str = arr;
|
||||
elseif isnumeric(arr)
|
||||
str = sprintf('%d.', arr);
|
||||
str = str(1:end-1); % remove final period
|
||||
end
|
||||
end
|
||||
101
Functions/helper_functions_community/mat2tikz/test/README.md
Normal file
@@ -0,0 +1,101 @@
|
||||
This test module is part of matlab2tikz.
|
||||
|
||||
Its use is mainly of interest to the matlab2tikz developers to assert that the produced output is good.
|
||||
Ideally, the tests should be run on every supported environment, i.e.:
|
||||
|
||||
* MATLAB R2014a/8.3 (or an older version)
|
||||
* MATLAB R2014b/8.4 (or a newer version)
|
||||
* Octave 3.8
|
||||
|
||||
Preparing your environment
|
||||
==========================
|
||||
|
||||
Before you can run the tests, you need to make sure that you have all relevant
|
||||
functions available on your path. From within the `/test` directory run the
|
||||
following code in your MATLAB/Octave console:
|
||||
|
||||
```matlab
|
||||
addpath(pwd); % for the test harness
|
||||
addpath(fullfile(pwd,'..','src')); % for matlab2tikz
|
||||
addpath(fullfile(pwd,'suites')); % for the test suites
|
||||
```
|
||||
|
||||
Running the tests
|
||||
=================
|
||||
|
||||
We have two kinds of tests runners available that each serve a slightly different
|
||||
purpose.
|
||||
|
||||
* "Graphical" tests produce an output report that graphically shows test
|
||||
figures as generated by MATLAB/Octave and our TikZ output.
|
||||
* "Headless" tests do not produce graphical output, but instead check the MD5
|
||||
hash of the generated TikZ files to make sure that the same output
|
||||
as before is generated.
|
||||
|
||||
It is recommended to run the headless tests first and check the problems in
|
||||
the graphical tests afterwards.
|
||||
|
||||
Headless tests
|
||||
--------------
|
||||
These tests check that the TikZ output file produced by `matlab2tikz` matches
|
||||
a reference output. The actual checking is done by hashing the file and the
|
||||
corresponding hashes are stored in `.md5` files next to the test suites.
|
||||
For each environment, different reference hashes can be stored.
|
||||
|
||||
The headless tests can be invoked using
|
||||
```matlab
|
||||
testHeadless;
|
||||
```
|
||||
, or, equivalently,
|
||||
```matlab
|
||||
makeTravisReport(testHeadless)
|
||||
```
|
||||
|
||||
There are some caveats for this method of testing:
|
||||
|
||||
* The MD5 hash is extremely brittle to small details in the output: e.g.
|
||||
extra whitespace or some other characters will change the hash.
|
||||
* This automated test does NOT test whether the output is desirable or not.
|
||||
It only checks whether the previous output is not altered!
|
||||
* Hence, when structural changes are made, the reference hash should be changed.
|
||||
This SHOULD be motivated in the pull request (e.g. with a picture)!
|
||||
|
||||
Graphical tests
|
||||
---------------
|
||||
These tests allow easy comparison of a native PDF `print` output and the
|
||||
output produced by `matlab2tikz`. For the large amount of cases, however,
|
||||
this comparison has become somewhat unwieldy.
|
||||
|
||||
You can execute the tests using
|
||||
```matlab
|
||||
testGraphical;
|
||||
```
|
||||
or, equivalently,
|
||||
```matlab
|
||||
makeLatexReport(testGraphical)
|
||||
```
|
||||
This generates a LaTeX report in `test/output/current/acid.tex` which can then be compiled.
|
||||
Compilation of this file can be done using the Makefile `test/output/current/Makefile` if you are on a Unix-like system (OS X, Linux) or have [Cygwin](https://www.cygwin.com) installed on Windows.
|
||||
|
||||
If all goes well, the result will be the file `test/output/current/acid.pdf` that contains
|
||||
a list of the test figures, exported as PDF and right next to it the matlab2tikz generated plot.
|
||||
|
||||
Advanced Use
|
||||
------------
|
||||
|
||||
Both `testHeadless` and `testGraphical` can take multiple arguments, those are documented in the raw test runner `testMatlab2tikz` that is used behind the scenes. Note that this file sits in a private directory, so `help testMatlab2tikz` will not work!
|
||||
|
||||
Also, both can be called with a single output argument, for programmatical
|
||||
access to the test results as
|
||||
```matlab
|
||||
status = testHeadless()
|
||||
```
|
||||
These test results in `status` can be passed to `saveHashTable` for updating the hash tables.
|
||||
Obviously, this should be done with the due diligence!
|
||||
|
||||
Automated Tests
|
||||
===============
|
||||
|
||||
The automated tests run on [Travis-CI](https://travis-ci.org) for Octave and on a [personal Jenkins server](https://github.com/matlab2tikz/matlab2tikz/wiki/Jenkins) for MATLAB.
|
||||
These are effectively the "headless" tests that get called by the `runMatlab2TikzTests` function.
|
||||
Without verification of those automated tests, a pull request is unlikely to get merged.
|
||||
280
Functions/helper_functions_community/mat2tikz/test/codeReport.m
Normal file
@@ -0,0 +1,280 @@
|
||||
function [ report ] = codeReport( varargin )
|
||||
%CODEREPORT Builds a report of the code health
|
||||
%
|
||||
% This function generates a Markdown report on the code health. At the moment
|
||||
% this is limited to the McCabe (cyclomatic) complexity of a function and its
|
||||
% subfunctions.
|
||||
%
|
||||
% This makes use of |checkcode| in MATLAB.
|
||||
%
|
||||
% Usage:
|
||||
%
|
||||
% CODEREPORT('function', functionName) to determine which function is
|
||||
% analyzed. (default: matlab2tikz)
|
||||
%
|
||||
% CODEREPORT('complexityThreshold', integer ) to set above which complexity, a
|
||||
% function is added to the report (default: 10)
|
||||
%
|
||||
% CODEREPORT('stream', stream) to set to which stream/file to output the report
|
||||
% (default: 1, i.e. stdout). The stream is used only when no output argument
|
||||
% for `codeReport` is specified!.
|
||||
%
|
||||
% See also: checkcode, mlint
|
||||
|
||||
SM = StreamMaker();
|
||||
%% input options
|
||||
ipp = m2tInputParser();
|
||||
ipp = ipp.addParamValue(ipp, 'function', 'matlab2tikz', @ischar);
|
||||
ipp = ipp.addParamValue(ipp, 'complexityThreshold', 10, @isnumeric);
|
||||
ipp = ipp.addParamValue(ipp, 'stream', 1, SM.isStream);
|
||||
ipp = ipp.parse(ipp, varargin{:});
|
||||
|
||||
stream = SM.make(ipp.Results.stream, 'w');
|
||||
|
||||
%% generate report data
|
||||
data = checkcode(ipp.Results.function,'-cyc','-struct');
|
||||
[complexityAll, mlintMessages] = splitCycloComplexity(data);
|
||||
|
||||
%% analyze cyclomatic complexity
|
||||
categorizeComplexity = @(x) categoryOfComplexity(x, ...
|
||||
ipp.Results.complexityThreshold, ...
|
||||
ipp.Results.function);
|
||||
|
||||
complexityAll = arrayfun(@parseCycloComplexity, complexityAll);
|
||||
complexityAll = arrayfun(categorizeComplexity, complexityAll);
|
||||
|
||||
complexity = filter(complexityAll, @(x) strcmpi(x.category, 'Bad'));
|
||||
complexity = sortBy(complexity, 'line', 'ascend');
|
||||
complexity = sortBy(complexity, 'complexity', 'descend');
|
||||
|
||||
[complexityStats] = complexityStatistics(complexityAll);
|
||||
|
||||
%% analyze other messages
|
||||
%TODO: handle all mlint messages and/or other metrics of the code
|
||||
|
||||
%% format report
|
||||
dataStr = complexity;
|
||||
dataStr = arrayfun(@(d) mapField(d, 'function', @markdownInlineCode), dataStr);
|
||||
if ~isempty(dataStr)
|
||||
dataStr = addFooterRow(dataStr, 'complexity', @sum, {'line',0, 'function',bold('Total')});
|
||||
end
|
||||
dataStr = arrayfun(@(d) mapField(d, 'line', @integerToString), dataStr);
|
||||
dataStr = arrayfun(@(d) mapField(d, 'complexity', @integerToString), dataStr);
|
||||
|
||||
report = makeTable(dataStr, {'function', 'complexity'}, ...
|
||||
{'Function', 'Complexity'});
|
||||
|
||||
%% command line usage
|
||||
if nargout == 0
|
||||
if ismember(stream.name, {'stdout','stderr'})
|
||||
stream.print('%s\n', codelinks(report, ipp.Results.function));
|
||||
else
|
||||
stream.print('%s\n', report);
|
||||
end
|
||||
|
||||
figure('name',sprintf('Complexity statistics of %s', ipp.Results.function));
|
||||
h = statisticsPlot(complexityStats, 'Complexity', 'Number of functions');
|
||||
for hh = h
|
||||
plot(hh, [1 1]*ipp.Results.complexityThreshold, ylim(hh), ...
|
||||
'k--','DisplayName','Threshold');
|
||||
end
|
||||
legend(h(1),'show','Location','NorthEast');
|
||||
|
||||
clear report
|
||||
end
|
||||
|
||||
end
|
||||
%% CATEGORIZATION ==============================================================
|
||||
function [complexity, others] = splitCycloComplexity(list)
|
||||
% splits codereport into McCabe complexity and others
|
||||
filter = @(l) ~isempty(strfind(l.message, 'McCabe complexity'));
|
||||
idxComplexity = arrayfun(filter, list);
|
||||
complexity = list( idxComplexity);
|
||||
others = list(~idxComplexity);
|
||||
end
|
||||
function [data] = categoryOfComplexity(data, threshold, mainFunc)
|
||||
% categorizes the complexity as "Good", "Bad" or "Accepted"
|
||||
TOKEN = '#COMPLEX'; % token to signal allowed complexity
|
||||
|
||||
try %#ok
|
||||
helpStr = help(sprintf('%s>%s', mainFunc, data.function));
|
||||
if ~isempty(strfind(helpStr, TOKEN))
|
||||
data.category = 'Accepted';
|
||||
return;
|
||||
end
|
||||
end
|
||||
if data.complexity > threshold
|
||||
data.category = 'Bad';
|
||||
else
|
||||
data.category = 'Good';
|
||||
end
|
||||
end
|
||||
|
||||
%% PARSING =====================================================================
|
||||
function [out] = parseCycloComplexity(in)
|
||||
% converts McCabe complexity report strings into a better format
|
||||
out = regexp(in.message, ...
|
||||
'The McCabe complexity of ''(?<function>[A-Za-z0-9_]+)'' is (?<complexity>[0-9]+).', ...
|
||||
'names');
|
||||
out.complexity = str2double(out.complexity);
|
||||
out.line = in.line;
|
||||
end
|
||||
|
||||
%% DATA PROCESSING =============================================================
|
||||
function selected = filter(list, filterFunc)
|
||||
% filters an array according to a binary function
|
||||
idx = logical(arrayfun(filterFunc, list));
|
||||
selected = list(idx);
|
||||
end
|
||||
function [data] = mapField(data, field, mapping)
|
||||
data.(field) = mapping(data.(field));
|
||||
end
|
||||
function sorted = sortBy(list, fieldName, mode)
|
||||
% sorts a struct array by a single field
|
||||
% extra arguments are as for |sort|
|
||||
values = arrayfun(@(m)m.(fieldName), list);
|
||||
[dummy, idxSorted] = sort(values(:), 1, mode); %#ok
|
||||
sorted = list(idxSorted);
|
||||
end
|
||||
|
||||
function [stat] = complexityStatistics(list)
|
||||
% calculate some basic statistics of the complexities
|
||||
|
||||
stat.values = arrayfun(@(c)(c.complexity), list);
|
||||
stat.binCenter = sort(unique(stat.values));
|
||||
|
||||
categoryPerElem = {list.category};
|
||||
stat.categories = unique(categoryPerElem);
|
||||
nCategories = numel(stat.categories);
|
||||
|
||||
groupedHist = zeros(numel(stat.binCenter), nCategories);
|
||||
for iCat = 1:nCategories
|
||||
category = stat.categories{iCat};
|
||||
idxCat = ismember(categoryPerElem, category);
|
||||
groupedHist(:,iCat) = hist(stat.values(idxCat), stat.binCenter);
|
||||
end
|
||||
|
||||
stat.histogram = groupedHist;
|
||||
stat.median = median(stat.values);
|
||||
end
|
||||
function [data] = addFooterRow(data, column, func, otherFields)
|
||||
% adds a footer row to data table based on calculations of a single column
|
||||
footer = data(end);
|
||||
for iField = 1:2:numel(otherFields)
|
||||
field = otherFields{iField};
|
||||
value = otherFields{iField+1};
|
||||
footer.(field) = value;
|
||||
end
|
||||
footer.(column) = func([data(:).(column)]);
|
||||
data(end+1) = footer;
|
||||
end
|
||||
|
||||
%% FORMATTING ==================================================================
|
||||
function str = integerToString(value)
|
||||
% convert integer to string
|
||||
str = sprintf('%d',value);
|
||||
end
|
||||
function str = markdownInlineCode(str)
|
||||
% format as inline code for markdown
|
||||
str = sprintf('`%s`', str);
|
||||
end
|
||||
function str = makeTable(data, fields, header)
|
||||
% make a markdown table from struct array
|
||||
nData = numel(data);
|
||||
str = '';
|
||||
if nData == 0
|
||||
return; % empty input
|
||||
end
|
||||
%TODO: use gfmTable from makeTravisReport instead to do the formatting
|
||||
|
||||
% determine column sizes
|
||||
nFields = numel(fields);
|
||||
table = cell(nFields, nData);
|
||||
columnWidth = zeros(1,nFields);
|
||||
for iField = 1:nFields
|
||||
field = fields{iField};
|
||||
table(iField, :) = {data(:).(field)};
|
||||
columnWidth(iField) = max(cellfun(@numel, table(iField, :)));
|
||||
end
|
||||
columnWidth = max(columnWidth, cellfun(@numel, header));
|
||||
columnWidth = columnWidth + 2; % empty space left and right
|
||||
columnWidth([1,end]) = columnWidth([1,end]) - 1; % except at the edges
|
||||
|
||||
% format table inside cell array
|
||||
table = [header; table'];
|
||||
for iField = 1:nFields
|
||||
FORMAT = ['%' int2str(columnWidth(iField)) 's'];
|
||||
|
||||
for jData = 1:size(table, 1)
|
||||
table{jData, iField} = strjust(sprintf(FORMAT, ...
|
||||
table{jData, iField}), 'center');
|
||||
end
|
||||
end
|
||||
|
||||
% insert separator
|
||||
table = [table(1,:)
|
||||
arrayfun(@(n) repmat('-',1,n), columnWidth, 'UniformOutput',false)
|
||||
table(2:end,:)]';
|
||||
|
||||
% convert cell array to string
|
||||
FORMAT = ['%s' repmat('|%s', 1,nFields-1) '\n'];
|
||||
str = sprintf(FORMAT, table{:});
|
||||
|
||||
end
|
||||
|
||||
function str = codelinks(str, functionName)
|
||||
% replaces inline functions with clickable links in MATLAB
|
||||
str = regexprep(str, '`([A-Za-z0-9_]+)`', ...
|
||||
['`<a href="matlab:edit ' functionName '>$1">$1</a>`']);
|
||||
%NOTE: editing function>subfunction will focus on that particular subfunction
|
||||
% in the editor (this also works for the main function)
|
||||
end
|
||||
function str = bold(str)
|
||||
str = ['**' str '**'];
|
||||
end
|
||||
|
||||
%% PLOTTING ====================================================================
|
||||
function h = statisticsPlot(stat, xLabel, yLabel)
|
||||
% plot a histogram and box plot
|
||||
nCategories = numel(stat.categories);
|
||||
colors = colorscheme;
|
||||
|
||||
h(1) = subplot(5,1,1:4);
|
||||
hold all;
|
||||
hb = bar(stat.binCenter, stat.histogram, 'stacked');
|
||||
|
||||
for iCat = 1:nCategories
|
||||
category = stat.categories{iCat};
|
||||
|
||||
set(hb(iCat), 'DisplayName', category, 'FaceColor', colors.(category), ...
|
||||
'LineStyle','none');
|
||||
end
|
||||
|
||||
%xlabel(xLabel);
|
||||
ylabel(yLabel);
|
||||
|
||||
h(2) = subplot(5,1,5);
|
||||
hold all;
|
||||
|
||||
boxplot(stat.values,'orientation','horizontal',...
|
||||
'boxstyle', 'outline', ...
|
||||
'symbol', 'o', ...
|
||||
'colors', colors.All);
|
||||
xlabel(xLabel);
|
||||
|
||||
xlims = [min(stat.binCenter)-1 max(stat.binCenter)+1];
|
||||
c = 1;
|
||||
ylims = (ylim(h(2)) - c)/3 + c;
|
||||
|
||||
set(h,'XTickMode','manual','XTick',stat.binCenter,'XLim',xlims);
|
||||
set(h(1),'XTickLabel','');
|
||||
set(h(2),'YTickLabel','','YLim',ylims);
|
||||
linkaxes(h, 'x');
|
||||
end
|
||||
function colors = colorscheme()
|
||||
% recognizable color scheme for the categories
|
||||
colors.All = [ 0 113 188]/255;
|
||||
colors.Good = [118 171 47]/255;
|
||||
colors.Bad = [161 19 46]/255;
|
||||
colors.Accepted = [236 176 31]/255;
|
||||
end
|
||||
@@ -0,0 +1,256 @@
|
||||
function compareTimings(statusBefore, statusAfter)
|
||||
% COMPARETIMINGS compare timing of matlab2tikz test suite runs
|
||||
%
|
||||
% This function plots some analysis plots of the timings of different test
|
||||
% cases. When the test suite is run repeatedly, the median statistics are
|
||||
% reported as well as the individual runs.
|
||||
%
|
||||
% Usage:
|
||||
% COMPARETIMINGS(statusBefore, statusAfter)
|
||||
%
|
||||
% Parameters:
|
||||
% - statusBefore and statusAfter are expected to be
|
||||
% N x R cell arrays, each cell contains a status of a test case
|
||||
% where there are N test cases, repeated R times each.
|
||||
%
|
||||
% You can build such cells, e.g. with the following snippet.
|
||||
%
|
||||
% suite = @ACID
|
||||
% N = numel(suite(0)); % number of test cases
|
||||
% R = 10; % number of repetitions of each test case
|
||||
%
|
||||
% statusBefore = cell(N, R);
|
||||
% for r = 1:R
|
||||
% statusBefore(:, r) = testHeadless;
|
||||
% end
|
||||
%
|
||||
% % now check out the after commit
|
||||
%
|
||||
% statusAfter = cell(N, R);
|
||||
% for r = 1:R
|
||||
% statusAfter(:, r) = testHeadless;
|
||||
% end
|
||||
%
|
||||
% compareTimings(statusBefore, statusAfter)
|
||||
%
|
||||
% See also: testHeadless
|
||||
|
||||
%% Extract timing information
|
||||
time_cf = extract(statusBefore, statusAfter, @(s) s.tikzStage.cleanfigure_time);
|
||||
time_m2t = extract(statusBefore, statusAfter, @(s) s.tikzStage.m2t_time);
|
||||
%% Construct plots
|
||||
hax(1) = subplot(3,2,1);
|
||||
histograms(time_cf, 'cleanfigure');
|
||||
legend('show')
|
||||
|
||||
hax(2) = subplot(3,2,3);
|
||||
histograms(time_m2t, 'matlab2tikz');
|
||||
legend('show')
|
||||
linkaxes(hax([1 2]),'x');
|
||||
|
||||
hax(3) = subplot(3,2,5);
|
||||
histogramSpeedup('cleanfigure', time_cf, 'matlab2tikz', time_m2t);
|
||||
legend('show');
|
||||
|
||||
hax(4) = subplot(3,2,2);
|
||||
plotByTestCase(time_cf, 'cleanfigure');
|
||||
legend('show')
|
||||
|
||||
hax(5) = subplot(3,2,4);
|
||||
plotByTestCase(time_m2t, 'matlab2tikz');
|
||||
legend('show')
|
||||
|
||||
hax(6) = subplot(3,2,6);
|
||||
plotSpeedup('cleanfigure', time_cf, 'matlab2tikz', time_m2t);
|
||||
legend('show');
|
||||
|
||||
linkaxes(hax([4 5 6]), 'x');
|
||||
|
||||
% ------------------------------------------------------------------------------
|
||||
end
|
||||
%% Data processing
|
||||
function timing = extract(statusBefore, statusAfter, func)
|
||||
otherwiseNaN = {'ErrorHandler', @(varargin) NaN};
|
||||
|
||||
timing.before = cellfun(func, statusBefore, otherwiseNaN{:});
|
||||
timing.after = cellfun(func, statusAfter, otherwiseNaN{:});
|
||||
end
|
||||
function [names,timings] = splitNameTiming(vararginAsCell)
|
||||
names = vararginAsCell(1:2:end-1);
|
||||
timings = vararginAsCell(2:2:end);
|
||||
end
|
||||
|
||||
%% Plot subfunctions
|
||||
function [h] = histograms(timing, name)
|
||||
% plot histogram of time measurements
|
||||
colors = colorscheme;
|
||||
histostyle = {'DisplayStyle', 'bar',...
|
||||
'Normalization','pdf',...
|
||||
'EdgeColor','none',...
|
||||
'BinWidth',0.025};
|
||||
|
||||
hold on;
|
||||
h{1} = myHistogram(timing.before, histostyle{:}, ...
|
||||
'FaceColor', colors.before, ...
|
||||
'DisplayName', 'Before');
|
||||
h{2} = myHistogram(timing.after , histostyle{:}, ...
|
||||
'FaceColor', colors.after,...
|
||||
'DisplayName', 'After');
|
||||
|
||||
xlabel(sprintf('%s runtime [s]',name))
|
||||
ylabel('Empirical PDF');
|
||||
end
|
||||
function [h] = histogramSpeedup(varargin)
|
||||
% plot histogram of observed speedup
|
||||
histostyle = {'DisplayStyle', 'bar',...
|
||||
'Normalization','pdf',...
|
||||
'EdgeColor','none'};
|
||||
|
||||
[names,timings] = splitNameTiming(varargin);
|
||||
nData = numel(timings);
|
||||
h = cell(nData, 1);
|
||||
minTime = NaN; maxTime = NaN;
|
||||
for iData = 1:nData
|
||||
name = names{iData};
|
||||
timing = timings{iData};
|
||||
|
||||
hold on;
|
||||
speedup = computeSpeedup(timing);
|
||||
color = colorOptionsOfName(name, 'FaceColor');
|
||||
|
||||
h{iData} = myHistogram(speedup, histostyle{:}, color{:},...
|
||||
'DisplayName', name);
|
||||
|
||||
[minTime, maxTime] = minAndMax(speedup, minTime, maxTime);
|
||||
end
|
||||
xlabel('Speedup')
|
||||
ylabel('Empirical PDF');
|
||||
set(gca,'XScale','log', 'XLim', [minTime, maxTime].*[0.9 1.1]);
|
||||
end
|
||||
function [h] = plotByTestCase(timing, name)
|
||||
% plot all time measurements per test case
|
||||
colors = colorscheme;
|
||||
hold on;
|
||||
if size(timing.before, 2) > 1
|
||||
h{3} = plot(timing.before, '.',...
|
||||
'Color', colors.before, 'HandleVisibility', 'off');
|
||||
h{4} = plot(timing.after, '.',...
|
||||
'Color', colors.after, 'HandleVisibility', 'off');
|
||||
end
|
||||
h{1} = plot(median(timing.before, 2), '-',...
|
||||
'LineWidth', 2, ...
|
||||
'Color', colors.before, ...
|
||||
'DisplayName', 'Before');
|
||||
h{2} = plot(median(timing.after, 2), '-',...
|
||||
'LineWidth', 2, ...
|
||||
'Color', colors.after,...
|
||||
'DisplayName', 'After');
|
||||
|
||||
ylabel(sprintf('%s runtime [s]', name));
|
||||
set(gca,'YScale','log')
|
||||
end
|
||||
function [h] = plotSpeedup(varargin)
|
||||
% plot speed up per test case
|
||||
[names, timings] = splitNameTiming(varargin);
|
||||
|
||||
nDatasets = numel(names);
|
||||
minTime = NaN;
|
||||
maxTime = NaN;
|
||||
h = cell(nDatasets, 1);
|
||||
for iData = 1:nDatasets
|
||||
name = names{iData};
|
||||
timing = timings{iData};
|
||||
color = colorOptionsOfName(name);
|
||||
|
||||
hold on
|
||||
[speedup, medSpeedup] = computeSpeedup(timing);
|
||||
if size(speedup, 2) > 1
|
||||
plot(speedup, '.', color{:}, 'HandleVisibility','off');
|
||||
end
|
||||
h{iData} = plot(medSpeedup, color{:}, 'DisplayName', name, ...
|
||||
'LineWidth', 2);
|
||||
|
||||
[minTime, maxTime] = minAndMax(speedup, minTime, maxTime);
|
||||
end
|
||||
|
||||
nTests = size(speedup, 1);
|
||||
plot([-nTests nTests*2], ones(2,1), 'k','HandleVisibility','off');
|
||||
|
||||
legend('show', 'Location','NorthWest')
|
||||
set(gca,'YScale','log','YLim', [minTime, maxTime].*[0.9 1.1], ...
|
||||
'XLim', [0 nTests+1])
|
||||
xlabel('Test case');
|
||||
ylabel('Speed-up (t_{before}/t_{after})');
|
||||
end
|
||||
|
||||
%% Histogram wrapper
|
||||
function [h] = myHistogram(data, varargin)
|
||||
% this is a very crude wrapper that mimics Histogram in R2014a and older
|
||||
if ~isempty(which('histogram'))
|
||||
h = histogram(data, varargin{:});
|
||||
else % no "histogram" available
|
||||
options = struct(varargin{:});
|
||||
|
||||
minData = min(data(:));
|
||||
maxData = max(data(:));
|
||||
if isfield(options, 'BinWidth')
|
||||
numBins = ceil((maxData-minData)/options.BinWidth);
|
||||
elseif isfield(options, 'NumBins')
|
||||
numBins = options.NumBins;
|
||||
else
|
||||
numBins = 10;
|
||||
end
|
||||
[counts, bins] = hist(data(:), numBins);
|
||||
if isfield(options,'Normalization') && strcmp(options.Normalization,'pdf')
|
||||
binWidth = mean(diff(bins));
|
||||
counts = counts./sum(counts)/binWidth;
|
||||
end
|
||||
h = bar(bins, counts, 1);
|
||||
|
||||
% transfer properties as well
|
||||
names = fieldnames(options);
|
||||
for iName = 1:numel(names)
|
||||
option = names{iName};
|
||||
if isprop(h, option)
|
||||
set(h, option, options.(option));
|
||||
end
|
||||
end
|
||||
set(allchild(h),'FaceAlpha', 0.75); % only supported with OpenGL renderer
|
||||
% but this should look a bit similar with matlab2tikz then...
|
||||
end
|
||||
end
|
||||
|
||||
%% Calculations
|
||||
function [speedup, medSpeedup] = computeSpeedup(timing)
|
||||
% computes the timing speedup (and median speedup)
|
||||
dRep = 2; % dimension containing the repeated tests
|
||||
speedup = timing.before ./ timing.after;
|
||||
medSpeedup = median(timing.before, dRep) ./ median(timing.after, dRep);
|
||||
end
|
||||
function [minTime, maxTime] = minAndMax(speedup, minTime, maxTime)
|
||||
% calculates the minimum/maximum time in an array and peviously
|
||||
% computed min/max times
|
||||
minTime = min([minTime; speedup(:)]);
|
||||
maxTime = min([maxTime; speedup(:)]);
|
||||
end
|
||||
%% Color scheme
|
||||
function colors = colorscheme()
|
||||
% defines the color scheme
|
||||
colors.matlab2tikz = [161 19 46]/255;
|
||||
colors.cleanfigure = [ 0 113 188]/255;
|
||||
colors.before = [236 176 31]/255;
|
||||
colors.after = [118 171 47]/255;
|
||||
end
|
||||
function color = colorOptionsOfName(name, keyword)
|
||||
% returns a cell array with a keyword (default: 'Color') and a named color
|
||||
% if it exists in the colorscheme
|
||||
if ~exist('keyword','var') || isempty(keyword)
|
||||
keyword = 'Color';
|
||||
end
|
||||
colors = colorscheme;
|
||||
if isfield(colors,name)
|
||||
color = {keyword, colors.(name)};
|
||||
else
|
||||
color = {};
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,53 @@
|
||||
function example_bar_plot()
|
||||
test_data =[18 0; 20 0; 21 2; 30 14; 35 34; 40 57; 45 65; 50 46; 55 9; 60 2; 65 1; 70 0];
|
||||
|
||||
% Create figure
|
||||
figure1 = figure('Color',[1 1 1]);
|
||||
|
||||
subplot(1,2,1)
|
||||
|
||||
|
||||
hb=barh(test_data(:,1),test_data(:,2),'DisplayName','Test Data');
|
||||
|
||||
ylabel('parameter [units]');
|
||||
xlabel('#');
|
||||
legend('show','Location','northwest');
|
||||
subplot(1,2,2)
|
||||
|
||||
|
||||
hb=bar(test_data(:,1),test_data(:,2),'DisplayName','Test Data');
|
||||
|
||||
xlabel('parameter [units]');
|
||||
ylabel('#');
|
||||
legend('show','Location','northwest');
|
||||
|
||||
|
||||
xdata=test_data(:,1);
|
||||
barWidth=test_getBarWidthInAbsolutUnits(hb);
|
||||
|
||||
x_l=xdata-barWidth/2;
|
||||
x_u=xdata+barWidth/2;
|
||||
max_y=max(test_data(:,2))*1.2;
|
||||
x=[];
|
||||
y=[];
|
||||
for i=1:length(x_l)
|
||||
x = [x , x_l(i),x_l(i),nan,x_u(i),x_u(i),nan];
|
||||
y = [y, 0,max_y ,nan,0 ,max_y ,nan];
|
||||
|
||||
|
||||
end
|
||||
hold on
|
||||
plot(x,y,'r');
|
||||
|
||||
matlab2tikz('figurehandle',figure1,'filename','example_v_bar_plot.tex' ,'standalone', true);
|
||||
|
||||
|
||||
function BarWidth=test_getBarWidthInAbsolutUnits(h)
|
||||
% astimates the width of a bar plot
|
||||
XData_bar=get(h,'XData');
|
||||
length_bar = length(XData_bar);
|
||||
BarWidth= get(h, 'BarWidth');
|
||||
if length_bar > 1
|
||||
BarWidth = min(diff(XData_bar))*BarWidth;
|
||||
end
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
%% Quiver calculations
|
||||
% These are calculations for the quiver dimensions as implemented in MATLAB
|
||||
% (HG1) as in the |quiver.m| function.
|
||||
%
|
||||
% For HG2 and Octave, the situation might be different.
|
||||
%
|
||||
% A single quiver is defined as:
|
||||
%
|
||||
% C
|
||||
% \
|
||||
% \
|
||||
% A ----------------- B
|
||||
% /
|
||||
% /
|
||||
% D
|
||||
%
|
||||
% To know the dimensions of the arrow head, MATLAB defines the quantities
|
||||
% alpha = beta = 0.33 that determine the coordinates of C and D as given below.
|
||||
|
||||
clc;
|
||||
clear variables;
|
||||
close all;
|
||||
|
||||
%% Parameters
|
||||
try
|
||||
syms x y z u v w alpha beta epsilon real
|
||||
catch
|
||||
warning('Symbolic toolbox not found. Interpret the values with care!');
|
||||
x = randn(); y = randn(); z = randn();
|
||||
u = randn(); v = randn(); w = randn();
|
||||
end
|
||||
alpha = 0.33;
|
||||
beta = alpha;
|
||||
epsilon = 0;
|
||||
is2D = true;
|
||||
|
||||
%% Coordinates as defined in MATLAB
|
||||
% Note that in 3D, the arrow head is oriented in a weird way. Let' just ignore
|
||||
% that and only focus on 2D and use the same in 3D. Due to the lack
|
||||
% of [u,v,w]-symmetry in those equations, the angle is bound to depend on the
|
||||
% length of |delta|, i.e. something we don't know beforehand.
|
||||
A = [x y z].';
|
||||
delta = [u v w].';
|
||||
B = A + delta;
|
||||
C = B - alpha*[u+beta*(v+epsilon);
|
||||
v-beta*(u+epsilon)
|
||||
w];
|
||||
D = B - alpha*[u-beta*(v+epsilon);
|
||||
v+beta*(u+epsilon)
|
||||
w];
|
||||
|
||||
if is2D
|
||||
A = A(1:2);
|
||||
B = B(1:2);
|
||||
C = C(1:2);
|
||||
D = D(1:2);
|
||||
delta = delta(1:2);
|
||||
end
|
||||
|
||||
%% Calculating the angle of the arrowhead
|
||||
% Calculate the cos(angle) using the inner product
|
||||
unitVector = @(v) v/norm(v);
|
||||
cosAngleBetween = @(a,b,c) unitVector(a-b).' * unitVector(c-b);
|
||||
|
||||
cosTwiceTheta = cosAngleBetween(C,B,D);
|
||||
if isa(cosTwiceTheta, 'sym')
|
||||
cosTwiceTheta = simplify(cosTwiceTheta);
|
||||
end
|
||||
|
||||
theta = acos(cosTwiceTheta) / 2
|
||||
|
||||
radToDeg = @(rads) (rads * 180 / pi);
|
||||
|
||||
thetaVal = radToDeg(theta)
|
||||
try
|
||||
thetaVal = double(thetaVal)
|
||||
end
|
||||
|
||||
% For the MATLAB parameters alpha=beta=0.33, we get theta = 18.263 degrees.
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
function makeLatexReport(status, output)
|
||||
% generate a LaTeX report
|
||||
%
|
||||
%
|
||||
if ~exist('output','var')
|
||||
output = m2troot('test','output','current');
|
||||
end
|
||||
% first, initialize the tex output
|
||||
SM = StreamMaker();
|
||||
stream = SM.make(fullfile(output, 'acid.tex'), 'w');
|
||||
|
||||
texfile_init(stream);
|
||||
|
||||
printFigures(stream, status);
|
||||
printSummaryTable(stream, status);
|
||||
printErrorMessages(stream, status);
|
||||
printEnvironmentInfo(stream, status);
|
||||
|
||||
texfile_finish(stream);
|
||||
end
|
||||
% =========================================================================
|
||||
function texfile_init(stream)
|
||||
|
||||
stream.print(['\\documentclass[landscape]{scrartcl}\n' , ...
|
||||
'\\pdfminorversion=6\n\n' , ...
|
||||
'\\usepackage{amsmath} %% required for $\\text{xyz}$\n\n', ...
|
||||
'\\usepackage{hyperref}\n' , ...
|
||||
'\\usepackage{graphicx}\n' , ...
|
||||
'\\usepackage{epstopdf}\n' , ...
|
||||
'\\usepackage{tikz}\n' , ...
|
||||
'\\usetikzlibrary{plotmarks}\n\n' , ...
|
||||
'\\usepackage{pgfplots}\n' , ...
|
||||
'\\pgfplotsset{compat=newest}\n\n' , ...
|
||||
'\\usepackage[margin=0.5in]{geometry}\n' , ...
|
||||
'\\newlength\\figurewidth\n' , ...
|
||||
'\\setlength\\figurewidth{0.4\\textwidth}\n\n' , ...
|
||||
'\\begin{document}\n\n']);
|
||||
|
||||
end
|
||||
% =========================================================================
|
||||
function texfile_finish(stream)
|
||||
stream.print('\\end{document}');
|
||||
end
|
||||
% =========================================================================
|
||||
function printFigures(stream, status)
|
||||
for k = 1:length(status)
|
||||
texfile_addtest(stream, status{k});
|
||||
end
|
||||
end
|
||||
% =========================================================================
|
||||
function printSummaryTable(stream, status)
|
||||
texfile_tab_completion_init(stream)
|
||||
for k = 1:length(status)
|
||||
stat = status{k};
|
||||
testNumber = stat.index;
|
||||
% Break table up into pieces if it gets too long for one page
|
||||
%TODO: use booktabs instead
|
||||
%TODO: maybe just write a function to construct the table at once
|
||||
% from a cell array (see makeTravisReport for GFM counterpart)
|
||||
if ~mod(k,35)
|
||||
texfile_tab_completion_finish(stream);
|
||||
texfile_tab_completion_init(stream);
|
||||
end
|
||||
|
||||
stream.print('%d & \\texttt{%s}', testNumber, name2tex(stat.function));
|
||||
if stat.skip
|
||||
stream.print(' & --- & skipped & ---');
|
||||
else
|
||||
for err = [stat.plotStage.error, ...
|
||||
stat.saveStage.error, ...
|
||||
stat.tikzStage.error]
|
||||
if err
|
||||
stream.print(' & \\textcolor{red}{failed}');
|
||||
else
|
||||
stream.print(' & \\textcolor{green!50!black}{passed}');
|
||||
end
|
||||
end
|
||||
end
|
||||
stream.print(' \\\\\n');
|
||||
end
|
||||
texfile_tab_completion_finish(stream);
|
||||
end
|
||||
% =========================================================================
|
||||
function printErrorMessages(stream, status)
|
||||
if errorHasOccurred(status)
|
||||
stream.print('\\section*{Error messages}\n\\scriptsize\n');
|
||||
for k = 1:length(status)
|
||||
stat = status{k};
|
||||
testNumber = stat.index;
|
||||
if isempty(stat.plotStage.message) && ...
|
||||
isempty(stat.saveStage.message) && ...
|
||||
isempty(stat.tikzStage.message)
|
||||
continue % No error messages for this test case
|
||||
end
|
||||
|
||||
stream.print('\n\\subsection*{Test case %d: \\texttt{%s}}\n', testNumber, name2tex(stat.function));
|
||||
print_verbatim_information(stream, 'Plot generation', stat.plotStage.message);
|
||||
print_verbatim_information(stream, 'PDF generation' , stat.saveStage.message);
|
||||
print_verbatim_information(stream, 'matlab2tikz' , stat.tikzStage.message);
|
||||
end
|
||||
stream.print('\n\\normalsize\n\n');
|
||||
end
|
||||
end
|
||||
% =========================================================================
|
||||
function printEnvironmentInfo(stream, status)
|
||||
[env,versionString] = getEnvironment();
|
||||
|
||||
testsuites = unique(cellfun(@(s) func2str(s.testsuite) , status, ...
|
||||
'UniformOutput', false));
|
||||
testsuites = name2tex(m2tstrjoin(testsuites, ', '));
|
||||
|
||||
stream.print(['\\newpage\n',...
|
||||
'\\begin{tabular}{ll}\n',...
|
||||
' Suite & ' testsuites ' \\\\ \n', ...
|
||||
' Created & ' datestr(now) ' \\\\ \n', ...
|
||||
' OS & ' OSVersion ' \\\\ \n',...
|
||||
' ' env ' & ' versionString ' \\\\ \n', ...
|
||||
VersionControlIdentifier, ...
|
||||
' TikZ & \\expandafter\\csname ver@tikz.sty\\endcsname \\\\ \n',...
|
||||
' Pgfplots & \\expandafter\\csname ver@pgfplots.sty\\endcsname \\\\ \n',...
|
||||
'\\end{tabular}\n']);
|
||||
|
||||
end
|
||||
% =========================================================================
|
||||
function print_verbatim_information(stream, title, contents)
|
||||
if ~isempty(contents)
|
||||
stream.print(['\\subsubsection*{%s}\n', ...
|
||||
'\\begin{verbatim}\n%s\\end{verbatim}\n'], ...
|
||||
title, contents);
|
||||
end
|
||||
end
|
||||
% =========================================================================
|
||||
function texfile_addtest(stream, status)
|
||||
% Actually add the piece of LaTeX code that'll later be used to display
|
||||
% the given test.
|
||||
if ~status.skip
|
||||
|
||||
ref_error = status.plotStage.error;
|
||||
gen_error = status.tikzStage.error;
|
||||
|
||||
ref_file = status.saveStage.texReference;
|
||||
gen_file = status.tikzStage.pdfFile;
|
||||
|
||||
stream.print(...
|
||||
['\\begin{figure}\n' , ...
|
||||
' \\centering\n' , ...
|
||||
' \\begin{tabular}{cc}\n' , ...
|
||||
' %s & %s \\\\\n' , ...
|
||||
' reference rendering & generated\n' , ...
|
||||
' \\end{tabular}\n' , ...
|
||||
' \\caption{%s \\texttt{%s}, \\texttt{%s(%d)}.%s}\n', ...
|
||||
'\\end{figure}\n' , ...
|
||||
'\\clearpage\n\n'],...
|
||||
include_figure(ref_error, 'includegraphics', ref_file), ...
|
||||
include_figure(gen_error, 'includegraphics', gen_file), ...
|
||||
status.description, ...
|
||||
name2tex(status.function), name2tex(status.testsuite), status.index, ...
|
||||
formatIssuesForTeX(status.issues));
|
||||
end
|
||||
end
|
||||
% =========================================================================
|
||||
function str = include_figure(errorOccured, command, filename)
|
||||
if errorOccured
|
||||
str = sprintf(['\\tikz{\\draw[red,thick] ', ...
|
||||
'(0,0) -- (\\figurewidth,\\figurewidth) ', ...
|
||||
'(0,\\figurewidth) -- (\\figurewidth,0);}']);
|
||||
else
|
||||
switch command
|
||||
case 'includegraphics'
|
||||
strFormat = '\\includegraphics[width=\\figurewidth]{%s}';
|
||||
case 'input'
|
||||
strFormat = '\\input{%s}';
|
||||
otherwise
|
||||
error('Matlab2tikz_acidtest:UnknownFigureCommand', ...
|
||||
'Unknown figure command "%s"', command);
|
||||
end
|
||||
str = sprintf(strFormat, filename);
|
||||
end
|
||||
end
|
||||
% =========================================================================
|
||||
function texfile_tab_completion_init(stream)
|
||||
|
||||
stream.print(['\\clearpage\n\n' , ...
|
||||
'\\begin{table}\n' , ...
|
||||
'\\centering\n' , ...
|
||||
'\\caption{Test case completion summary}\n' , ...
|
||||
'\\begin{tabular}{rlccc}\n' , ...
|
||||
'No. & Test case & Plot & PDF & TikZ \\\\\n' , ...
|
||||
'\\hline\n']);
|
||||
|
||||
end
|
||||
% =========================================================================
|
||||
function texfile_tab_completion_finish(stream)
|
||||
|
||||
stream.print( ['\\end{tabular}\n' , ...
|
||||
'\\end{table}\n\n' ]);
|
||||
|
||||
end
|
||||
% =========================================================================
|
||||
function texName = name2tex(matlabIdentifier)
|
||||
% convert a MATLAB identifier/function handle to a TeX string
|
||||
if isa(matlabIdentifier, 'function_handle')
|
||||
matlabIdentifier = func2str(matlabIdentifier);
|
||||
end
|
||||
texName = strrep(matlabIdentifier, '_', '\_');
|
||||
end
|
||||
% =========================================================================
|
||||
function str = formatIssuesForTeX(issues)
|
||||
% make links to GitHub issues for the LaTeX output
|
||||
issues = issues(:)';
|
||||
if isempty(issues)
|
||||
str = '';
|
||||
return
|
||||
end
|
||||
BASEURL = 'https://github.com/matlab2tikz/matlab2tikz/issues/';
|
||||
SEPARATOR = sprintf(' \n');
|
||||
strs = arrayfun(@(n) sprintf(['\\href{' BASEURL '%d}{\\#%d}'], n,n), issues, ...
|
||||
'UniformOutput', false);
|
||||
strs = [strs; repmat({SEPARATOR}, 1, numel(strs))];
|
||||
str = sprintf('{\\color{blue} \\texttt{%s}}', [strs{:}]);
|
||||
end
|
||||
% ==============================================================================
|
||||
@@ -0,0 +1,74 @@
|
||||
function makeTapReport(status, varargin)
|
||||
% Makes a Test Anything Protocol report
|
||||
%
|
||||
% This function produces a testing report of HEADLESS tests for
|
||||
% display on Jenkins (or any other TAP-compatible system)
|
||||
%
|
||||
% MAKETAPREPORT(status) produces the report from the `status` output of
|
||||
% `testHeadless`.
|
||||
%
|
||||
% MAKETAPREPORT(status, 'stream', FID, ...) changes the filestream to use
|
||||
% to output the report to. (Default: 1 (stdout)).
|
||||
%
|
||||
% TAP Specification: https://testanything.org
|
||||
%
|
||||
% See also: testHeadless, makeTravisReport, makeLatexReport
|
||||
|
||||
%% Parse input arguments
|
||||
SM = StreamMaker();
|
||||
ipp = m2tInputParser();
|
||||
|
||||
ipp = ipp.addRequired(ipp, 'status', @iscell);
|
||||
ipp = ipp.addParamValue(ipp, 'stream', 1, SM.isStream);
|
||||
|
||||
ipp = ipp.parse(ipp, status, varargin{:});
|
||||
arg = ipp.Results;
|
||||
|
||||
%% Construct stream
|
||||
stream = SM.make(arg.stream, 'w');
|
||||
|
||||
%% build report
|
||||
printTAPVersion(stream);
|
||||
printTAPPlan(stream, status);
|
||||
for iStatus = 1:numel(status)
|
||||
printTAPReport(stream, status{iStatus}, iStatus);
|
||||
end
|
||||
end
|
||||
% ==============================================================================
|
||||
function printTAPVersion(stream)
|
||||
% prints the TAP version
|
||||
stream.print('TAP version 13\n');
|
||||
end
|
||||
function printTAPPlan(stream, statuses)
|
||||
% prints the TAP test plan
|
||||
firstTest = 1;
|
||||
lastTest = numel(statuses);
|
||||
stream.print('%d..%d\n', firstTest, lastTest);
|
||||
end
|
||||
function printTAPReport(stream, status, testNum)
|
||||
% prints a TAP test case report
|
||||
message = status.function;
|
||||
|
||||
if hasTestFailed(status)
|
||||
result = 'not ok';
|
||||
else
|
||||
result = 'ok';
|
||||
end
|
||||
directives = getTAPDirectives(status);
|
||||
|
||||
stream.print('%s %d %s %s\n', result, testNum, message, directives);
|
||||
|
||||
%TODO: we can provide more information on the failure using YAML syntax
|
||||
end
|
||||
function directives = getTAPDirectives(status)
|
||||
% add TAP directive (a todo or skip) to the test directives
|
||||
directives = {};
|
||||
if status.skip
|
||||
directives{end+1} = '# SKIP skipped';
|
||||
end
|
||||
if status.unreliable
|
||||
directives{end+1} = '# TODO unreliable';
|
||||
end
|
||||
directives = strtrim(m2tstrjoin(directives, ' '));
|
||||
end
|
||||
% ==============================================================================
|
||||
@@ -0,0 +1,360 @@
|
||||
function [nErrors] = makeTravisReport(status, varargin)
|
||||
% Makes a readable report for Travis/Github of test results
|
||||
%
|
||||
% This function produces a testing report of HEADLESS tests for
|
||||
% display on GitHub and Travis.
|
||||
%
|
||||
% MAKETRAVISREPORT(status) produces the report from the `status` output of
|
||||
% `testHeadless`.
|
||||
%
|
||||
% MAKETRAVISREPORT(status, 'stream', FID, ...) changes the filestream to use
|
||||
% to output the report to. (Default: 1 (stdout)).
|
||||
%
|
||||
% MAKETRAVISREPORT(status, 'length', CHAR, ...) changes the report length.
|
||||
% A few values are possible that cover different aspects in less/more detail.
|
||||
% - 'default': all unreliable tests, failed & skipped tests and summary
|
||||
% - 'short' : only show the brief summary
|
||||
% - 'long' : all tests + summary
|
||||
%
|
||||
% See also: testHeadless, makeLatexReport
|
||||
|
||||
SM = StreamMaker();
|
||||
%% Parse input arguments
|
||||
ipp = m2tInputParser();
|
||||
|
||||
ipp = ipp.addRequired(ipp, 'status', @iscell);
|
||||
ipp = ipp.addParamValue(ipp, 'stream', 1, SM.isStream);
|
||||
ipp = ipp.addParamValue(ipp, 'length', 'default', @isReportLength);
|
||||
|
||||
ipp = ipp.parse(ipp, status, varargin{:});
|
||||
arg = ipp.Results;
|
||||
arg.length = lower(arg.length);
|
||||
stream = SM.make(arg.stream, 'w');
|
||||
|
||||
%% transform status data into groups
|
||||
S = splitStatuses(status);
|
||||
|
||||
%% build report
|
||||
stream.print(gfmHeader(describeEnvironment));
|
||||
reportUnreliableTests(stream, arg, S);
|
||||
reportReliableTests(stream, arg, S);
|
||||
displayTestSummary(stream, S);
|
||||
|
||||
%% set output arguments if needed
|
||||
if nargout >= 1
|
||||
nErrors = countNumberOfErrors(S.reliable);
|
||||
end
|
||||
end
|
||||
% == INPUT VALIDATOR FUNCTIONS =================================================
|
||||
function bool = isReportLength(val)
|
||||
% validates the report length
|
||||
bool = ismember(lower(val), {'default','short','long'});
|
||||
end
|
||||
% == GITHUB-FLAVORED MARKDOWN FUNCTIONS ========================================
|
||||
function str = gfmTable(data, header, alignment)
|
||||
% Construct a Github-flavored Markdown table
|
||||
%
|
||||
% Arguments:
|
||||
% - data: nRows x nCols cell array that represents the data
|
||||
% - header: cell array with the (nCol) column headers
|
||||
% - alignment: alignment specification per column
|
||||
% * 'l': left-aligned (default)
|
||||
% * 'c': centered
|
||||
% * 'r': right-aligned
|
||||
% When not enough entries are specified, the specification is repeated
|
||||
% cyclically.
|
||||
%
|
||||
% Output: table as a string
|
||||
%
|
||||
% See https://help.github.com/articles/github-flavored-markdown/#tables
|
||||
|
||||
% input argument validation and normalization
|
||||
nCols = size(data, 2);
|
||||
if ~exist('alignment','var') || isempty(alignment)
|
||||
alignment = 'l';
|
||||
end
|
||||
if numel(alignment) < nCols
|
||||
% repeat the alignment specifications along the columns
|
||||
alignment = repmat(alignment, 1, nCols);
|
||||
alignment = alignment(1:nCols);
|
||||
end
|
||||
|
||||
% calculate the required column width
|
||||
cellWidth = cellfun(@length, [header(:)' ;data]);
|
||||
columnWidth = max(max(cellWidth, [], 1),3); % use at least 3 places
|
||||
|
||||
% prepare the table format
|
||||
COLSEP = '|'; ROWSEP = sprintf('\n');
|
||||
rowformat = [COLSEP sprintf([' %%%ds ' COLSEP], columnWidth) ROWSEP];
|
||||
alignmentRow = formatAlignment(alignment, columnWidth);
|
||||
|
||||
% actually print the table
|
||||
fullTable = [header; alignmentRow; data];
|
||||
strs = cell(size(fullTable,1), 1);
|
||||
for iRow = 1:numel(strs)
|
||||
thisRow = fullTable(iRow,:);
|
||||
%TODO: maybe preprocess thisRow with strjust first
|
||||
strs{iRow} = sprintf(rowformat, thisRow{:});
|
||||
end
|
||||
str = [strs{:}];
|
||||
|
||||
%---------------------------------------------------------------------------
|
||||
function alignRow = formatAlignment(alignment, columnWidth)
|
||||
% Construct a row of dashes to specify the alignment of each column
|
||||
% See https://help.github.com/articles/github-flavored-markdown/#tables
|
||||
DASH = '-'; COLON = ':';
|
||||
N = numel(columnWidth);
|
||||
alignRow = arrayfun(@(w) repmat(DASH, 1, w), columnWidth, ...
|
||||
'UniformOutput', false);
|
||||
for iColumn = 1:N
|
||||
thisAlign = alignment(iColumn);
|
||||
thisSpec = alignRow{iColumn};
|
||||
switch lower(thisAlign)
|
||||
case 'l'
|
||||
thisSpec(1) = COLON;
|
||||
case 'r'
|
||||
thisSpec(end) = COLON;
|
||||
case 'c'
|
||||
thisSpec([1 end]) = COLON;
|
||||
otherwise
|
||||
error('gfmTable:BadAlignment','Unknown alignment "%s"',...
|
||||
thisAlign);
|
||||
end
|
||||
alignRow{iColumn} = thisSpec;
|
||||
end
|
||||
end
|
||||
end
|
||||
function str = gfmCode(str, inline, language)
|
||||
% Construct a GFM code fragment
|
||||
%
|
||||
% Arguments:
|
||||
% - str: code to be displayed
|
||||
% - inline: - true -> formats inline
|
||||
% - false -> formats as code block
|
||||
% - [] -> automatic mode (default): picks one of the above
|
||||
% - language: which language the code is (enforces a code block)
|
||||
%
|
||||
% Output: GFM formatted string
|
||||
%
|
||||
% See https://help.github.com/articles/github-flavored-markdown
|
||||
if ~exist('inline','var')
|
||||
inline = [];
|
||||
end
|
||||
if ~exist('language','var') || isempty(language)
|
||||
language = '';
|
||||
else
|
||||
inline = false; % highlighting is not supported for inline code
|
||||
end
|
||||
if isempty(inline)
|
||||
inline = isempty(strfind(str, sprintf('\n')));
|
||||
end
|
||||
|
||||
if inline
|
||||
prefix = '`';
|
||||
postfix = '`';
|
||||
else
|
||||
prefix = sprintf('\n```%s\n', language);
|
||||
postfix = sprintf('\n```\n');
|
||||
if str(end) == sprintf('\n')
|
||||
postfix = postfix(2:end); % remove extra endline
|
||||
end
|
||||
end
|
||||
|
||||
str = sprintf('%s%s%s', prefix, str, postfix);
|
||||
end
|
||||
function str = gfmHeader(str, level)
|
||||
% Constructs a GFM/Markdown header
|
||||
if ~exist('level','var')
|
||||
level = 1;
|
||||
end
|
||||
str = sprintf('\n%s %s\n', repmat('#', 1, level), str);
|
||||
end
|
||||
function symbols = githubEmoji()
|
||||
% defines the emojis to signal the test result
|
||||
symbols = struct('pass', ':white_check_mark:', ...
|
||||
'fail', ':heavy_exclamation_mark:', ...
|
||||
'skip', ':grey_question:');
|
||||
end
|
||||
% ==============================================================================
|
||||
function S = splitStatuses(status)
|
||||
% splits a cell array of statuses into a struct of cell arrays
|
||||
% of statuses according to their value of "skip", "reliable" and whether
|
||||
% an error has occured.
|
||||
% See also: splitUnreliableTests, splitPassFailSkippedTests
|
||||
S = struct('all', {status}); % beware of cell array assignment to structs!
|
||||
|
||||
[S.reliable, S.unreliable] = splitUnreliableTests(status);
|
||||
[S.passR, S.failR, S.skipR] = splitPassFailSkippedTests(S.reliable);
|
||||
[S.passU, S.failU, S.skipU] = splitPassFailSkippedTests(S.unreliable);
|
||||
end
|
||||
% ==============================================================================
|
||||
function [short, long] = describeEnvironment()
|
||||
% describes the environment in a short and long format
|
||||
[env, ver] = getEnvironment;
|
||||
[dummy, VCID] = VersionControlIdentifier(); %#ok
|
||||
if ~isempty(VCID)
|
||||
VCID = [' commit ' VCID(1:10)];
|
||||
end
|
||||
OS = OSVersion;
|
||||
short = sprintf('%s %s (%s)', env, ver, OS, VCID);
|
||||
long = sprintf('Test results for m2t%s running with %s %s on %s.', ...
|
||||
VCID, env, ver, OS);
|
||||
end
|
||||
% ==============================================================================
|
||||
function reportUnreliableTests(stream, arg, S)
|
||||
% report on the unreliable tests
|
||||
if ~isempty(S.unreliable) && ~strcmpi(arg.length, 'short')
|
||||
stream.print(gfmHeader('Unreliable tests',2));
|
||||
stream.print('These do not cause the build to fail.\n\n');
|
||||
displayTestResults(stream, S.unreliable);
|
||||
end
|
||||
end
|
||||
function reportReliableTests(stream, arg, S)
|
||||
% report on the reliable tests
|
||||
switch arg.length
|
||||
case 'long'
|
||||
tests = S.reliable;
|
||||
message = '';
|
||||
case 'default'
|
||||
tests = [S.failR; S.skipR];
|
||||
message = 'Passing tests are not shown (only failed and skipped tests).\n\n';
|
||||
case 'short'
|
||||
return; % don't show this part
|
||||
end
|
||||
|
||||
stream.print(gfmHeader('Reliable tests',2));
|
||||
stream.print('Only the reliable tests determine the build outcome.\n');
|
||||
stream.print(message);
|
||||
displayTestResults(stream, tests);
|
||||
end
|
||||
% ==============================================================================
|
||||
function displayTestResults(stream, status)
|
||||
% display a table of specific test outcomes
|
||||
headers = {'Testcase', 'Name', 'OK', 'Status'};
|
||||
data = cell(numel(status), numel(headers));
|
||||
symbols = githubEmoji;
|
||||
for iTest = 1:numel(status)
|
||||
data(iTest,:) = fillTestResultRow(status{iTest}, symbols);
|
||||
end
|
||||
str = gfmTable(data, headers, 'llcl');
|
||||
stream.print('%s', str);
|
||||
end
|
||||
function row = fillTestResultRow(oneStatus, symbol)
|
||||
% format the status of a single test for the summary table
|
||||
testNumber = oneStatus.index;
|
||||
testSuite = func2str(oneStatus.testsuite);
|
||||
summary = '';
|
||||
if oneStatus.skip
|
||||
summary = 'SKIPPED';
|
||||
passOrFail = symbol.skip;
|
||||
else
|
||||
stages = getStagesFromStatus(oneStatus);
|
||||
for jStage = 1:numel(stages)
|
||||
thisStage = oneStatus.(stages{jStage});
|
||||
if ~thisStage.error
|
||||
continue;
|
||||
end
|
||||
stageName = strrep(stages{jStage},'Stage','');
|
||||
switch stageName
|
||||
case 'plot'
|
||||
summary = sprintf('%s plot failed', summary);
|
||||
case 'tikz'
|
||||
summary = sprintf('%s m2t failed', summary);
|
||||
case 'hash'
|
||||
summary = sprintf('new hash %32s != expected (%32s) %s', ...
|
||||
thisStage.found, thisStage.expected, summary);
|
||||
otherwise
|
||||
summary = sprintf('%s %s FAILED', summary, thisStage);
|
||||
end
|
||||
end
|
||||
if isempty(summary)
|
||||
passOrFail = symbol.pass;
|
||||
else
|
||||
passOrFail = symbol.fail;
|
||||
end
|
||||
summary = strtrim(summary);
|
||||
end
|
||||
row = { gfmCode(sprintf('%s(%d)', testSuite, testNumber)), ...
|
||||
gfmCode(oneStatus.function), ...
|
||||
passOrFail, ...
|
||||
summary};
|
||||
end
|
||||
% ==============================================================================
|
||||
function displayTestSummary(stream, S)
|
||||
% display a table of # of failed/passed/skipped tests vs (un)reliable
|
||||
|
||||
% compute number of cases per category
|
||||
reliableSummary = cellfun(@numel, {S.passR, S.failR, S.skipR});
|
||||
unreliableSummary = cellfun(@numel, {S.passU, S.failU, S.skipU});
|
||||
|
||||
% make summary table + calculate totals
|
||||
summary = [unreliableSummary numel(S.unreliable);
|
||||
reliableSummary numel(S.reliable);
|
||||
reliableSummary+unreliableSummary numel(S.all)];
|
||||
|
||||
% put results into cell array with proper layout
|
||||
summary = arrayfun(@(v) sprintf('%d',v), summary, 'UniformOutput', false);
|
||||
table = repmat({''}, 3, 5);
|
||||
header = {'','Pass','Fail','Skip','Total'};
|
||||
table(:,1) = {'Unreliable','Reliable','Total'};
|
||||
table(:,2:end) = summary;
|
||||
|
||||
% print table
|
||||
[envShort, envDescription] = describeEnvironment(); %#ok
|
||||
stream.print(gfmHeader('Test summary', 2));
|
||||
stream.print('%s\n', envDescription);
|
||||
stream.print('%s\n', gfmCode(generateCode(S),false,'matlab'));
|
||||
stream.print(gfmTable(table, header, 'lrrrr'));
|
||||
|
||||
% print overall outcome
|
||||
symbol = githubEmoji;
|
||||
nErrors = numel(S.failR);
|
||||
if nErrors == 0
|
||||
stream.print('\nBuild passes. %s\n', symbol.pass);
|
||||
else
|
||||
stream.print('\nBuild fails with %d errors. %s\n', nErrors, symbol.fail);
|
||||
end
|
||||
end
|
||||
function code = generateCode(S)
|
||||
% generates some MATLAB code to easily replicate the results
|
||||
code = sprintf('%s = %s;\n', ...
|
||||
'suite', ['@' func2str(S.all{1}.testsuite)], ...
|
||||
'alltests', testNumbers(S.all), ...
|
||||
'reliable', testNumbers(S.reliable), ...
|
||||
'unreliable', testNumbers(S.unreliable), ...
|
||||
'failReliable', testNumbers(S.failR), ...
|
||||
'passUnreliable', testNumbers(S.passU), ...
|
||||
'skipped', testNumbers([S.skipR; S.skipU]));
|
||||
% --------------------------------------------------------------------------
|
||||
function str = testNumbers(status)
|
||||
str = intelligentVector( cellfun(@(s) s.index, status) );
|
||||
end
|
||||
end
|
||||
function str = intelligentVector(numbers)
|
||||
% Produce a string that is an intelligent vector notation of its arguments
|
||||
% e.g. when numbers = [ 1 2 3 4 6 7 8 9 ], it should return '[ 1:4 6:9 ]'
|
||||
% The order in the vector is not retained!
|
||||
|
||||
if isempty(numbers)
|
||||
str = '[]';
|
||||
else
|
||||
numbers = sort(numbers(:).');
|
||||
delta = diff([numbers(1)-1 numbers]);
|
||||
% place virtual bounds at the first element and beyond the last one
|
||||
bounds = [1 find(delta~=1) numel(numbers)+1];
|
||||
idx = 1:(numel(bounds)-1); % start index of each segment
|
||||
start = numbers(bounds(idx ) );
|
||||
stop = numbers(bounds(idx+1)-1);
|
||||
parts = arrayfun(@formatRange, start, stop, 'UniformOutput', false);
|
||||
str = sprintf('[%s]', strtrim(sprintf('%s ', parts{:})));
|
||||
end
|
||||
end
|
||||
function str = formatRange(start, stop)
|
||||
% format a range [start:stop] of integers in MATLAB syntax
|
||||
if start==stop
|
||||
str = sprintf('%d',start);
|
||||
else
|
||||
str = sprintf('%d:%d',start, stop);
|
||||
end
|
||||
end
|
||||
% ==============================================================================
|
||||