diff --git a/GIV_GUI_initialize.m b/GIV_GUI_initialize.m new file mode 100644 index 0000000..27b88fb --- /dev/null +++ b/GIV_GUI_initialize.m @@ -0,0 +1,1243 @@ +function GIV_GUI_initialize() +% +% +%This function starts off the main image velocity calculation code. It will +%open a graphical user interface where the different input values can be +%entered, and then run the functions to calcuate velocities for each image +%pair inputted. +% +% +%Note this can take a long time (hours) for very large datasets, it is +%sometimes worth testing it with smaller datasets to begin with (and/or +%using low temporal oversampling values). +% +%Most of this very long file is simply setting the location of the boxes, +%etc. Portions were generated automatically using MATLAB's app builder. You +%can tweak it to improve layout if you like, but I would not recommend +%changing it very much. + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + + +%% Make sure to add functions to matlab path so that they are accessible +if ~isdeployed +addpath(genpath(pwd)); +end +%Create array to hold all the components in + +GUIinputs = []; + + +%% This portion of the code generated the GUI and input boxes. It is not very interesting. + +% Create UIFigure and hide until all components are created + GUIFigure = uifigure('Visible', 'off'); + GUIFigure.Position = [100 100 656 736]; + GUIFigure.Name = 'GLACIER IMAGE VELOCIMETRY'; + + % Create TabGroup + TabGroup = uitabgroup(GUIFigure); + TabGroup.Position = [1 194 660 543]; + + % Create REQUIREDINPUTSTab + REQUIREDINPUTSTab = uitab(TabGroup); + REQUIREDINPUTSTab.Title = ' REQUIRED INPUTS '; + + % Create PathtoimagesfolderEditFieldLabel + PathtoimagesfolderEditFieldLabel = uilabel(REQUIREDINPUTSTab); + PathtoimagesfolderEditFieldLabel.HorizontalAlignment = 'right'; + PathtoimagesfolderEditFieldLabel.FontName = 'Cambria'; + PathtoimagesfolderEditFieldLabel.Position = [209 305 113 22]; + PathtoimagesfolderEditFieldLabel.Text = 'Path to images folder'; + + % Create PathtoimagesfolderEditField + PathtoimagesfolderEditField = uieditfield(REQUIREDINPUTSTab, 'text'); + PathtoimagesfolderEditField.Position = [337 305 100 22]; + PathtoimagesfolderEditField.Value = 'C:/EXAMPLE/PATH/TO/IMAGES'; + + % Create Image + Image = uiimage(REQUIREDINPUTSTab); + Image.Position = [146 355 347 154]; + Image.ImageSource = 'logo.png'; + + % Create BASICINPUTSREQUIREDLabel + BASICINPUTSREQUIREDLabel = uilabel(REQUIREDINPUTSTab); + BASICINPUTSREQUIREDLabel.FontName = 'Cambria'; + BASICINPUTSREQUIREDLabel.FontSize = 15; + BASICINPUTSREQUIREDLabel.FontWeight = 'bold'; + BASICINPUTSREQUIREDLabel.Position = [236 344 191 22]; + BASICINPUTSREQUIREDLabel.Text = 'BASIC INPUTS (REQUIRED)'; + + + % Create MinimumLatitudeLabel + MinimumLatitudeLabel = uilabel(REQUIREDINPUTSTab); + MinimumLatitudeLabel.HorizontalAlignment = 'right'; + MinimumLatitudeLabel.FontName = 'Cambria'; + MinimumLatitudeLabel.Position = [213 271 109 22]; + MinimumLatitudeLabel.Text = 'Minimum Latitude '; + + % Create MinimumLatitudeEditField + MinimumLatitudeEditField = uieditfield(REQUIREDINPUTSTab, 'numeric'); + MinimumLatitudeEditField.Position = [337 271 100 22]; + MinimumLatitudeEditField.Value = -50.9640; + + % Create MaximumLatitudeEditFieldLabel + MaximumLatitudeEditFieldLabel = uilabel(REQUIREDINPUTSTab); + MaximumLatitudeEditFieldLabel.HorizontalAlignment = 'right'; + MaximumLatitudeEditFieldLabel.FontName = 'Cambria'; + MaximumLatitudeEditFieldLabel.Position = [212 237 110 22]; + MaximumLatitudeEditFieldLabel.Text = 'Maximum Latitude '; + + % Create MaximumLatitudeEditField + MaximumLatitudeEditField = uieditfield(REQUIREDINPUTSTab, 'numeric'); + MaximumLatitudeEditField.Position = [337 237 100 22]; + MaximumLatitudeEditField.Value = -50.8920; + + % Create MinimumLongitudeEditFieldLabel + MinimumLongitudeEditFieldLabel = uilabel(REQUIREDINPUTSTab); + MinimumLongitudeEditFieldLabel.HorizontalAlignment = 'right'; + MinimumLongitudeEditFieldLabel.FontName = 'Cambria'; + MinimumLongitudeEditFieldLabel.Position = [207 205 115 22]; + MinimumLongitudeEditFieldLabel.Text = 'Minimum Longitude '; + + % Create MinimumLongitudeEditField + MinimumLongitudeEditField = uieditfield(REQUIREDINPUTSTab, 'numeric'); + MinimumLongitudeEditField.Position = [337 205 100 22]; + MinimumLongitudeEditField.Value = -73.7460; + + % Create MaximumLongitudeEditFieldLabel + MaximumLongitudeEditFieldLabel = uilabel(REQUIREDINPUTSTab); + MaximumLongitudeEditFieldLabel.HorizontalAlignment = 'right'; + MaximumLongitudeEditFieldLabel.FontName = 'Cambria'; + MaximumLongitudeEditFieldLabel.Position = [208 170 114 22]; + MaximumLongitudeEditFieldLabel.Text = 'Maximum Longitude '; + + % Create MaximumLongitudeEditField + MaximumLongitudeEditField = uieditfield(REQUIREDINPUTSTab, 'numeric'); + MaximumLongitudeEditField.Position = [337 170 100 22]; + MaximumLongitudeEditField.Value = -73.4730; + + + % Create ParralelizeCodeLabel + geotiffinputLabel = uilabel(REQUIREDINPUTSTab); + geotiffinputLabel.FontName = 'Cambria'; + geotiffinputLabel.Position = [515 250 110 22]; + geotiffinputLabel.Text = 'geoTiff input?'; + + % Create geotiffinput + geotiffinputSwitch = uiswitch(REQUIREDINPUTSTab, 'slider'); + geotiffinputSwitch.Items = {'No', 'Yes'}; + geotiffinputSwitch.FontName = 'Cambria'; + geotiffinputSwitch.Position = [525 220 110 22]; + geotiffinputSwitch.Value = 'Yes'; + + + % Create TimeoversamplingfactorEditFieldLabel + TimeoversamplingfactorEditFieldLabel = uilabel(REQUIREDINPUTSTab); + TimeoversamplingfactorEditFieldLabel.HorizontalAlignment = 'right'; + TimeoversamplingfactorEditFieldLabel.FontName = 'Cambria'; + TimeoversamplingfactorEditFieldLabel.Position = [185 134 137 22]; + TimeoversamplingfactorEditFieldLabel.Text = 'Time oversampling factor'; + + % Create TimeoversamplingfactorEditField + TimeoversamplingfactorEditField = uieditfield(REQUIREDINPUTSTab, 'numeric'); + TimeoversamplingfactorEditField.Position = [337 134 100 22]; + TimeoversamplingfactorEditField.Value = 1; + + % Create ParralelizecodeSwitch + ParralelizecodeSwitch = uiswitch(REQUIREDINPUTSTab, 'slider'); + ParralelizecodeSwitch.Items = {'No', 'Yes'}; + ParralelizecodeSwitch.FontName = 'Cambria'; + ParralelizecodeSwitch.Position = [309 15 45 20]; + ParralelizecodeSwitch.Value = 'Yes'; + + + % Create FilenametosaveasEditFieldLabel + FilenametosaveasEditFieldLabel = uilabel(REQUIREDINPUTSTab); + FilenametosaveasEditFieldLabel.HorizontalAlignment = 'right'; + FilenametosaveasEditFieldLabel.FontName = 'Cambria'; + FilenametosaveasEditFieldLabel.Position = [215 99 107 22]; + FilenametosaveasEditFieldLabel.Text = 'File name to save as'; + + % Create FilenametosaveasEditField + FilenametosaveasEditField = uieditfield(REQUIREDINPUTSTab, 'text'); + FilenametosaveasEditField.Position = [337 99 100 22]; + FilenametosaveasEditField.Value = 'Glacier Velocities 1'; + + + + % Create ParralelizeCodeLabel + ParralelizeCodeLabel = uilabel(REQUIREDINPUTSTab); + ParralelizeCodeLabel.Position = [282 48 101 22]; + ParralelizeCodeLabel.FontName = 'Cambria'; + ParralelizeCodeLabel.Text = 'Parralelize Code?'; + + % Create SelectButton + SelectButton = uibutton(REQUIREDINPUTSTab, 'push'); + SelectButton.BackgroundColor = [0.8 0.8 0.8]; + SelectButton.FontName = 'Cambria'; + SelectButton.FontWeight = 'bold'; + SelectButton.Position = [517 305 100 23]; + SelectButton.Text = 'Select'; + SelectButton.ButtonPushedFcn = @(btn,event) plotButtonPushed1(btn,GUIinputs); + + + % Create orLabel + orLabel = uilabel(REQUIREDINPUTSTab); + orLabel.FontName = 'Cambria'; + orLabel.Position = [468 305 25 22]; + orLabel.Text = 'or'; + + % Create AdvancedInputsTab + AdvancedInputsTab = uitab(TabGroup); + AdvancedInputsTab.Title = ' Advanced Inputs '; + + % Create Image_2 + Image_2 = uiimage(AdvancedInputsTab); + Image_2.Position = [146 355 347 154]; + Image_2.ImageSource = 'logo.png'; + + % Create TabGroup2 + TabGroup2 = uitabgroup(AdvancedInputsTab); + TabGroup2.Position = [1 1 659 368]; + + % Create TemplatematchingTab + TemplatematchingTab = uitab(TabGroup2); + TemplatematchingTab.Title = ' Template matching '; + + % Create Switch + Switch = uiswitch(TemplatematchingTab, 'slider'); + Switch.Items = {'Single Pass', 'Multipass'}; + Switch.FontName = 'Cambria'; + Switch.Position = [308 311 45 20]; + Switch.Value = 'Multipass'; + + + + % Create SignaltonoiseratioEditFieldLabel + SignaltonoiseratioEditFieldLabel = uilabel(TemplatematchingTab); + SignaltonoiseratioEditFieldLabel.HorizontalAlignment = 'right'; + SignaltonoiseratioEditFieldLabel.FontName = 'Cambria'; + SignaltonoiseratioEditFieldLabel.Position = [208 215 106 22]; + SignaltonoiseratioEditFieldLabel.Text = 'Signal to noise ratio'; + + % Create SignaltonoiseratioEditField + SignaltonoiseratioEditField = uieditfield(TemplatematchingTab, 'numeric'); + SignaltonoiseratioEditField.Position = [329 215 100 22]; + if strcmpi(Switch.Value,'Multipass') + SignaltonoiseratioEditField.Value = 1.3; + else + SignaltonoiseratioEditField.Value = 5; + end + + + + + +% % Create MultipassoptionsLabel +% MultipassoptionsLabel = uilabel(TemplatematchingTab); +% MultipassoptionsLabel.FontName = 'Cambria'; +% MultipassoptionsLabel.Position = [447 259 97 22]; +% MultipassoptionsLabel.Text = 'Multipass options'; +% +% % Create WindowmatchoverlapEditFieldLabel +% WindowmatchoverlapEditFieldLabel = uilabel(TemplatematchingTab); +% WindowmatchoverlapEditFieldLabel.HorizontalAlignment = 'right'; +% WindowmatchoverlapEditFieldLabel.FontName = 'Cambria'; +% WindowmatchoverlapEditFieldLabel.Position = [387 210 124 22]; +% WindowmatchoverlapEditFieldLabel.Text = 'Window match overlap'; +% +% % Create WindowmatchoverlapEditField +% WindowmatchoverlapEditField = uieditfield(TemplatematchingTab, 'numeric'); +% WindowmatchoverlapEditField.Position = [526 210 100 22]; +% WindowmatchoverlapEditField.Value = 0.5; +% +% % Create MatchwindowsizeEditFieldLabel +% MatchwindowsizeEditFieldLabel = uilabel(TemplatematchingTab); +% MatchwindowsizeEditFieldLabel.HorizontalAlignment = 'right'; +% MatchwindowsizeEditFieldLabel.FontName = 'Cambria'; +% MatchwindowsizeEditFieldLabel.Position = [408 170 103 22]; +% MatchwindowsizeEditFieldLabel.Text = 'Match window size'; +% +% % Create MatchwindowsizeEditField +% MatchwindowsizeEditField = uieditfield(TemplatematchingTab, 'numeric'); +% MatchwindowsizeEditField.FontName = 'Cambria'; +% MatchwindowsizeEditField.Position = [526 170 100 22]; +% MatchwindowsizeEditField.Value = 64; +% +% +% +% +% % Create SinglepassoptionsLabel +% SinglepassoptionsLabel = uilabel(TemplatematchingTab); +% SinglepassoptionsLabel.FontName = 'Cambria'; +% SinglepassoptionsLabel.Position = [89 259 103 22]; +% SinglepassoptionsLabel.Text = 'Single pass options'; + + % Create IdealresolutionofoutputdataEditFieldLabel + IdealresolutionofoutputdataEditFieldLabel = uilabel(TemplatematchingTab); + IdealresolutionofoutputdataEditFieldLabel.HorizontalAlignment = 'right'; + IdealresolutionofoutputdataEditFieldLabel.FontName = 'Cambria'; + IdealresolutionofoutputdataEditFieldLabel.Position = [152 259 161 22]; + IdealresolutionofoutputdataEditFieldLabel.Text = 'Ideal resolution of output data'; + + % Create IdealresolutionofoutputdataEditField + IdealresolutionofoutputdataEditField = uieditfield(TemplatematchingTab, 'numeric'); + IdealresolutionofoutputdataEditField.Position = [328 259 100 22]; + IdealresolutionofoutputdataEditField.Value = 50; + + +% % Create SearchwindowSizeEditFieldLabel +% SearchwindowSizeEditFieldLabel = uilabel(TemplatematchingTab); +% SearchwindowSizeEditFieldLabel.HorizontalAlignment = 'right'; +% SearchwindowSizeEditFieldLabel.FontName = 'Cambria'; +% SearchwindowSizeEditFieldLabel.Position = [77 170 107 22]; +% SearchwindowSizeEditFieldLabel.Text = 'Search window Size'; +% +% % Create SearchwindowSizeEditField +% SearchwindowSizeEditField = uieditfield(TemplatematchingTab, 'numeric'); +% SearchwindowSizeEditField.Position = [199 170 100 22]; +% SearchwindowSizeEditField.Value = 30; +% +% % Create MinimumsearchareaEditFieldLabel +% MinimumsearchareaEditFieldLabel = uilabel(TemplatematchingTab); +% MinimumsearchareaEditFieldLabel.HorizontalAlignment = 'right'; +% MinimumsearchareaEditFieldLabel.FontName = 'Cambria'; +% MinimumsearchareaEditFieldLabel.Position = [68 132 116 22]; +% MinimumsearchareaEditFieldLabel.Text = 'Minimum search area'; +% +% % Create MinimumsearchareaEditField +% MinimumsearchareaEditField = uieditfield(TemplatematchingTab, 'numeric'); +% MinimumsearchareaEditField.Position = [199 132 100 22]; +% MinimumsearchareaEditField.Value = 50; + + + % Create DateoptionsTab + DateoptionsTab = uitab(TabGroup2); + DateoptionsTab.Title = ' Date options '; + + % Create MinimumYearEditFieldLabel + MinimumYearEditFieldLabel = uilabel(DateoptionsTab); + MinimumYearEditFieldLabel.HorizontalAlignment = 'right'; + MinimumYearEditFieldLabel.FontName = 'Cambria'; + MinimumYearEditFieldLabel.Position = [245 288 85 22]; + MinimumYearEditFieldLabel.Text = 'Minimum Year '; + + % Create MinimumYearEditField + MinimumYearEditField = uieditfield(DateoptionsTab, 'numeric'); + MinimumYearEditField.Position = [345 288 100 22]; + MinimumYearEditField.Value = 1900; + + % Create MaximumYearEditFieldLabel + MaximumYearEditFieldLabel = uilabel(DateoptionsTab); + MaximumYearEditFieldLabel.HorizontalAlignment = 'right'; + MaximumYearEditFieldLabel.FontName = 'Cambria'; + MaximumYearEditFieldLabel.Position = [243 254 87 22]; + MaximumYearEditFieldLabel.Text = 'Maximum Year '; + + % Create MaximumYearEditField + MaximumYearEditField = uieditfield(DateoptionsTab, 'numeric'); + MaximumYearEditField.Position = [345 254 100 22]; + MaximumYearEditField.Value = 2050; + + + % Create MinimumMonthEditFieldLabel + MinimumMonthEditFieldLabel = uilabel(DateoptionsTab); + MinimumMonthEditFieldLabel.HorizontalAlignment = 'right'; + MinimumMonthEditFieldLabel.FontName = 'Cambria'; + MinimumMonthEditFieldLabel.Position = [239 222 91 22]; + MinimumMonthEditFieldLabel.Text = 'Minimum Month'; + + % Create MinimumMonthEditField + MinimumMonthEditField = uieditfield(DateoptionsTab, 'numeric'); + MinimumMonthEditField.Position = [345 222 100 22]; + MinimumMonthEditField.Value = 1; + + % Create MaximumMonthEditFieldLabel + MaximumMonthEditFieldLabel = uilabel(DateoptionsTab); + MaximumMonthEditFieldLabel.HorizontalAlignment = 'right'; + MaximumMonthEditFieldLabel.FontName = 'Cambria'; + MaximumMonthEditFieldLabel.Position = [237 187 93 22]; + MaximumMonthEditFieldLabel.Text = 'Maximum Month'; + + % Create MaximumMonthEditField + MaximumMonthEditField = uieditfield(DateoptionsTab, 'numeric'); + MaximumMonthEditField.Position = [345 187 100 22]; + MaximumMonthEditField.Value = 12; + + + + % Create MinimumDayEditFieldLabel + MinimumDayEditFieldLabel = uilabel(DateoptionsTab); + MinimumDayEditFieldLabel.HorizontalAlignment = 'right'; + MinimumDayEditFieldLabel.FontName = 'Cambria'; + MinimumDayEditFieldLabel.Position = [253 152 77 22]; + MinimumDayEditFieldLabel.Text = 'Minimum Day'; + + % Create MinimumDayEditField + MinimumDayEditField = uieditfield(DateoptionsTab, 'numeric'); + MinimumDayEditField.Position = [345 152 100 22]; + MinimumDayEditField.Value = 1; + + % Create MaximumDayEditFieldLabel + MaximumDayEditFieldLabel = uilabel(DateoptionsTab); + MaximumDayEditFieldLabel.HorizontalAlignment = 'right'; + MaximumDayEditFieldLabel.FontName = 'Cambria'; + MaximumDayEditFieldLabel.Position = [251 117 79 22]; + MaximumDayEditFieldLabel.Text = 'Maximum Day'; + + % Create MaximumDayEditField + MaximumDayEditField = uieditfield(DateoptionsTab, 'numeric'); + MaximumDayEditField.Position = [345 117 100 22]; + MaximumDayEditField.Value = 31; + + + % Create MinimumintervalforimagepairsEditFieldLabel + MinimumintervalforimagepairsEditFieldLabel = uilabel(DateoptionsTab); + MinimumintervalforimagepairsEditFieldLabel.HorizontalAlignment = 'right'; + MinimumintervalforimagepairsEditFieldLabel.FontName = 'Cambria'; + MinimumintervalforimagepairsEditFieldLabel.Position = [153 70 177 22]; + MinimumintervalforimagepairsEditFieldLabel.Text = 'Minimum interval for image pairs'; + + % Create MinimumintervalforimagepairsEditField + MinimumintervalforimagepairsEditField = uieditfield(DateoptionsTab, 'numeric'); + MinimumintervalforimagepairsEditField.Position = [345 70 100 22]; + MinimumintervalforimagepairsEditField.Value = 0.019; + + + % Create MaximumintervalforimagepairsEditFieldLabel + MaximumintervalforimagepairsEditFieldLabel = uilabel(DateoptionsTab); + MaximumintervalforimagepairsEditFieldLabel.HorizontalAlignment = 'right'; + MaximumintervalforimagepairsEditFieldLabel.FontName = 'Cambria'; + MaximumintervalforimagepairsEditFieldLabel.Position = [151 35 179 22]; + MaximumintervalforimagepairsEditFieldLabel.Text = 'Maximum interval for image pairs'; + + % Create MaximumintervalforimagepairsEditField + MaximumintervalforimagepairsEditField = uieditfield(DateoptionsTab, 'numeric'); + MaximumintervalforimagepairsEditField.FontName = 'Cambria'; + MaximumintervalforimagepairsEditField.Position = [345 35 100 22]; + MaximumintervalforimagepairsEditField.Value = 0.75; + + + % Create ImagefilteringTab + ImagefilteringTab = uitab(TabGroup2); + ImagefilteringTab.Title = ' Image filtering '; + + % Create Switch_2 + Switch_2 = uiswitch(ImagefilteringTab, 'slider'); + Switch_2.Items = {'OFF', 'ON'}; + Switch_2.FontName = 'Cambria'; + Switch_2.Position = [200 293 45 20]; + Switch_2.Value = 'OFF'; + + % Create ContrastLimitedHistogramEqualisationLabel + ContrastLimitedHistogramEqualisationLabel = uilabel(ImagefilteringTab); + ContrastLimitedHistogramEqualisationLabel.Position = [123 319 220 22]; + ContrastLimitedHistogramEqualisationLabel.Text = 'Contrast Limited Histogram Equalisation'; + + % Create Switch_3 + Switch_3 = uiswitch(ImagefilteringTab, 'slider'); + Switch_3.Items = {'OFF', 'ON'}; + Switch_3.FontName = 'Cambria'; + Switch_3.Position = [201 240 45 20]; + Switch_3.Value = 'OFF'; + + % Create HighpassFilterLabel + HighpassFilterLabel = uilabel(ImagefilteringTab); + HighpassFilterLabel.Position = [180 266 85 22]; + HighpassFilterLabel.Text = 'Highpass Filter'; + + + % Create Switch_4 + Switch_4 = uiswitch(ImagefilteringTab, 'slider'); + Switch_4.Items = {'OFF', 'ON'}; + Switch_4.FontName = 'Cambria'; + Switch_4.Position = [202 191 45 20]; + Switch_4.Value = 'OFF'; + + % Create IntensityCapLabel + IntensityCapLabel = uilabel(ImagefilteringTab); + IntensityCapLabel.Position = [187 215 75 22]; + IntensityCapLabel.Text = 'Intensity Cap'; + + + % Create Switch_5 + Switch_5 = uiswitch(ImagefilteringTab, 'slider'); + Switch_5.Items = {'OFF', 'ON'}; + Switch_5.FontName = 'Cambria'; + Switch_5.Position = [201 130 45 20]; + Switch_5.Value = 'ON'; + + % Create OrientationFilterLabel + OrientationFilterLabel = uilabel(ImagefilteringTab); + OrientationFilterLabel.Position = [178 154 94 22]; + OrientationFilterLabel.Text = 'Orientation Filter'; + + + + % Create CLAHEsizeEditFieldLabel + CLAHEsizeEditFieldLabel = uilabel(ImagefilteringTab); + CLAHEsizeEditFieldLabel.HorizontalAlignment = 'right'; + CLAHEsizeEditFieldLabel.Position = [384 298 70 22]; + CLAHEsizeEditFieldLabel.Text = 'CLAHE size'; + + % Create CLAHEsizeEditField + CLAHEsizeEditField = uieditfield(ImagefilteringTab, 'numeric'); + CLAHEsizeEditField.Position = [469 298 100 22]; + CLAHEsizeEditField.Value = 10; + + + + + % Create HighpasssizeEditFieldLabel + HighpasssizeEditFieldLabel = uilabel(ImagefilteringTab); + HighpasssizeEditFieldLabel.HorizontalAlignment = 'right'; + HighpasssizeEditFieldLabel.Position = [375 245 80 22]; + HighpasssizeEditFieldLabel.Text = 'Highpass size'; + + % Create HighpasssizeEditField + HighpasssizeEditField = uieditfield(ImagefilteringTab, 'numeric'); + HighpasssizeEditField.Position = [470 245 100 22]; + HighpasssizeEditField.Value = 10; + + + + % Create Switch_10 + Switch_10 = uiswitch(ImagefilteringTab, 'slider'); + Switch_10.Items = {'OFF', 'ON'}; + Switch_10.FontName = 'Cambria'; + Switch_10.Position = [202 70 45 20]; + Switch_10.Value = 'OFF'; + + % Create Sobel Filter + Sobel_Filter = uilabel(ImagefilteringTab); + Sobel_Filter.Position = [187 94 75 22]; + Sobel_Filter.Text = 'Sobel Filter'; + + + % Create Switch_11 + Switch_11 = uiswitch(ImagefilteringTab, 'slider'); + Switch_11.Items = {'OFF', 'ON'}; + Switch_11.FontName = 'Cambria'; + Switch_11.Position = [201 9 45 20]; + Switch_11.Value = 'OFF'; + + % Create OrientationFilterLabel_2 + Laplacian_filter = uilabel(ImagefilteringTab); + Laplacian_filter.Position = [178 33 94 22]; + Laplacian_filter.Text = 'Laplacian filter'; + + + % Create SavingTab + SavingTab = uitab(TabGroup2); + SavingTab.Title = ' Saving '; + + % Create Switch_6 + Switch_6 = uiswitch(SavingTab, 'slider'); + Switch_6.Items = {'OFF', 'ON'}; + Switch_6.FontName = 'Cambria'; + Switch_6.Position = [298 275 45 20]; + Switch_6.Value = 'ON'; + + % Create SaveMATLABdataarraysLabel + SaveMATLABdataarraysLabel = uilabel(SavingTab); + SaveMATLABdataarraysLabel.Position = [254 302 153 22]; + SaveMATLABdataarraysLabel.Text = 'Save MATLAB data arrays?'; + + + % Create Switch_7 + Switch_7 = uiswitch(SavingTab, 'slider'); + Switch_7.Items = {'OFF', 'ON'}; + Switch_7.FontName = 'Cambria'; + Switch_7.Position = [298 198 45 20]; + Switch_7.Value = 'ON'; + + % Create Switch_8 + Switch_8 = uiswitch(SavingTab, 'slider'); + Switch_8.Items = {'OFF', 'ON'}; + Switch_8.FontName = 'Cambria'; + Switch_8.Position = [299 19 45 20]; + Switch_8.Value = 'ON'; + + % Create SavegeoreferencedtifimagesLabel + SavegeoreferencedtifimagesLabel = uilabel(SavingTab); + SavegeoreferencedtifimagesLabel.Position = [233 46 178 22]; + SavegeoreferencedtifimagesLabel.Text = 'Save georeferenced .tif images?'; + + % Create SaveimagesofkeyvelocitiesLabel + SaveimagesofkeyvelocitiesLabel = uilabel(SavingTab); + SaveimagesofkeyvelocitiesLabel.Position = [237 229 169 22]; + SaveimagesofkeyvelocitiesLabel.Text = 'Save images of key velocities?'; + + + % Create FormatofimagestosaveEditFieldLabel + FormatofimagestosaveEditFieldLabel = uilabel(SavingTab); + FormatofimagestosaveEditFieldLabel.HorizontalAlignment = 'right'; + FormatofimagestosaveEditFieldLabel.Position = [147 119 141 22]; + FormatofimagestosaveEditFieldLabel.Text = 'Format of images to save'; + + % Create FormatofimagestosaveEditField + FormatofimagestosaveEditField = uieditfield(SavingTab, 'text'); + FormatofimagestosaveEditField.Position = [303 119 100 22]; + FormatofimagestosaveEditField.Value = 'png'; + + + % Create OtherTab + OtherTab = uitab(TabGroup2); + OtherTab.Title = ' Other '; + + % Create MaximumVelocityEditFieldLabel + MaximumVelocityEditFieldLabel = uilabel(OtherTab); + MaximumVelocityEditFieldLabel.HorizontalAlignment = 'right'; + MaximumVelocityEditFieldLabel.FontName = 'Cambria'; + MaximumVelocityEditFieldLabel.Position = [222 300 100 22]; + MaximumVelocityEditFieldLabel.Text = 'Maximum Velocity'; + + % Create MaximumVelocityEditField + MaximumVelocityEditField = uieditfield(OtherTab, 'numeric'); + MaximumVelocityEditField.Position = [337 300 100 22]; + MaximumVelocityEditField.Value = 2500; + + % Create Excludedangle1minimumEditFieldLabel + Excludedangle1minimumEditFieldLabel = uilabel(OtherTab); + Excludedangle1minimumEditFieldLabel.HorizontalAlignment = 'right'; + Excludedangle1minimumEditFieldLabel.FontName = 'Cambria'; + Excludedangle1minimumEditFieldLabel.Position = [58 210 144 22]; + Excludedangle1minimumEditFieldLabel.Text = 'Excluded angle 1 minimum'; + + % Create Excludedangle1minimumEditField + Excludedangle1minimumEditField = uieditfield(OtherTab, 'numeric'); + Excludedangle1minimumEditField.Position = [217 210 100 22]; + + % Create Excludedangle2minimumEditFieldLabel + Excludedangle2minimumEditFieldLabel = uilabel(OtherTab); + Excludedangle2minimumEditFieldLabel.HorizontalAlignment = 'right'; + Excludedangle2minimumEditFieldLabel.FontName = 'Cambria'; + Excludedangle2minimumEditFieldLabel.Position = [58 174 144 22]; + Excludedangle2minimumEditFieldLabel.Text = 'Excluded angle 2 minimum'; + + % Create Excludedangle2minimumEditField + Excludedangle2minimumEditField = uieditfield(OtherTab, 'numeric'); + Excludedangle2minimumEditField.Position = [217 174 100 22]; + Excludedangle2minimumEditField.Value = 360; + + % Create Excludedangle2maximumEditFieldLabel + Excludedangle2maximumEditFieldLabel = uilabel(OtherTab); + Excludedangle2maximumEditFieldLabel.HorizontalAlignment = 'right'; + Excludedangle2maximumEditFieldLabel.FontName = 'Cambria'; + Excludedangle2maximumEditFieldLabel.Position = [353 174 146 22]; + Excludedangle2maximumEditFieldLabel.Text = 'Excluded angle 2 maximum'; + + % Create Excludedangle2maximumEditField + Excludedangle2maximumEditField = uieditfield(OtherTab, 'numeric'); + Excludedangle2maximumEditField.Position = [514 174 100 22]; + Excludedangle2maximumEditField.Value = 360; + + % Create Excludedangle1maximumEditFieldLabel + Excludedangle1maximumEditFieldLabel = uilabel(OtherTab); + Excludedangle1maximumEditFieldLabel.HorizontalAlignment = 'right'; + Excludedangle1maximumEditFieldLabel.FontName = 'Cambria'; + Excludedangle1maximumEditFieldLabel.Position = [353 210 146 22]; + Excludedangle1maximumEditFieldLabel.Text = 'Excluded angle 1 maximum'; + + % Create Excludedangle1maximumEditField + Excludedangle1maximumEditField = uieditfield(OtherTab, 'numeric'); + Excludedangle1maximumEditField.Position = [514 210 100 22]; + + +% % % % Create MinimumangleEditFieldLabel +% % % MinimumangleEditFieldLabel = uilabel(OtherTab); +% % % MinimumangleEditFieldLabel.HorizontalAlignment = 'right'; +% % % MinimumangleEditFieldLabel.FontName = 'Cambria'; +% % % MinimumangleEditFieldLabel.Position = [230 187 85 22]; +% % % MinimumangleEditFieldLabel.Text = 'Minimum angle'; +% % % +% % % % Create MinimumangleEditField +% % % MinimumangleEditField = uieditfield(OtherTab, 'numeric'); +% % % MinimumangleEditField.Position = [330 187 100 22]; +% % % MinimumangleEditField.Value = 0; +% % % +% % % +% % % % Create MaximumAngleEditFieldLabel +% % % MaximumAngleEditFieldLabel = uilabel(OtherTab); +% % % MaximumAngleEditFieldLabel.HorizontalAlignment = 'right'; +% % % MaximumAngleEditFieldLabel.FontName = 'Cambria'; +% % % MaximumAngleEditFieldLabel.Position = [227 151 88 22]; +% % % MaximumAngleEditFieldLabel.Text = 'Maximum Angle'; +% % % +% % % % Create MaximumAngleEditField +% % % MaximumAngleEditField = uieditfield(OtherTab, 'numeric'); +% % % MaximumAngleEditField.Position = [330 151 100 22]; +% % % MaximumAngleEditField.Value = 360; + + % Create Switch_9 + Switch_9 = uiswitch(OtherTab, 'slider'); + Switch_9.Items = {'NO', 'YES'}; + Switch_9.FontName = 'Cambria'; + Switch_9.Position = [316 243 45 20]; + Switch_9.Value = 'NO'; + + + % Create FilterbasedonflowdirectionLabel + FilterbasedonflowdirectionLabel = uilabel(OtherTab); + FilterbasedonflowdirectionLabel.Position = [272 270 158 22]; + FilterbasedonflowdirectionLabel.Text = 'Filter based on flow direction'; + + + + % Create SmoothingofcompositearrayofallvelocitiesDropDownLabel + SmoothingofcompositearrayofallvelocitiesDropDownLabel = uilabel(OtherTab); + SmoothingofcompositearrayofallvelocitiesDropDownLabel.HorizontalAlignment = 'right'; + SmoothingofcompositearrayofallvelocitiesDropDownLabel.Position = [103 18 248 22]; + SmoothingofcompositearrayofallvelocitiesDropDownLabel.Text = 'Smoothing of composite array of all velocities'; + + % Create SmoothingofcompositearrayofallvelocitiesDropDown + SmoothingofcompositearrayofallvelocitiesDropDown = uidropdown(OtherTab); + SmoothingofcompositearrayofallvelocitiesDropDown.Items = {'No Smoothing', 'Smoothing in time', 'Smoothing in time and space'}; + SmoothingofcompositearrayofallvelocitiesDropDown.Position = [365 18 192 22]; + SmoothingofcompositearrayofallvelocitiesDropDown.Value = 'Smoothing in time and space'; + + % Create NumberofiterationsformonthlyvelocitiesEditFieldLabel + NumberofiterationsformonthlyvelocitiesEditFieldLabel = uilabel(OtherTab); + NumberofiterationsformonthlyvelocitiesEditFieldLabel.HorizontalAlignment = 'right'; + NumberofiterationsformonthlyvelocitiesEditFieldLabel.Position = [134 59 231 22]; + NumberofiterationsformonthlyvelocitiesEditFieldLabel.Text = 'Number of iterations for monthly velocities'; + + % Create NumberofiterationsformonthlyvelocitiesEditField + NumberofiterationsformonthlyvelocitiesEditField = uieditfield(OtherTab, 'numeric'); + NumberofiterationsformonthlyvelocitiesEditField.Position = [380 59 100 22]; + NumberofiterationsformonthlyvelocitiesEditField.Value = 0; + + % Create Switch_12 + Switch_12 = uiswitch(OtherTab, 'slider'); + Switch_12.Items = {'NO', 'YES'}; + Switch_12.FontName = 'Cambria'; + Switch_12.Position = [321 102 45 20]; + Switch_12.Value = 'NO'; + + % Create NormalizetovelocityofastableregionLabel + NormalizetovelocityofastableregionLabel = uilabel(OtherTab); + NormalizetovelocityofastableregionLabel.Position = [245 130 212 22]; + NormalizetovelocityofastableregionLabel.Text = 'Normalize to velocity of a stable region'; + + + % Create GIVAGLACIERVELOCITYCALCULATIONTOOLBOXBYMAXVANWYKDEVRIESLabel + GIVAGLACIERVELOCITYCALCULATIONTOOLBOXBYMAXVANWYKDEVRIESLabel = uilabel(GUIFigure); + GIVAGLACIERVELOCITYCALCULATIONTOOLBOXBYMAXVANWYKDEVRIESLabel.FontName = 'Cambria'; + GIVAGLACIERVELOCITYCALCULATIONTOOLBOXBYMAXVANWYKDEVRIESLabel.FontAngle = 'italic'; + GIVAGLACIERVELOCITYCALCULATIONTOOLBOXBYMAXVANWYKDEVRIESLabel.Position = [116 26 447 22]; + GIVAGLACIERVELOCITYCALCULATIONTOOLBOXBYMAXVANWYKDEVRIESLabel.Text = 'GIV: A GLACIER VELOCITY CALCULATION TOOLBOX BY MAX VAN WYK DE VRIES ET AL.'; + + % Create WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel + WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel = uilabel(GUIFigure); + WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel.FontName = 'Cambria'; + WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel.FontSize = 10; + WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel.FontAngle = 'italic'; + WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel.Position = [184 6 295 22]; + WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel.Text = 'WWW.GIVGLACIER.COM --- CONTACT ME AT VANWY048@UMN.EDU '; + + % Create CALCULATEVELOCITIESButton + CALCULATEVELOCITIESButton = uibutton(GUIFigure, 'push'); + CALCULATEVELOCITIESButton.BackgroundColor = [0.302 0.7451 0.9333]; + CALCULATEVELOCITIESButton.FontName = 'Cambria'; + CALCULATEVELOCITIESButton.FontSize = 25; + CALCULATEVELOCITIESButton.FontWeight = 'bold'; + CALCULATEVELOCITIESButton.FontAngle = 'italic'; + CALCULATEVELOCITIESButton.FontColor = [0 0.149 1]; + CALCULATEVELOCITIESButton.Position = [186 59 310 71]; + CALCULATEVELOCITIESButton.Text = 'CALCULATE VELOCITIES'; + CALCULATEVELOCITIESButton.ButtonPushedFcn = @(btn,event) plotButtonPushed2 (btn); + + % Create LoadsetupButton + LoadsetupButton = uibutton(GUIFigure, 'push'); + LoadsetupButton.FontName = 'Cambria'; + LoadsetupButton.FontWeight = 'bold'; + LoadsetupButton.Position = [26 77 100 34]; + LoadsetupButton.Text = 'Load setup'; + LoadsetupButton.ButtonPushedFcn = @(btn,event) plotButtonPushed3(btn); + + % Create SavesetupButton + SavesetupButton = uibutton(GUIFigure, 'push'); + SavesetupButton.BackgroundColor = [0.9412 0.9412 0.9412]; + SavesetupButton.FontName = 'Cambria'; + SavesetupButton.FontWeight = 'bold'; + SavesetupButton.Position = [536 77 100 34]; + SavesetupButton.Text = 'Save setup'; + SavesetupButton.ButtonPushedFcn = @(btn,event) plotButtonPushed4 (btn); + + % Create AnalyseImagePairsButton + AnalyseImagePairsButton = uibutton(GUIFigure, 'push'); + AnalyseImagePairsButton.BackgroundColor = [0.302 0.7451 0.9333]; + AnalyseImagePairsButton.FontName = 'Cambria'; + AnalyseImagePairsButton.FontSize = 18; + AnalyseImagePairsButton.FontWeight = 'bold'; + AnalyseImagePairsButton.FontAngle = 'italic'; + AnalyseImagePairsButton.Position = [248 142 185 40]; + AnalyseImagePairsButton.Text = 'Analyse Image Pairs'; + AnalyseImagePairsButton.ButtonPushedFcn = @(btn,event) plotButtonPushed5 (btn); + + + + % Show the figure after all components are created + GUIFigure.Visible = 'on'; + + + %% This portion makes the buttons call the relevant functions. + + %For ease, functions are all wrapped in a single GIV_GUI_main, + %which is called here. + + + % This button press allows you to select the input folder. + function [btn,event,GUIinputs]= plotButtonPushed1(btn,GUIinputs) + a = uigetdir('.'); + PathtoimagesfolderEditField.Value = a; + GUIinputs.folder = a; + figure(GUIFigure) + end + + %This button runs GIV + function [btn,event]= plotButtonPushed2(btn,GUIinputs) + + %Display message to user + logo = imread('GIV_LOGO_SMALL.png'); + msgbox({'RUNNING...YOU MAY CLOSE THE INPUTS BOX. IT MAY TAKE A FEW SECONDS TO CLOSE'},... + 'GIV is running','custom',logo); + + %Combine input into a MATLAB struct array. These are more human + %readable than a simple array, and easier to modify in the + %future. + GUIinputs.folder = PathtoimagesfolderEditField.Value; + GUIinputs.isgeotiff = geotiffinputSwitch.Value; + GUIinputs.minlat = MinimumLatitudeEditField.Value; + GUIinputs.maxlat = MaximumLatitudeEditField.Value; + GUIinputs.minlon = MinimumLongitudeEditField.Value; + GUIinputs.maxlon = MaximumLongitudeEditField.Value; + GUIinputs.temporaloversampling = TimeoversamplingfactorEditField.Value; + GUIinputs.parralelize = ParralelizecodeSwitch.Value; + GUIinputs.name = FilenametosaveasEditField.Value; + + if strcmpi(Switch.Value, 'Multipass') + GUIinputs.numpass = 'Multi'; + else + GUIinputs.numpass = 'Single'; + end + + GUIinputs.snr = SignaltonoiseratioEditField.Value; + GUIinputs.windowoverlap = 0.5; + GUIinputs.idealresolution = IdealresolutionofoutputdataEditField.Value; + GUIinputs.searchwindowsize = 30; + GUIinputs.minsearcharea = 50; + GUIinputs.minyear = MinimumYearEditField.Value; + GUIinputs.maxyear = MaximumYearEditField.Value; + GUIinputs.minmonth = MinimumMonthEditField.Value; + GUIinputs.maxmonth = MaximumMonthEditField.Value; + GUIinputs.minday = MinimumDayEditField.Value; + GUIinputs.maxday = MaximumDayEditField.Value; + GUIinputs.mininterval = MinimumintervalforimagepairsEditField.Value; + GUIinputs.maxinterval = MaximumintervalforimagepairsEditField.Value; + + if strcmpi(Switch_2.Value, 'ON') + GUIinputs.CLAHE = 1; + else + GUIinputs.CLAHE = 0; + end + + if strcmpi(Switch_3.Value, 'ON') + GUIinputs.hipass = 1; + else + GUIinputs.hipass = 0; + end + + if strcmpi(Switch_4.Value, 'ON') + GUIinputs.intenscap = 1; + else + GUIinputs.intenscap = 0; + end + + if strcmpi(Switch_5.Value, 'ON') + GUIinputs.NAOF = 1; + else + GUIinputs.NAOF = 0; + end + + GUIinputs.CLAHEsize = CLAHEsizeEditField.Value; + GUIinputs.hipasssize = HighpasssizeEditField.Value; + + if strcmpi(Switch_10.Value, 'ON') + GUIinputs.sobel = 1; + else + GUIinputs.sobel = 0; + end + + if strcmpi(Switch_11.Value, 'ON') + GUIinputs.laplacian = 1; + else + GUIinputs.laplacian = 0; + end + + if strcmpi(Switch_6.Value, 'ON') + GUIinputs.savearrays = 'Yes'; %'Yes' or 'No' + else + GUIinputs.savearrays = 'No'; + end + + if strcmpi(Switch_7.Value, 'ON') + GUIinputs.savekeyvel = 'Yes'; %'Yes' or 'No' + else + GUIinputs.savekeyvel = 'No'; + end + + if strcmpi(Switch_8.Value, 'ON') + GUIinputs.savegeotiff = 'Yes'; %'Yes' or 'No' + else + GUIinputs.savegeotiff = 'No'; + end + + GUIinputs.imageformat = FormatofimagestosaveEditField.Value; + GUIinputs.maxvel = MaximumVelocityEditField.Value; + GUIinputs.excudedangle1.min = Excludedangle1minimumEditField.Value; + GUIinputs.excudedangle1.max = Excludedangle1maximumEditField.Value; + GUIinputs.excudedangle2.min = Excludedangle2minimumEditField.Value; + GUIinputs.excudedangle2.max = Excludedangle2maximumEditField.Value; + + if strcmpi(Switch_12.Value, 'YES') + GUIinputs.stable = 'Yes'; %'Yes' or 'No' + else + GUIinputs.stable = 'No'; + end + + if strcmpi(Switch_9.Value, 'YES') + GUIinputs.excludeangle = 'Yes'; %'Yes' or 'No' + else + GUIinputs.excludeangle = 'No'; + end + + if strcmpi(SmoothingofcompositearrayofallvelocitiesDropDown.Value, 'Smoothing in time and space') + GUIinputs.finalsmooth = 'Time and Space'; + elseif strcmpi(SmoothingofcompositearrayofallvelocitiesDropDown.Value, 'Smoothing in time') + GUIinputs.finalsmooth = 'Time'; + else + GUIinputs.finalsmooth = 'None'; + end + + GUIinputs.nummonthiter = NumberofiterationsformonthlyvelocitiesEditField.Value; + + %Rename this array + inputs = GUIinputs; + + %Call the main wrapper function + GIV_GUI_main(inputs) + end + + %Load a previously saved inputs file. + function [btn,event]= plotButtonPushed3(btn) + + %Prompt user to select file + load_file = uigetfile('input files', 'Select an input file you previously saved.') + load(strcat(load_file,'/',file_name),'inputs'); + + %Display message + logo = imread('GIV_LOGO_SMALL.png'); + msgbox({'RUNNING...YOU MAY CLOSE THE INPUTS BOX. IT MAY TAKE A FEW SECONDS TO CLOSE'},... + 'GIV is running','custom',logo); + + %Call main wrapper function + GIV_GUI_main(inputs) + end + + %Save an input setup + function [btn,event]= plotButtonPushed4(btn,GUIinputs) + + %Combine input into a MATLAB struct array. These are more human + %readable than a simple array, and easier to modify in the + %future. + GUIinputs.folder = PathtoimagesfolderEditField.Value; + GUIinputs.isgeotiff = geotiffinputSwitch.Value; + GUIinputs.minlat = MinimumLatitudeEditField.Value; + GUIinputs.maxlat = MaximumLatitudeEditField.Value; + GUIinputs.minlon = MinimumLongitudeEditField.Value; + GUIinputs.maxlon = MaximumLongitudeEditField.Value; + GUIinputs.temporaloversampling = TimeoversamplingfactorEditField.Value; + GUIinputs.parralelize = ParralelizecodeSwitch.Value; + GUIinputs.name = FilenametosaveasEditField.Value; + + if strcmpi(Switch.Value, 'Multipass') + GUIinputs.numpass = 'Multi'; + else + GUIinputs.numpass = 'Single'; + end + + GUIinputs.snr = SignaltonoiseratioEditField.Value; + GUIinputs.windowoverlap = 0.5; + GUIinputs.idealresolution = IdealresolutionofoutputdataEditField.Value; + GUIinputs.searchwindowsize = 30; + GUIinputs.minsearcharea = 50; + GUIinputs.minyear = MinimumYearEditField.Value; + GUIinputs.maxyear = MaximumYearEditField.Value; + GUIinputs.minmonth = MinimumMonthEditField.Value; + GUIinputs.maxmonth = MaximumMonthEditField.Value; + GUIinputs.minday = MinimumDayEditField.Value; + GUIinputs.maxday = MaximumDayEditField.Value; + GUIinputs.mininterval = MinimumintervalforimagepairsEditField.Value; + GUIinputs.maxinterval = MaximumintervalforimagepairsEditField.Value; + + if strcmpi(Switch_2.Value, 'ON') + GUIinputs.CLAHE = 1; + else + GUIinputs.CLAHE = 0; + end + + if strcmpi(Switch_3.Value, 'ON') + GUIinputs.hipass = 1; + else + GUIinputs.hipass = 0; + end + + if strcmpi(Switch_4.Value, 'ON') + GUIinputs.intenscap = 1; + else + GUIinputs.intenscap = 0; + end + + if strcmpi(Switch_5.Value, 'ON') + GUIinputs.NAOF = 1; + else + GUIinputs.NAOF = 0; + end + + GUIinputs.CLAHEsize = CLAHEsizeEditField.Value; + GUIinputs.hipasssize = HighpasssizeEditField.Value; + + if strcmpi(Switch_10.Value, 'ON') + GUIinputs.sobel = 1; + else + GUIinputs.sobel = 0; + end + + if strcmpi(Switch_11.Value, 'ON') + GUIinputs.laplacian = 1; + else + GUIinputs.laplacian = 0; + end + + if strcmpi(Switch_6.Value, 'ON') + GUIinputs.savearrays = 'Yes'; %'Yes' or 'No' + else + GUIinputs.savearrays = 'No'; + end + + if strcmpi(Switch_7.Value, 'ON') + GUIinputs.savekeyvel = 'Yes'; %'Yes' or 'No' + else + GUIinputs.savekeyvel = 'No'; + end + + if strcmpi(Switch_8.Value, 'ON') + GUIinputs.savegeotiff = 'Yes'; %'Yes' or 'No' + else + GUIinputs.savegeotiff = 'No'; + end + + GUIinputs.imageformat = FormatofimagestosaveEditField.Value; + GUIinputs.maxvel = MaximumVelocityEditField.Value; + GUIinputs.excudedangle1.min = Excludedangle1minimumEditField.Value; + GUIinputs.excudedangle1.max = Excludedangle1maximumEditField.Value; + GUIinputs.excudedangle2.min = Excludedangle2minimumEditField.Value; + GUIinputs.excudedangle2.max = Excludedangle2maximumEditField.Value; + + if strcmpi(Switch_12.Value, 'YES') + GUIinputs.stable = 'Yes'; %'Yes' or 'No' + else + GUIinputs.stable = 'No'; + end + + if strcmpi(Switch_9.Value, 'YES') + GUIinputs.excludeangle = 'Yes'; %'Yes' or 'No' + else + GUIinputs.excludeangle = 'No'; + end + + if strcmpi(SmoothingofcompositearrayofallvelocitiesDropDown.Value, 'Smoothing in time and space') + GUIinputs.finalsmooth = 'Time and Space'; + elseif strcmpi(SmoothingofcompositearrayofallvelocitiesDropDown.Value, 'Smoothing in time') + GUIinputs.finalsmooth = 'Time'; + else + GUIinputs.finalsmooth = 'None'; + end + + GUIinputs.nummonthiter = NumberofiterationsformonthlyvelocitiesEditField.Value; + + %Rename this array + inputs = GUIinputs; + + %Save the file + filename2 = strcat(inputs{1,2},'/input files'); + if ~exist(filename2) + mkdir(filename2) + end + uisave('inputs',strcat(filename2,'/','savefile')); + + end + + %Calculate number of viable images for a given setup. + function [btn,event]= plotButtonPushed5(btn,GUIinputs) + + %Display message to user + logo = imread('GIV_LOGO_SMALL.png'); + msgbox({'CALCULATING NUMBER OF IMAGE PAIRS...YOU MAY CLOSE THE INPUTS BOX. IT MAY TAKE A FEW SECONDS TO CLOSE'},... + 'GIV is running','custom',logo); + + %Combine input into a MATLAB struct array. These are more human + %readable than a simple array, and easier to modify in the + %future. + GUIinputs.folder = PathtoimagesfolderEditField.Value; + GUIinputs.isgeotiff = geotiffinputSwitch.Value; + GUIinputs.minlat = MinimumLatitudeEditField.Value; + GUIinputs.maxlat = MaximumLatitudeEditField.Value; + GUIinputs.minlon = MinimumLongitudeEditField.Value; + GUIinputs.maxlon = MaximumLongitudeEditField.Value; + GUIinputs.temporaloversampling = TimeoversamplingfactorEditField.Value; + GUIinputs.parralelize = ParralelizecodeSwitch.Value; + GUIinputs.name = FilenametosaveasEditField.Value; + + if strcmpi(Switch.Value, 'Multipass') + GUIinputs.numpass = 'Multi'; + else + GUIinputs.numpass = 'Single'; + end + + GUIinputs.snr = SignaltonoiseratioEditField.Value; + GUIinputs.windowoverlap = 0.5; + GUIinputs.idealresolution = IdealresolutionofoutputdataEditField.Value; + GUIinputs.searchwindowsize = 30; + GUIinputs.minsearcharea = 50; + GUIinputs.minyear = MinimumYearEditField.Value; + GUIinputs.maxyear = MaximumYearEditField.Value; + GUIinputs.minmonth = MinimumMonthEditField.Value; + GUIinputs.maxmonth = MaximumMonthEditField.Value; + GUIinputs.minday = MinimumDayEditField.Value; + GUIinputs.maxday = MaximumDayEditField.Value; + GUIinputs.mininterval = MinimumintervalforimagepairsEditField.Value; + GUIinputs.maxinterval = MaximumintervalforimagepairsEditField.Value; + + if strcmpi(Switch_2.Value, 'ON') + GUIinputs.CLAHE = 1; + else + GUIinputs.CLAHE = 0; + end + + if strcmpi(Switch_3.Value, 'ON') + GUIinputs.hipass = 1; + else + GUIinputs.hipass = 0; + end + + if strcmpi(Switch_4.Value, 'ON') + GUIinputs.intenscap = 1; + else + GUIinputs.intenscap = 0; + end + + if strcmpi(Switch_5.Value, 'ON') + GUIinputs.NAOF = 1; + else + GUIinputs.NAOF = 0; + end + + GUIinputs.CLAHEsize = CLAHEsizeEditField.Value; + GUIinputs.hipasssize = HighpasssizeEditField.Value; + + if strcmpi(Switch_10.Value, 'ON') + GUIinputs.sobel = 1; + else + GUIinputs.sobel = 0; + end + + if strcmpi(Switch_11.Value, 'ON') + GUIinputs.laplacian = 1; + else + GUIinputs.laplacian = 0; + end + + if strcmpi(Switch_6.Value, 'ON') + GUIinputs.savearrays = 'Yes'; %'Yes' or 'No' + else + GUIinputs.savearrays = 'No'; + end + + if strcmpi(Switch_7.Value, 'ON') + GUIinputs.savekeyvel = 'Yes'; %'Yes' or 'No' + else + GUIinputs.savekeyvel = 'No'; + end + + if strcmpi(Switch_8.Value, 'ON') + GUIinputs.savegeotiff = 'Yes'; %'Yes' or 'No' + else + GUIinputs.savegeotiff = 'No'; + end + + GUIinputs.imageformat = FormatofimagestosaveEditField.Value; + GUIinputs.maxvel = MaximumVelocityEditField.Value; + GUIinputs.excudedangle1.min = Excludedangle1minimumEditField.Value; + GUIinputs.excudedangle1.max = Excludedangle1maximumEditField.Value; + GUIinputs.excudedangle2.min = Excludedangle2minimumEditField.Value; + GUIinputs.excudedangle2.max = Excludedangle2maximumEditField.Value; + + if strcmpi(Switch_12.Value, 'YES') + GUIinputs.stable = 'Yes'; %'Yes' or 'No' + else + GUIinputs.stable = 'No'; + end + + if strcmpi(Switch_9.Value, 'YES') + GUIinputs.excludeangle = 'Yes'; %'Yes' or 'No' + else + GUIinputs.excludeangle = 'No'; + end + + if strcmpi(SmoothingofcompositearrayofallvelocitiesDropDown.Value, 'Smoothing in time and space') + GUIinputs.finalsmooth = 'Time and Space'; + elseif strcmpi(SmoothingofcompositearrayofallvelocitiesDropDown.Value, 'Smoothing in time') + GUIinputs.finalsmooth = 'Time'; + else + GUIinputs.finalsmooth = 'None'; + end + + GUIinputs.nummonthiter = NumberofiterationsformonthlyvelocitiesEditField.Value; + + %Rename this array + inputs = GUIinputs; + + %Call the viable image calculation script. + GIVruntime(inputs); + end + + +end + diff --git a/GIV_GUI_timeseries.m b/GIV_GUI_timeseries.m new file mode 100644 index 0000000..063d653 --- /dev/null +++ b/GIV_GUI_timeseries.m @@ -0,0 +1,329 @@ +function GIV_GUI_timeseries() +% This function opens up a user interface that is used to extract time +% series plots from previously calculated velocity maps. It may be run +% independantly at any point after the main function GIV_GUI_initialize has +% been completed. +% +% 1 = array with different lat longs inputted by user +% +% 2 = size of padding of averages 0 = no pad, 1 = 1 cell pad, etc. +% +% 3 = Yes or no for calculate for raw data +% +% 4 = Yes or no for calculate for monthly data +% +% 5 = flow direction and velocity or just velocity + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + +%% Create the timeseries calculation GUI + +% Create TimeseriesGUIFigure and hide until all components are created + TimeseriesGUIFigure = uifigure('Visible', 'off'); + TimeseriesGUIFigure.Position = [100 100 630 561]; + TimeseriesGUIFigure.Name = 'GIV: EXTRACT TIME SERIES'; + +% Create Image + Image = uiimage(TimeseriesGUIFigure); + Image.Position = [130 410 345 152]; + Image.ImageSource = 'logo.png'; + +% Create Latitude1EditFieldLabel + Latitude1EditFieldLabel = uilabel(TimeseriesGUIFigure); + Latitude1EditFieldLabel.HorizontalAlignment = 'right'; + Latitude1EditFieldLabel.FontName = 'Cambria'; + Latitude1EditFieldLabel.Position = [31 294 57 22]; + Latitude1EditFieldLabel.Text = 'Latitude 1'; + +% Create Latitude1EditField + Latitude1EditField = uieditfield(TimeseriesGUIFigure, 'numeric'); + Latitude1EditField.FontName = 'Cambria'; + Latitude1EditField.Position = [103 294 67 22]; + Latitude1EditField.Value = 0; + +% Create Longitude1EditFieldLabel + Longitude1EditFieldLabel = uilabel(TimeseriesGUIFigure); + Longitude1EditFieldLabel.HorizontalAlignment = 'right'; + Longitude1EditFieldLabel.FontName = 'Cambria'; + Longitude1EditFieldLabel.Position = [187 294 67 22]; + Longitude1EditFieldLabel.Text = 'Longitude 1'; + +% Create Longitude1EditField + Longitude1EditField = uieditfield(TimeseriesGUIFigure, 'numeric'); + Longitude1EditField.FontName = 'Cambria'; + Longitude1EditField.Position = [269 294 67 22]; + Longitude1EditField.Value = 0; + +% Create Latitude2EditFieldLabel + Latitude2EditFieldLabel = uilabel(TimeseriesGUIFigure); + Latitude2EditFieldLabel.HorizontalAlignment = 'right'; + Latitude2EditFieldLabel.FontName = 'Cambria'; + Latitude2EditFieldLabel.Position = [31 262 57 22]; + Latitude2EditFieldLabel.Text = 'Latitude 2'; + + +% Create Latitude2EditField + Latitude2EditField = uieditfield(TimeseriesGUIFigure, 'numeric'); + Latitude2EditField.FontName = 'Cambria'; + Latitude2EditField.Position = [103 262 67 22]; + Latitude2EditField.Value = 0; + +% Create Longitude2EditFieldLabel + Longitude2EditFieldLabel = uilabel(TimeseriesGUIFigure); + Longitude2EditFieldLabel.HorizontalAlignment = 'right'; + Longitude2EditFieldLabel.FontName = 'Cambria'; + Longitude2EditFieldLabel.Position = [187 262 67 22]; + Longitude2EditFieldLabel.Text = 'Longitude 2'; + +% Create Longitude2EditField + Longitude2EditField = uieditfield(TimeseriesGUIFigure, 'numeric'); + Longitude2EditField.FontName = 'Cambria'; + Longitude2EditField.Position = [269 262 67 22]; + Longitude2EditField.Value = 0; + +% Create Latitude3EditFieldLabel + Latitude3EditFieldLabel = uilabel(TimeseriesGUIFigure); + Latitude3EditFieldLabel.HorizontalAlignment = 'right'; + Latitude3EditFieldLabel.FontName = 'Cambria'; + Latitude3EditFieldLabel.Position = [31 232 57 22]; + Latitude3EditFieldLabel.Text = 'Latitude 3'; + +% Create Latitude3EditField + Latitude3EditField = uieditfield(TimeseriesGUIFigure, 'numeric'); + Latitude3EditField.FontName = 'Cambria'; + Latitude3EditField.Position = [103 232 67 22]; + Latitude3EditField.Value = 0; + +% Create Longitude3EditFieldLabel + Longitude3EditFieldLabel = uilabel(TimeseriesGUIFigure); + Longitude3EditFieldLabel.HorizontalAlignment = 'right'; + Longitude3EditFieldLabel.FontName = 'Cambria'; + Longitude3EditFieldLabel.Position = [187 232 67 22]; + Longitude3EditFieldLabel.Text = 'Longitude 3'; + +% Create Longitude3EditField + Longitude3EditField = uieditfield(TimeseriesGUIFigure, 'numeric'); + Longitude3EditField.FontName = 'Cambria'; + Longitude3EditField.Position = [269 232 67 22]; + Longitude3EditField.Value = 0; + +% Create Latitude4EditFieldLabel + Latitude4EditFieldLabel = uilabel(TimeseriesGUIFigure); + Latitude4EditFieldLabel.HorizontalAlignment = 'right'; + Latitude4EditFieldLabel.FontName = 'Cambria'; + Latitude4EditFieldLabel.Position = [31 200 57 22]; + Latitude4EditFieldLabel.Text = 'Latitude 4'; + +% Create Latitude4EditField + Latitude4EditField = uieditfield(TimeseriesGUIFigure, 'numeric'); + Latitude4EditField.FontName = 'Cambria'; + Latitude4EditField.Position = [103 200 67 22]; + Latitude4EditField.Value = 0; + +% Create Longitude4EditFieldLabel + Longitude4EditFieldLabel = uilabel(TimeseriesGUIFigure); + Longitude4EditFieldLabel.HorizontalAlignment = 'right'; + Longitude4EditFieldLabel.FontName = 'Cambria'; + Longitude4EditFieldLabel.Position = [187 200 67 22]; + Longitude4EditFieldLabel.Text = 'Longitude 4'; + +% Create Longitude4EditField + Longitude4EditField = uieditfield(TimeseriesGUIFigure, 'numeric'); + Longitude4EditField.FontName = 'Cambria'; + Longitude4EditField.Position = [269 200 67 22]; + Longitude4EditField.Value = 0; + +% Create Latitude5EditFieldLabel + Latitude5EditFieldLabel = uilabel(TimeseriesGUIFigure); + Latitude5EditFieldLabel.HorizontalAlignment = 'right'; + Latitude5EditFieldLabel.FontName = 'Cambria'; + Latitude5EditFieldLabel.Position = [31 170 57 22]; + Latitude5EditFieldLabel.Text = 'Latitude 5'; + +% Create Latitude5EditField + Latitude5EditField = uieditfield(TimeseriesGUIFigure, 'numeric'); + Latitude5EditField.FontName = 'Cambria'; + Latitude5EditField.Position = [103 170 67 22]; + Latitude5EditField.Value = 0; + +% Create Longitude5EditFieldLabel + Longitude5EditFieldLabel = uilabel(TimeseriesGUIFigure); + Longitude5EditFieldLabel.HorizontalAlignment = 'right'; + Longitude5EditFieldLabel.FontName = 'Cambria'; + Longitude5EditFieldLabel.Position = [187 170 67 22]; + Longitude5EditFieldLabel.Text = 'Longitude 5'; + +% Create Longitude5EditField + Longitude5EditField = uieditfield(TimeseriesGUIFigure, 'numeric'); + Longitude5EditField.FontName = 'Cambria'; + Longitude5EditField.Position = [269 170 67 22]; + Longitude5EditField.Value = 0; + +% Create Latitude6EditFieldLabel + Latitude6EditFieldLabel = uilabel(TimeseriesGUIFigure); + Latitude6EditFieldLabel.HorizontalAlignment = 'right'; + Latitude6EditFieldLabel.FontName = 'Cambria'; + Latitude6EditFieldLabel.Position = [31 138 57 22]; + Latitude6EditFieldLabel.Text = 'Latitude 6'; + +% Create Latitude6EditField + Latitude6EditField = uieditfield(TimeseriesGUIFigure, 'numeric'); + Latitude6EditField.FontName = 'Cambria'; + Latitude6EditField.Position = [103 138 67 22]; + Latitude6EditField.Value = 0; + +% Create Longitude6EditFieldLabel + Longitude6EditFieldLabel = uilabel(TimeseriesGUIFigure); + Longitude6EditFieldLabel.HorizontalAlignment = 'right'; + Longitude6EditFieldLabel.FontName = 'Cambria'; + Longitude6EditFieldLabel.Position = [187 138 67 22]; + Longitude6EditFieldLabel.Text = 'Longitude 6'; + +% Create Longitude6EditField + Longitude6EditField = uieditfield(TimeseriesGUIFigure, 'numeric'); + Longitude6EditField.FontName = 'Cambria'; + Longitude6EditField.Position = [269 138 67 22]; + Longitude6EditField.Value = 0; + +% Create GIVAGLACIERVELOCITYCALCULATIONTOOLBOXBYMAXVANWYKDEVRIESLabel + GIVAGLACIERVELOCITYCALCULATIONTOOLBOXBYMAXVANWYKDEVRIESLabel = uilabel(TimeseriesGUIFigure); + GIVAGLACIERVELOCITYCALCULATIONTOOLBOXBYMAXVANWYKDEVRIESLabel.FontName = 'Cambria'; + GIVAGLACIERVELOCITYCALCULATIONTOOLBOXBYMAXVANWYKDEVRIESLabel.FontAngle = 'italic'; + GIVAGLACIERVELOCITYCALCULATIONTOOLBOXBYMAXVANWYKDEVRIESLabel.Position = [119 35 412 22]; + GIVAGLACIERVELOCITYCALCULATIONTOOLBOXBYMAXVANWYKDEVRIESLabel.Text = 'GIV: A GLACIER VELOCITY CALCULATION TOOLBOX BY MAX VAN WYK DE VRIES'; + +% Create WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel + WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel = uilabel(TimeseriesGUIFigure); + WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel.FontName = 'Cambria'; + WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel.FontSize = 10; + WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel.FontAngle = 'italic'; + WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel.Position = [178 9 295 22]; + WWWGIVGLACIERCOMCONTACTMEATVANWY048UMNEDULabel.Text = 'WWW.GIVGLACIER.COM --- CONTACT ME AT VANWY048@UMN.EDU '; + +% Create SizeofadditionalareaaveragedEditFieldLabel + SizeofadditionalareaaveragedEditFieldLabel = uilabel(TimeseriesGUIFigure); + SizeofadditionalareaaveragedEditFieldLabel.HorizontalAlignment = 'right'; + SizeofadditionalareaaveragedEditFieldLabel.FontName = 'Cambria'; + SizeofadditionalareaaveragedEditFieldLabel.Position = [360 338 167 22]; + SizeofadditionalareaaveragedEditFieldLabel.Text = 'Size of additional area averaged'; + +% Create SizeofadditionalareaaveragedEditField + SizeofadditionalareaaveragedEditField = uieditfield(TimeseriesGUIFigure, 'numeric'); + SizeofadditionalareaaveragedEditField.FontName = 'Cambria'; + SizeofadditionalareaaveragedEditField.Position = [542 338 67 22]; + SizeofadditionalareaaveragedEditField.Value = 3; + +% Create TimeseriesofrawdataSwitchLabel + TimeseriesofrawdataSwitchLabel = uilabel(TimeseriesGUIFigure); + TimeseriesofrawdataSwitchLabel.HorizontalAlignment = 'center'; + TimeseriesofrawdataSwitchLabel.FontName = 'Cambria'; + TimeseriesofrawdataSwitchLabel.Position = [411 270 131 22]; + TimeseriesofrawdataSwitchLabel.Text = 'Time-series of raw data?'; + +% Create TimeseriesofrawdataSwitch + TimeseriesofrawdataSwitch = uiswitch(TimeseriesGUIFigure, 'slider'); + TimeseriesofrawdataSwitch.Items = {'No', 'Yes'}; + TimeseriesofrawdataSwitch.FontName = 'Cambria'; + TimeseriesofrawdataSwitch.Position = [454 297 45 20]; + TimeseriesofrawdataSwitch.Value = 'Yes'; + +% Create AlsosaveflowdirectionsSwitchLabel + AlsosaveflowdirectionsSwitchLabel = uilabel(TimeseriesGUIFigure); + AlsosaveflowdirectionsSwitchLabel.HorizontalAlignment = 'center'; + AlsosaveflowdirectionsSwitchLabel.FontName = 'Cambria'; + AlsosaveflowdirectionsSwitchLabel.Position = [408 117 137 22]; + AlsosaveflowdirectionsSwitchLabel.Text = 'Also save flow directions?'; + +% Create AlsosaveflowdirectionsSwitch + AlsosaveflowdirectionsSwitch = uiswitch(TimeseriesGUIFigure, 'slider'); + AlsosaveflowdirectionsSwitch.Items = {'No', 'Yes'}; + AlsosaveflowdirectionsSwitch.FontName = 'Cambria'; + AlsosaveflowdirectionsSwitch.Position = [454 149 45 20]; + AlsosaveflowdirectionsSwitch.Value = 'Yes'; + +% Create TimeseriesofmonthlydataSwitchLabel + TimeseriesofmonthlydataSwitchLabel = uilabel(TimeseriesGUIFigure); + TimeseriesofmonthlydataSwitchLabel.HorizontalAlignment = 'center'; + TimeseriesofmonthlydataSwitchLabel.FontName = 'Cambria'; + TimeseriesofmonthlydataSwitchLabel.Position = [400 191 154 22]; + TimeseriesofmonthlydataSwitchLabel.Text = 'Time-series of monthly data?'; + +% Create TimeseriesofmonthlydataSwitch + TimeseriesofmonthlydataSwitch = uiswitch(TimeseriesGUIFigure, 'slider'); + TimeseriesofmonthlydataSwitch.Items = {'No', 'Yes'}; + TimeseriesofmonthlydataSwitch.FontName = 'Cambria'; + TimeseriesofmonthlydataSwitch.Position = [454 219 45 20]; + TimeseriesofmonthlydataSwitch.Value = 'Yes'; + +% Create CalculateDataTimeseriesLabel + CalculateDataTimeseriesLabel = uilabel(TimeseriesGUIFigure); + CalculateDataTimeseriesLabel.FontName = 'Cambria'; + CalculateDataTimeseriesLabel.FontSize = 15; + CalculateDataTimeseriesLabel.FontWeight = 'bold'; + CalculateDataTimeseriesLabel.Position = [233 389 184 22]; + CalculateDataTimeseriesLabel.Text = 'Calculate Data Timeseries'; + +% Create LatitudeLongitudeinputLabel + LatitudeLongitudeinputLabel = uilabel(TimeseriesGUIFigure); + LatitudeLongitudeinputLabel.FontName = 'Cambria'; + LatitudeLongitudeinputLabel.FontWeight = 'bold'; + LatitudeLongitudeinputLabel.Position = [144 341 144 22]; + LatitudeLongitudeinputLabel.Text = 'Latitude-Longitude input'; + + +% Create ExtractTimeSeriesButton + ExtractTimeSeriesButton = uibutton(TimeseriesGUIFigure, 'push'); + ExtractTimeSeriesButton.BackgroundColor = [0.302 0.7451 0.9333]; + ExtractTimeSeriesButton.FontName = 'Cambria'; + ExtractTimeSeriesButton.FontSize = 15; + ExtractTimeSeriesButton.FontWeight = 'bold'; + ExtractTimeSeriesButton.Position = [215 68 221 27]; + ExtractTimeSeriesButton.Text = 'Extract Time Series'; + ExtractTimeSeriesButton.ButtonPushedFcn = @(btn,event) plotButtonPushed (btn); + + +% Show the figure after all components are created + TimeseriesGUIFigure.Visible = 'on'; + + + %% This section sets the inputs and calls the timeseries extraction algorithm. + function [btn,event]= plotButtonPushed(btn) + + vtplotinputs= {}; + vtplotinputs{1,1} = 'array with different lat longs inputted by user'; + vtplotinputs{1,2} = [Latitude1EditField.Value,Longitude1EditField.Value;Latitude2EditField.Value,Longitude2EditField.Value;... + Latitude3EditField.Value,Longitude3EditField.Value;Latitude4EditField.Value,Longitude4EditField.Value;... + Latitude5EditField.Value,Longitude5EditField.Value;Latitude6EditField.Value,Longitude6EditField.Value]; + vtplotinputs{2,1} = 'size of padding'; + vtplotinputs{2,2} = SizeofadditionalareaaveragedEditField.Value; + vtplotinputs{3,1} = 'Yes or no for calculate for raw data'; + vtplotinputs{3,2} = TimeseriesofrawdataSwitch.Value; + vtplotinputs{4,1} = 'Yes or no for calculate for monthly data'; + vtplotinputs{4,2} = TimeseriesofmonthlydataSwitch.Value; + vtplotinputs{5,1} = 'flow direction as well as velocity?'; + vtplotinputs{5,2} = AlsosaveflowdirectionsSwitch.Value; + velocitytimeplot(vtplotinputs); + + end + +end diff --git a/GIV_LOGO_SMALL.png b/GIV_LOGO_SMALL.png new file mode 100644 index 0000000..2a0412b Binary files /dev/null and b/GIV_LOGO_SMALL.png differ diff --git a/GIV_V0.7_matlab.zip b/GIV_V0.7_matlab.zip deleted file mode 100644 index 40aaf1d..0000000 Binary files a/GIV_V0.7_matlab.zip and /dev/null differ diff --git a/functions/GIV_GUI_main.m b/functions/GIV_GUI_main.m new file mode 100644 index 0000000..f7766fd --- /dev/null +++ b/functions/GIV_GUI_main.m @@ -0,0 +1,117 @@ +function GIV_GUI_main(inputs) +% +%This is the main wrapper script for GIV. It simply calls the following +%functions to calculate glacier velocities. Functions called are: +% +% loadtseries.m : load the images +% +% cropmask.m : crop the images to a mask and pre-process them +% +% GIVcore.m : perform the feature tracking +% +% filtall.m : filter the velocity maps and exlude outliers +% +% im2month.m : create monthly velocity maps +% +% save_images.m : create plots and save results +% +% An additional function, save_raw_array.m saves the results prior to +% filtering, such that they may be post-processed using different settings +% or recovered if the run crashes or is interrupted. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +%% Load image series +% Loads all of the images from a folder. + +[images,inputs]=loadtseries(inputs); + + +%% Crop to mask +% Crops and pre-processes the images + +[images,inputs]=cropmask(images,inputs); +save_raw_array(images,inputs); + +%Display message to let the user know that the pre-processing is completed. +logo = imread('GIV_LOGO_SMALL.png'); +message_1 = msgbox({'Images loaded and cropped to mask.';'Calculating glacier velocities via feature tracking of image pairs. Please be patient, this step may take a while.'},... + 'GIV is running','custom',logo); + + +%% Calculate velocity from image pairs +%Perform the feature tracking. GIV will most likely spend ~90% of its +%runtime on this step. + +[images,inputs]=GIVcore(images,inputs); + +%Delete previous message box if has not been closed. +if exist('message_1', 'var') + delete(message_1); + clear('message_1'); +end + +%Save raw feature tracking results so that they can be recovered if +%necessary. Note that file sizes can be several GB for large datasets and +%you may wish to delete this file. +save_raw_array(images,inputs); + +%Let the user know that feature tracking is completed. +message_2 = msgbox('Velocity pairs calculated. Filtering and saving entire dataset.',... + 'GIV is running','custom',logo); + + +%% Filter based on entire dataset +%Perform post-processing + +[images,images_stack]=filtall(images,inputs); + + +%% Create monthly average velocities +%Resample to monthly maps + +[monthly_averages]=im2month(images,inputs,images_stack); + + +%% Save the data +%Plot and save the data. + +[images] = save_images (images, inputs, images_stack, monthly_averages); + +%Delete previous message box if has not been closed. +if exist('message_2', 'var') + delete(message_2); + clear('message_2'); +end + +%Let the user know that GIV is finished. +message_3 = msgbox({'COMPLETE.'; 'ALL IMAGES AMD FILES HAVE BEEN FILTERED AND SAVED TO THE RESULTS FOLDER. SEE USER MANUAL FOR MORE DETAILS.'},... + 'GIV is running','custom',logo); + + +%% Open up the timeseries selection dialogue (you can come back to this later). +%Open timeseries ui for convenience. App users will have to open the +%interface this way, it can also be called from the following matlab +%function at any later point: + +GIV_GUI_timeseries; \ No newline at end of file diff --git a/functions/image cross correlation/GIVcore.m b/functions/image cross correlation/GIVcore.m new file mode 100644 index 0000000..b675d19 --- /dev/null +++ b/functions/image cross correlation/GIVcore.m @@ -0,0 +1,696 @@ +function [images,inputs]=GIVcore(images,inputs) +% +%This functions calculates the image pairs and sends them off to be +%calculated. If the code is running in parralel mode then it will slice the +%pairs into portions the size of the number of cores on your computer to +%improve the efficiency of the calculations. +% +%If you are running in single pass mode, pairs are feature tracked with +%GIVtrack.m +% +%If you are running in multi pass mode, pairs are feature tracked with +%GIVtrackmulti.m + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +%% Perform some initial tasks + +%Initialize the timer. This will tell the user how long is remaining until +%the run is complete. +time_all_iterations = tic; + +%Logo for msg boxes +logo = imread('GIV_LOGO_SMALL.png'); + +%IF images are being compared to a portion of stable ground, the stable +%mask is loaded and processed here. +if strcmpi(inputs.stable, 'Yes') + + if exist(fullfile(inputs.folder,'stable.png')) > 0 + cdata = imread(fullfile(inputs.folder,'stable.png')); + elseif exist(fullfile(inputs.folder,'stable.jpg')) >0 + cdata = imread(fullfile(inputs.folder,'stable.jpg')); + end + + % Create binary mask with pure white pixels + cdata = double(cdata); + cdata = cdata(:,:,1)+cdata(:,:,2)+cdata(:,:,3); + cdata(cdata==765) = NaN; + cdata(cdata>0)= 0; + cdata(isnan(cdata))= 1; + stable = cdata; + stable = flipud(stable); + +else + + %Create dummy stable mask if not needed + stable = zeros(size(images{2,3})); + +end + +scale_length = size(images{2,3}); + +%Calculate resolution of image + if strcmpi(inputs.isgeotiff,'No') + NS1 = [inputs.minlat,inputs.minlon]; + NS2 = [inputs.maxlat,inputs.minlon]; + EW1 = [inputs.minlat,inputs.minlon]; + EW2 = [inputs.minlat,inputs.maxlon]; + else + NS1 = [inputs.geotifflocationdata.CornerCoords.Lat(1,4),inputs.geotifflocationdata.CornerCoords.Lon(1,4)]; + NS2 = [inputs.geotifflocationdata.CornerCoords.Lat(1,1),inputs.geotifflocationdata.CornerCoords.Lon(1,1)]; + EW1 = [inputs.geotifflocationdata.CornerCoords.Lat(1,4),inputs.geotifflocationdata.CornerCoords.Lon(1,4)]; + EW2 = [inputs.geotifflocationdata.CornerCoords.Lat(1,3),inputs.geotifflocationdata.CornerCoords.Lon(1,3)]; + end + + %Convert lat long to distances + dy=coordtom(EW1,EW2); + dx=coordtom(NS1,NS2); + + stepx=dx/scale_length(1); %m/pixel + stepy=dy/scale_length(2); %m/pixel + mean_resolution = 0.5*(stepx+stepy); + + %Write the resolution to the inputs array for future use + inputs.realresolution = ceil(inputs.idealresolution/mean_resolution)*8; +% + +%Initialize some parameters +newcol1 = {}; %import to external (new) array in order to be parralelized +newcol2 = {}; +number_in_range = 0; +meta_dum = 0; +emptycount_inner = 0; +emptycount_outer = 0; + +%% CREATE IMAGE PAIRS ARRAY + +for time_loop = 1:inputs.temporaloversampling %for multisampling in time + for inner_loop = 2:inputs.numimages-time_loop %main loop + loop2 = inner_loop+time_loop; %for multisampling in time, will skip one for higher time_bracket + + %Work out time between two images, if too long then do not run + %templatematch. + + A1_t= (images{inner_loop,5}); + B1_t= (images{loop2,5}); + + timestep = (B1_t-A1_t)/365; + + if timestep <= inputs.maxinterval && timestep >= inputs.mininterval + + number_in_range = number_in_range + 1; + + end + emptycount_outer = emptycount_outer + emptycount_inner; + emptycount_inner = 0; + meta_dum = meta_dum + inputs.numimages-time_loop-1; + + + end +end + +emptycount_inner = 0; + +column_save_variable = 1; + +parralel_timestep = 1; + +core_info = evalc('feature(''numcores'')'); +Num_cores = ans; +clear ans +clear core_info + +%% Main feature tracking +% This can (and should!) be parralelized. But it can also be run in series + +if strcmpi(inputs.parralelize, 'No') + +for time_loop = 1:inputs.temporaloversampling %for multisampling in time + + for inner_loop = 2:inputs.numimages-time_loop %main loop + loop2 = inner_loop+time_loop; %for multisampling in time, will skip one for higher time_bracket + + %Work out time between two images, if too long then do not run + %feature track. + A1_t= (images{inner_loop,5}); + B1_t= (images{loop2,5}); + timestep = (B1_t-A1_t)/365; + dt = 0; + + %this loop accounts for several dt steps where dum > 1 + %(non-consecutive images being considered). + for iit = inner_loop+1:loop2 + dt = dt + images{iit,6}; + end + + %Include only images within the bounds + if timestep <= inputs.maxinterval && timestep >= inputs.mininterval + + %Load the two images + A1= (images{inner_loop,3}); + B1= (images{loop2,3}); + + %Write them to a parralel chip array. This chip is then sent to the + %processors instead of the entire array, reducing overhead and + %runtime. + parralel_chip{parralel_timestep,1} = A1; + parralel_chip{parralel_timestep,2} = B1; + parralel_chip{parralel_timestep,3} = dt; + parralel_timestep = parralel_timestep+1; + else + emptycount_inner = emptycount_inner + 1; + end + + %Check that a parralel chip has been created (not at end of run) and + %that some conditions are met. + + if exist('parralel_chip') == 1 && ... + size(parralel_chip,1) == Num_cores | (time_loop == inputs.temporaloversampling && inner_loop == inputs.numimages-time_loop) + + for inner_loop_parralel = 1:size(parralel_chip,1) + A1= parralel_chip{inner_loop_parralel,1}; + B1= parralel_chip{inner_loop_parralel,2}; + dt = parralel_chip{inner_loop_parralel,3}; + + %This function will perform the feature tracking. The multipass method is generally better. + + if strcmpi(inputs.numpass, 'Multi') + [~,~,u,v,snr]=GIVtrackmulti(A1,B1,inputs.realresolution,inputs.windowoverlap); + elseif strcmpi(inputs.numpass, 'Single') + + %set maximum expected velocity + max_expected = round(dt * inputs.maxvel/mean_resolution); % Rounding is necessary + + % make minimum limit, else can become too small if close images. + if max_expected < inputs.minsearcharea + max_d = inputs.minsearcharea; + else + max_d = max_expected; + end + + [u, v, C, Cnoise]=GIVtrack(A1,B1,inputs,max_d,inputs.idealresolution); + else + disp('Check bottom of inputs file for single or multipass entry') + end + + %% Convert to velocity and perform filtering + + % filter out portions with signal to noise lower than a given value + % implement value + if strcmpi(inputs.numpass, 'Single') + snr = C./Cnoise; + end + + %Smooth signal to noise map and add it on, meaning that values + %close to 'good' pixels are kept, and groups of 'bad' pixels + %are excluded. Minimises loss of information. + snrsm = nanfillsm(snr,inputs,2,2); + snrextra = snrsm; + snrextra(snrsm<=(inputs.snr+0.5))=0; + snrextra(snrextra>0)=1; + snrextra = smooth_snr(snrextra, inputs); + snrfn = snrextra.*snrsm; + snrfn(snrfn<=0.1) = 0; + snrfn(snrfn>0) = 1; + u = u.*snrfn; + u(u==0) = NaN; + v = v.*snrfn; + v(v==0) = NaN; + u(snr inputs.maxvel) = -1; + V(V == -1) = NaN; + + %Finally apply a selective interpolation and smoothing algorithm to + %infill the gaps created and prior non-tracked values without creating + %spurious peaks/troughs. If not sufficient data is present in the area + %to make an interpolation, it will not be done. + + % First pass with a small window size and higher tolerance to fill + % small gaps: + u = nanfillsm(u,inputs,2,2); + v = nanfillsm(v,inputs,2,2); + + if strcmpi(inputs.stable, 'Yes') + stable_used = (interp2(stable, linspace(1,size(images{2,3},2),size(u,2)).', linspace(1,size(images{2,3},1),size(u,1)))); + dudiff = nanmean(u(stable_used == 1)); + dvdiff = nanmean(v(stable_used == 1)); + u = u - dudiff; + v = v - dvdiff; + end + + [V,fd] = xytoV(u, v, mean_resolution, dt); + V(V > inputs.maxvel) = -1; + V(V == -1) = NaN; + + %Exclude displacements in wrong direction. + if strcmpi(inputs.excludeangle, 'Yes') + + %Remove areas flowing in wrong direction (change direction for specific + %glaciers or remove, on Amalia it is all flowing W) + tempwrongfd1 = double(fd>inputs.excudedangle1.min) + double(fdinputs.excudedangle2.min) + double(fd 100 + percent_completed = 100; + disp('At last!'); + end + + %Calculate approximate time remaining; + elapsed_time = toc(time_all_iterations); + total_time = (elapsed_time * number_in_range) / column_save_variable2; + remaining_time = total_time * (1-column_save_variable2/number_in_range); + + if percent_completed > 100 + remaining_time = 0; + end + + %Display time remaining in a reasonable unit. + if remaining_time < 60 %seconds remaining + text_percent = ['Approximatively' ' ' num2str(percent_completed) '%' ' ' 'of image pairs calculated and' ' ' num2str(remaining_time) ' ' 'seconds remaining.']; + elseif remaining_time > 60 && remaining_time < 3600 + remaining_time = remaining_time/60; + text_percent = ['Approximatively' ' ' num2str(percent_completed) '%' ' ' 'of image pairs calculated and' ' ' num2str(remaining_time) ' ' 'minutes remaining.']; + elseif remaining_time > 3600 + remaining_time = remaining_time/3600; + text_percent = ['Approximatively' ' ' num2str(percent_completed) '%' ' ' 'of image pairs calculated and' ' ' num2str(remaining_time) ' ' 'hours remaining.']; + end + + if exist('message_1', 'var') + delete(message_1); + clear('message_1'); + end + + message_1 = msgbox(text_percent,... + 'GIV is running','custom',logo); + + %Display time remaining + disp(text_percent); + parralel_chip = {}; + parralel_timestep = 1; + + %This section in case one worker in the parralel pool 'dies' during + % a long calculation. Should reboot the full parralel pool to ensure + % maximum speed. + core_info = gcp('nocreate'); + try + current_cores = core_info.NumWorkers; + catch + current_cores = 0; + end + clear core_info + + if current_cores < Num_cores + delete(gcp('nocreate')) + parpool(Num_cores) + end + + end + + end %size parralel if end + + emptycount_inner = 0; + +end + + +%Or run it in parralel +elseif strcmpi(inputs.parralelize, 'Yes') + +for time_loop = 1:inputs.temporaloversampling %for multisampling in time + + for inner_loop = 2:inputs.numimages-time_loop %main loop + loop2 = inner_loop+time_loop; %for multisampling in time, will skip one for higher time_bracket + + %Work out time between two images, if too long then do not run + %feature track. + A1_t= (images{inner_loop,5}); + B1_t= (images{loop2,5}); + timestep = (B1_t-A1_t)/365; + dt = 0; + + %this loop accounts for several dt steps where dum > 1 + %(non-consecutive images being considered). + for iit = inner_loop+1:loop2 + dt = dt + images{iit,6}; + end + + %Include only images within the bounds + if timestep <= inputs.maxinterval && timestep >= inputs.mininterval + + %Load the two images + A1= (images{inner_loop,3}); + B1= (images{loop2,3}); + + %Write them to a parralel chip array. This chip is then sent to the + %processors instead of the entire array, reducing overhead and + %runtime. + parralel_chip{parralel_timestep,1} = A1; + parralel_chip{parralel_timestep,2} = B1; + parralel_chip{parralel_timestep,3} = dt; + parralel_timestep = parralel_timestep+1; + else + emptycount_inner = emptycount_inner + 1; + end + + %Check that a parralel chip has been created (not at end of run) and + %that some conditions are met. + + if exist('parralel_chip') == 1 && ... + size(parralel_chip,1) == Num_cores | (time_loop == inputs.temporaloversampling && inner_loop == inputs.numimages-time_loop) + + %parralelized loop. Requires a slightly different code structure. + parfor inner_loop_parralel = 1:size(parralel_chip,1) + A1= parralel_chip{inner_loop_parralel,1}; + B1= parralel_chip{inner_loop_parralel,2}; + dt = parralel_chip{inner_loop_parralel,3}; + + %This function will perform the feature tracking. The multipass method is generally better. + + if strcmpi(inputs.numpass, 'Multi') + [~,~,u,v,snr]=GIVtrackmulti(A1,B1,inputs.realresolution,inputs.windowoverlap); + elseif strcmpi(inputs.numpass, 'Single') + + %set maximum expected velocity + max_expected = round(dt * inputs.maxvel/mean_resolution); % Rounding is necessary + + % make minimum limit, else can become too small if close images. + if max_expected < inputs.minsearcharea + max_d = inputs.minsearcharea; + else + max_d = max_expected; + end + + [u, v, C, Cnoise]=GIVtrack(A1,B1,inputs,max_d,inputs.idealresolution); + else + disp('Check bottom of inputs file for single or multipass entry') + end + + %% Convert to velocity and perform filtering + + % filter out portions with signal to noise lower than a given value + % implement value + if strcmpi(inputs.numpass, 'Single') + snr = C./Cnoise; + end + + %Smooth signal to noise map and add it on, meaning that values + %close to 'good' pixels are kept, and groups of 'bad' pixels + %are excluded. Minimises loss of information. + snrsm = nanfillsm(snr,inputs,2,2); + snrextra = snrsm; + snrextra(snrsm<=(inputs.snr+0.5))=0; + snrextra(snrextra>0)=1; + snrextra = smooth_snr(snrextra, inputs); + snrfn = snrextra.*snrsm; + snrfn(snrfn<=0.1) = 0; + snrfn(snrfn>0) = 1; + u = u.*snrfn; + u(u==0) = NaN; + v = v.*snrfn; + v(v==0) = NaN; + u(snr inputs.maxvel) = -1; + V(V == -1) = NaN; + + %Finally apply a selective interpolation and smoothing algorithm to + %infill the gaps created and prior non-tracked values without creating + %spurious peaks/troughs. If not sufficient data is present in the area + %to make an interpolation, it will not be done. + + % First pass with a small window size and higher tolerance to fill + % small gaps: + u = nanfillsm(u,inputs,2,2); + v = nanfillsm(v,inputs,2,2); + + if strcmpi(inputs.stable, 'Yes') + stable_used = (interp2(stable, linspace(1,size(images{2,3},2),size(u,2)).', linspace(1,size(images{2,3},1),size(u,1)))); + dudiff = nanmean(u(stable_used == 1)); + dvdiff = nanmean(v(stable_used == 1)); + u = u - dudiff; + v = v - dvdiff; + end + + [V,fd] = xytoV(u, v, mean_resolution, dt); + V(V > inputs.maxvel) = -1; + V(V == -1) = NaN; + + %Exclude displacements in wrong direction. + if strcmpi(inputs.excludeangle, 'Yes') + + %Remove areas flowing in wrong direction (change direction for specific + %glaciers or remove, on Amalia it is all flowing W) + tempwrongfd1 = double(fd>inputs.excudedangle1.min) + double(fdinputs.excudedangle2.min) + double(fd 100 + percent_completed = 100; + disp('At last!'); + end + + %Calculate approximate time remaining; + elapsed_time = toc(time_all_iterations); + total_time = (elapsed_time * number_in_range) / column_save_variable2; + remaining_time = total_time * (1-column_save_variable2/number_in_range); + + if percent_completed > 100 + remaining_time = 0; + end + + %Display time remaining in a reasonable unit. + if remaining_time < 60 %seconds remaining + text_percent = ['Approximatively' ' ' num2str(percent_completed) '%' ' ' 'of image pairs calculated and' ' ' num2str(remaining_time) ' ' 'seconds remaining.']; + elseif remaining_time > 60 && remaining_time < 3600 + remaining_time = remaining_time/60; + text_percent = ['Approximatively' ' ' num2str(percent_completed) '%' ' ' 'of image pairs calculated and' ' ' num2str(remaining_time) ' ' 'minutes remaining.']; + elseif remaining_time > 3600 + remaining_time = remaining_time/3600; + text_percent = ['Approximatively' ' ' num2str(percent_completed) '%' ' ' 'of image pairs calculated and' ' ' num2str(remaining_time) ' ' 'hours remaining.']; + end + + %Remove previous message if it exists + if exist('message_1', 'var') + delete(message_1); + clear('message_1'); + end + + %Create pop up message box with duration remaining. + message_1 = msgbox(text_percent,... + 'GIV is running','custom',logo); + parralel_chip = {}; + + parralel_timestep = 1; + + %This section in case one worked in the parralel pool 'dies' during + % a long calculation. Should reboot the full parralel pool. + core_info = gcp('nocreate'); + try + current_cores = core_info.NumWorkers; + catch + current_cores = 0; + end + clear core_info + + if current_cores < Num_cores + delete(gcp('nocreate')) + parpool(Num_cores) + end + + + end + + end %size parralel if end + + emptycount_inner = 0; + +end + +end + + + +%% REINSERT MATRICES INTO IMAGES ARRAY +% May be more efficient in future to remove this step? + +%Reinitialize loop parameters +meta_dum = 0; +array_pos = 0; +emptycount_inner = 0; +emptycount_outer = 0; + +%Run loop +for time_loop = 1:inputs.temporaloversampling + position1 = time_loop + 6 + array_pos; + position2 = time_loop + 7 + array_pos; + for inner_loop = 2:inputs.numimages-time_loop + loop2 = inner_loop+time_loop; %for multisampling in time, will skip one for higher time_bracket + + %Work out time between two images. + A1_t= (images{inner_loop,5}); + B1_t= (images{loop2,5}); + timestep = (B1_t-A1_t)/365; + dt = 0; + + %this loop accounts for several dt steps where dum > 1 + %(non-consecutive images being considered). + for iit = inner_loop+1:loop2 + dt = dt + images{iit,6}; + end + + if timestep <= inputs.maxinterval && timestep >= inputs.mininterval + %Replace velocity in array + images{inner_loop,position1} = column_v{inner_loop+meta_dum-1-emptycount_inner-emptycount_outer,1}; + + %Replace flow direction in array + images{inner_loop,position2} = column_fd{inner_loop+meta_dum-1-emptycount_inner-emptycount_outer,1}; + else + emptycount_inner = emptycount_inner + 1; + end + + end + + + emptycount_outer = emptycount_outer + emptycount_inner; + emptycount_inner = 0; + meta_dum = meta_dum + inputs.numimages-time_loop-1; + array_pos = array_pos + 1; +end + +%Calculate the size of raw images and write to inputs array for future +%reference +for i = 2:size(images,1) + if ~isempty(images{i,3}) + inputs.sizeraw = size(images{i,3}); + end +end + +%Calculate the size of processed images and write to inputs array for future +%reference +number_with_values = (size(images,2)-6)/2; +for ii = 7:(6+number_with_values*2) +for i = 2:size(images,1) + if ~isempty(images{i,ii}) + inputs.sizevel = size(images{i,ii}); + end +end +end \ No newline at end of file diff --git a/functions/image cross correlation/GIVtrack.m b/functions/image cross correlation/GIVtrack.m new file mode 100644 index 0000000..7c7fedd --- /dev/null +++ b/functions/image cross correlation/GIVtrack.m @@ -0,0 +1,198 @@ +function [du, dv, peakCorr, meanAbsCorr,pu,pv]=GIVtrack(A,B,inputs,max_d) +%% Feature tracking by template matching +% +%Takes an image pair and uses standard image velocimetry techniques in +%order to derive a velocity map. See user manual for details of this +%process. The fast fourrier transforms of this function are the most +%computationally demanding portion of this toolbox. +% +% OUTPUTS: +% du,dv: displacement of each point in pu,pv. [A(pu,pv) has moved to B(pu+du,pv+dv)] +% peakCorr: correlation coefficient of the matched template. +% meanAbsCorr: The mean absolute correlation coefficitent over the search +% region is an estimate of the noise level. +% pu,pv: actual pixel centers of templates in A may differ from inputs because of rounding. +% +% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +%Largely based on function 'templatematch' by Alsak Grinstead, part of +%the ImGRAFT toolbox. See his website below for details. + +% ImGRAFT - An image georectification and feature tracking toolbox for MATLAB +% Copvright (C) 2014 Aslak Grinsted (www.glaciology.net) + +% Permission is hereby granted, free of charge, to any person obtaining a copv +% of this software and associated documentation files (the "Software"), to deal +% in the Software without restriction, including without limitation the rights +% to use, copv, 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 copvright 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. + + +scale_length = size(A); + +%Calculate resolution of image +if strcmpi(inputs.isgeotiff,'No') + NS1 = [inputs.minlat,inputs.minlon]; + NS2 = [inputs.maxlat,inputs.minlon]; + EW1 = [inputs.minlat,inputs.minlon]; + EW2 = [inputs.minlat,inputs.maxlon]; +else + NS1 = [inputs.geotifflocationdata.CornerCoords.Lat(1,4),inputs.geotifflocationdata.CornerCoords.Lon(1,4)]; + NS2 = [inputs.geotifflocationdata.CornerCoords.Lat(1,1),inputs.geotifflocationdata.CornerCoords.Lon(1,1)]; + EW1 = [inputs.geotifflocationdata.CornerCoords.Lat(1,4),inputs.geotifflocationdata.CornerCoords.Lon(1,4)]; + EW2 = [inputs.geotifflocationdata.CornerCoords.Lat(1,3),inputs.geotifflocationdata.CornerCoords.Lon(1,3)]; +end + +dy=coordtom(EW1,EW2); +dx=coordtom(NS1,NS2); +stepx=dx/scale_length(1); %m/pixel +stepy=dy/scale_length(2); %m/pixel +resolution = 0.5*(stepx+stepy); +dpu = inputs.idealresolution / resolution; +dpv = inputs.idealresolution / resolution; +pu=inputs.searchwindowsize(1)/2 : dpu : size(A,2)-inputs.searchwindowsize(1)/2; +pv=inputs.searchwindowsize(1)/2: dpv : size(A,1)-inputs.searchwindowsize(1)/2; +[pu,pv]=meshgrid(pu,pv); + +initialdu = 0; +initialdv = 0; + +if any(inputs.searchwindowsize(:)>=max_d(:))||any(inputs.searchwindowsize(:)>=max_d(:)) + error('imgraft:inputerror','Search window size must be greater than template size.') +end + +Np=numel(pu); +du=nan(size(pu)); +dv=nan(size(pu)); +peakCorr=nan(size(pu)); +meanAbsCorr=nan(size(pu)); + +if all(isnan(pu+pv)) + error('imgraft:inputerror','No points to track (pu/pv is all nans)') +end + + if ~isfloat(A),A=im2float(A); end + if ~isfloat(B),B=im2float(B); end + gf=[1 0 -1]; %gf=[1 0;0 -1]; gf=[1 -1]; + ofilter=@(A)exp(1i*atan2(imfilter(A,gf,'replicate'),imfilter(A,rot90(gf),'replicate'))); + A=ofilter(A);B=ofilter(B); + +if ~isreal(B) + B=conj(B); %TODO: if you pass it orientation angles. +end + + +for ii=1:Np + initialdupart=0; + initialdvpart=0; + p=[pu(ii) pv(ii)]; + SearchWidth=max_d(min(numel(max_d),ii))-1; + SearchHeight=max_d(min(numel(max_d),ii))-1; + TemplateWidth=inputs.searchwindowsize(min(numel(inputs.searchwindowsize),ii))-1; + TemplateHeight=inputs.searchwindowsize(min(numel(inputs.searchwindowsize),ii))-1; + Acenter=round(p) - mod([TemplateWidth TemplateHeight]/2,1); % centre coordinate of template + Bcenter=round(p+[initialdupart initialdvpart]) - mod([SearchWidth SearchHeight]/2,1); % centre coordinate of search region + + %what was actually used: + pu(ii)=Acenter(1); + pv(ii)=Acenter(2); + initialdupart=Bcenter(1)-Acenter(1); + initialdvpart=Bcenter(2)-Acenter(2); + + try + BB=B( Bcenter(2)+(-SearchHeight/2:SearchHeight/2) ,Bcenter(1)+(-SearchWidth/2:SearchWidth/2),:); + if any(any(isnan(BB([1 end],[1 end])))) + continue + end + AA=A( Acenter(2)+(-TemplateHeight/2:TemplateHeight/2),Acenter(1)+(-TemplateWidth/2:TemplateWidth/2),:); + if any(any(isnan(AA([1 end],[1 end])))) + continue + end + catch + %out of bounds... continue (and thus return a nan for that point) + continue + end + + sT=size(AA); sB=size(BB); + sz=sB+sT-1; + fT=fft2(rot90(AA,2),sz(1),sz(2)); + fB=fft2(BB,sz(1),sz(2)); + C=real(ifft2(fB.*fT)); + %crop to central part not affected by edges. + wkeep=(sB-sT)/2; + c=(sz+1)/2; + C=C(c(1)+(-wkeep(1):wkeep(1)),c(2)+(-wkeep(2):wkeep(2))); + uu=-wkeep(2):wkeep(2); + vv=-wkeep(1):wkeep(1); + %TODO: allow for using max(C.*prior(uu,vv)) + [Cmax,mix]=max(C(:)); + [mix(1),mix(2)]=ind2sub(size(C),mix); + + meanAbsCorr(ii)=mean(abs(C(:))); %"noise" correlation level (we can accept that estimate even if we cannot find a good peak.) + + edgedist=min(abs([1-mix mix-size(C)])); + + %Slightly crude sub-pixel estimator + switch edgedist %SUBPIXEL METHOD:... + case 0, %do-nothing.... + mix=[];% do not accept peaks on edge + case 1, %3x3 + c=C(mix(1)+(-1:1),mix(2)+(-1:1)); + [uu,vv]=meshgrid(uu(mix(2)+(-1:1)),vv(mix(1)+(-1:1))); + c=(c-mean(c([1:4 6:9])));c(c<0)=0; %simple and excellent performance for landsat test images... + c=c./sum(c(:)); + mix(2)=sum(uu(:).*c(:)); + mix(1)=sum(vv(:).*c(:)); + + otherwise %5x5.... + c=C(mix(1)+(-2:2),mix(2)+(-2:2)); + [uu,vv]=meshgrid(uu(mix(2)+(-2:2)),vv(mix(1)+(-2:2))); + c=(c-mean(c([1:12 14:end])));c(c<0)=0;%simple and excellent performance for landsat test images... + c=c./sum(c(:)); + mix(2)=sum(uu(:).*c(:)); + mix(1)=sum(vv(:).*c(:)); + + end + if ~isempty(mix) + mix=mix([2 1]); + du(ii)=mix(1)+initialdupart; + dv(ii)=mix(2)+initialdvpart; + peakCorr(ii)=Cmax; + end + +end + diff --git a/functions/image cross correlation/GIVtrackmulti.m b/functions/image cross correlation/GIVtrackmulti.m new file mode 100644 index 0000000..8a898c5 --- /dev/null +++ b/functions/image cross correlation/GIVtrackmulti.m @@ -0,0 +1,100 @@ +function [x,y,u,v,snr,Pkh]=GIVtrackmulti(AA,BB,winsize,overlap) +% +% +% PIV in multiple passes to eliminate the displacement bias. +% Utilizes the increase in S/N by halving the size of the +% interrogation windows after the first pass. +% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +%This function is based upon a multipass solver written by Kristian Sveen +%as part of the matPIV toolbox. It has been adapted for use as part of GIV. +%It is distributed under the terms of the Gnu General Public License +%manager. + +%%%%%%%%% First pass to estimate displacement in integer values: +[x,y,datax,datay]=GIVtrackmultifirst(AA,BB,winsize,overlap); +datax1 = datax; +datay1 = datay; +[datax1,datay1]=neighbourfilter(x,y,datax1,datay1,'median',3,3); +[datax1,datay1]=fillnan(datax1,datay1,'linear',x,y); +% datax1 = nanfillsm(datax1,inputs,4,3); +% datay1 = nanfillsm(datay1,inputs,4,3); + +clear datax datay x y +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% expand the velocity data to twice the original size +% This is because we want to use half the interrogation +% window size from now on. +winsize=winsize/2; +[sy,sx]=size(AA); +X=(1:((1-overlap)*2*winsize):sx-2*winsize+1)+(2*winsize)/2; +Y=(1:((1-overlap)*2*winsize):sy-2*winsize+1)+(2*winsize)/2; +XI=(1:((1-overlap)*winsize):sx-winsize+1)+(winsize)/2; +YI=(1:((1-overlap)*winsize):sy-winsize+1)+(winsize)/2; +datax1(:,size(X,2)+1:end)=[]; +datax1(size(Y,2)+1:end,:)=[]; +datay1(:,size(X,2)+1:end)=[]; +datay1(size(Y,2)+1:end,:)=[]; +datax=interp2(X,Y',datax1,XI,YI'); +datay=interp2(X,Y',datay1,XI,YI'); +[datax,datay]=fillnan(datax,datay,'linear',... + repmat(XI,size(datax,1),1),repmat(YI',1,size(datax,2))); +datax=floor(datax); datay=floor(datay); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Second pass to estimate displacement in integer values: +% now using smaller interrogation windows +% to utilize the smaller S/N introduced with window offset. +[x,y,datax2,datay2]=GIVtrackmultifirst(AA,BB,winsize,overlap,datax,datay); +[datax2,datay2]=neighbourfilter(x,y,datax2,datay2,'median',3,3); +[datax2,datay2]=fillnan(datax2,datay2,'linear',x,y); +% datax2 = nanfillsm(datax2,inputs,4,3); +% datay2 = nanfillsm(datay2,inputs,4,3); +clear x y + +% expand the velocity data to twice the original size +% This is because we want to use half the interrogation +% window size from now on. +winsize=winsize/2; +[sy,sx]=size(AA); +X=(1:((1-overlap)*2*winsize):sx-4*winsize+1)+(4*winsize)/2; +Y=(1:((1-overlap)*2*winsize):sy-4*winsize+1)+(4*winsize)/2; +XI=(1:((1-overlap)*winsize):sx-winsize+1)+(winsize)/2; +YI=(1:((1-overlap)*winsize):sy-winsize+1)+(winsize)/2; +datax2(:,size(X,2)+1:end)=[]; +datax2(size(Y,2)+1:end,:)=[]; +datay2(:,size(X,2)+1:end)=[]; +datay2(size(Y,2)+1:end,:)=[]; +datax1=interp2(X,Y',datax2,XI,YI'); +datay1=interp2(X,Y',datay2,XI,YI'); +[datax1,datay1]=fillnan(datax1,datay1,'linear',... + repmat(XI,size(datax1,1),1),repmat(YI',1,size(datax1,2))); +datax1=floor(datax1); datay1=floor(datay1); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Final pass. Gives displacement to subpixel accuracy. + [x,y,u,v,snr,Pkh]=GIVtrackmultifinal(AA,BB,winsize,overlap,round(datax1),... + round(datay1)); +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/functions/image cross correlation/GIVtrackmultifinal.m b/functions/image cross correlation/GIVtrackmultifinal.m new file mode 100644 index 0000000..c7ee99d --- /dev/null +++ b/functions/image cross correlation/GIVtrackmultifinal.m @@ -0,0 +1,218 @@ +function [xp,yp,up,vp,SnR,Pkh]=GIVtrackmultifinal(A,B,winsize,overlap,initialdx,initialdy) +% function [x,y,u,v,SnR,PeakHeight]=finalpass(A,B,winsize,overlap,initialdx,initialdy) +% +% Provides the final pass to get the displacements with +% subpixel resolution. +% +% + + +%This function is based upon a multipass solver written by Kristian Sveen +%as part of the matPIV toolbox. It has been adapted for use as part of GIV. +%It is distributed under the terms of the Gnu General Public License +%manager. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + +if length(winsize)==1 + M=winsize; +else + M=winsize(1); winsize=winsize(2); +end +cj=1; +[sy,sx]=size(A); + +% Allocate space for matrixes +xp=zeros(ceil((size(A,1)-winsize)/((1-overlap)*winsize))+1, ... + ceil((size(A,2)-M)/((1-overlap)*M))+1); +yp=xp; up=xp; vp=xp; SnR=xp; Pkh=xp; + +IN=zeros(size(A)); + +%%%%%%%%%%%%%%% MAIN LOOP %%%%%%%%%%%%%%%%%%%%%%%%% +tic +for jj=1:((1-overlap)*winsize):sy-winsize+1 + ci=1; + for ii=1:((1-overlap)*M):sx-M+1 + if IN(jj+winsize/2,ii+M/2)~=1 + if isnan(initialdx(cj,ci)) + initialdx(cj,ci)=0; + end + if isnan(initialdy(cj,ci)) + initialdy(cj,ci)=0; + end + if jj+initialdy(cj,ci)<1 + initialdy(cj,ci)=1-jj; + elseif jj+initialdy(cj,ci)>sy-winsize+1 + initialdy(cj,ci)=sy-winsize+1-jj; + end + if ii+initialdx(cj,ci)<1 + initialdx(cj,ci)=1-ii; + elseif ii+initialdx(cj,ci)>sx-M+1 + initialdx(cj,ci)=sx-M+1-ii; + end + D2=B(jj+initialdy(cj,ci):jj+winsize-1+initialdy(cj,ci),ii+initialdx(cj,ci):ii+M-1+initialdx(cj,ci)); + E=A(jj:jj+winsize-1,ii:ii+M-1); + stad1=std(E(:)); + stad2=std(D2(:)); + if stad1==0, stad1=1; end + if stad2==0, stad2=1; end + E=E-mean(E(:)); + F=D2-mean(D2(:)); + %E(E<0)=0; F(F<0)=0; + + %%%%%%%%%%%%%%%%%%%%%% Calculate the normalized correlation: + R=xcorrelate(E,F)./(winsize*M*stad1*stad2); + %%%%%%%%%%%%%%%%%%%%%% Find the position of the maximal value of R + %%%%%%%%%%%%%%%%%%%%%% _IF_ the standard deviation is NOT NaN. + if all(~isnan(R(:))) && ~all(R(:)==0) %~isnan(stad1) & ~isnan(stad2) + if size(R,1)==(winsize-1) + [max_y1,max_x1]=find(R==max(R(:))); + + else + [max_y1,max_x1]=find(R==max(max(R(0.5*winsize+2:1.5*winsize-3,... + 0.5*M+2:1.5*M-3)))); + end + if length(max_x1)>1 + max_x1=round(sum(max_x1.^2)./sum(max_x1)); + max_y1=round(sum(max_y1.^2)./sum(max_y1)); + end + if max_x1==1, max_x1=2; end + if max_y1==1, max_y1=2; end + + + %Sub-pixel estimator: + % 3-point peak fit using centroid, gaussian (default) + % or parabolic fit + [x0, y0]=GIVtrackmultipeak(max_x1,max_y1,R(max_y1,max_x1),... + R(max_y1,max_x1-1),R(max_y1,max_x1+1),... + R(max_y1-1,max_x1),R(max_y1+1,max_x1),2,[M,winsize]); + + % Find the signal to Noise ratio + R2=R; + try + %consider changing this from try-catch to a simpler + %distance check. The key here is the distance tot he + %image edge. When peak is close to edge, this NaN + %allocation may fail. + R2(max_y1-3:max_y1+3,max_x1-3:max_x1+3)=NaN; + catch + R2(max_y1-1:max_y1+1,max_x1-1:max_x1+1)=NaN; + end + if size(R,1)==(winsize-1) + [p2_y2,p2_x2]=find(R2==max(R2(:))); + else + [p2_y2,p2_x2]=find(R2==max(max(R2(0.5*winsize:1.5*winsize-1,0.5*M:1.5*M-1)))); + end + if length(p2_x2)>1 + p2_x2=p2_x2(round(length(p2_x2)/2)); + p2_y2=p2_y2(round(length(p2_y2)/2)); + elseif isempty(p2_x2) + + end + % signal to noise: + snr=R(max_y1,max_x1)/R2(p2_y2,p2_x2); + + + %%%%%%%%%%%%%%%%%%%%%% Store the displacements, SnR and Peak Height. + up(cj,ci)=(-x0+initialdx(cj,ci)); + vp(cj,ci)=(-y0+initialdy(cj,ci)); + xp(cj,ci)=(ii+(M/2)-1); + yp(cj,ci)=(jj+(winsize/2)-1); + SnR(cj,ci)=snr; + Pkh(cj,ci)=R(max_y1,max_x1); + else + up(cj,ci)=NaN; vp(cj,ci)=NaN; SnR(cj,ci)=NaN; Pkh(cj,ci)=0; + xp(cj,ci)=(ii+(M/2)-1); + yp(cj,ci)=(jj+(winsize/2)-1); + end + ci=ci+1; + else + xp(cj,ci)=(M/2)+ii-1; + yp(cj,ci)=(winsize/2)+jj-1; + up(cj,ci)=NaN; vp(cj,ci)=NaN; + SnR(cj,ci)=NaN; Pkh(cj,ci)=NaN;ci=ci+1; + end + end + cj=cj+1; +end + + +% now we inline the function xcorrelate to shave off some time. +function c = xcorrelate(a,b) +% c = xcorrelate(a,b) +% +% +% Two-dimensional cross-correlation using Fourier transforms. + +%This function is based upon an adaptation of the xcorrf tool written by +%R. Johnson. It has been adapted for use as part of GIV. + + + if nargin<3 + pad='yes'; + end + + + [ma,na] = size(a); + if nargin == 1 + b = a; + end + [mb,nb] = size(b); + % make reverse conjugate of one array + b = conj(b(mb:-1:1,nb:-1:1)); + + if strcmp(pad,'yes'); + % use power of 2 transform lengths + mf = 2^nextpow2(ma+mb); + nf = 2^nextpow2(na+nb); + at = fft2(b,mf,nf); + bt = fft2(a,mf,nf); + elseif strcmp(pad,'no'); + at = fft2(b); + bt = fft2(a); + else + disp('Wrong input to xcorrelate'); return + end + + % multiply transforms then inverse transform + c = ifft2(at.*bt); + % make real output for real input + if ~any(any(imag(a))) & ~any(any(imag(b))) + c = real(c); + end + % trim to standard size + + if strcmp(pad,'yes'); + c(ma+mb:mf,:) = []; + c(:,na+nb:nf) = []; + elseif strcmp(pad,'no'); + c=fftshift(c(1:end-1,1:end-1)); + + c(ma+mb:mf,:) = []; + c(:,na+nb:nf) = []; + end + + +end +end \ No newline at end of file diff --git a/functions/image cross correlation/GIVtrackmultifirst.m b/functions/image cross correlation/GIVtrackmultifirst.m new file mode 100644 index 0000000..defa7f5 --- /dev/null +++ b/functions/image cross correlation/GIVtrackmultifirst.m @@ -0,0 +1,166 @@ +function [xx,yy,datax,datay]=GIVtrackmultifirst(A,B,winsize,overlap,initialdx,initialdy) + +% function [x,y,datax,datay]=firstpass(A,B,M,ol,idx,idy) +% + +%This function is based upon a multipass solver written by Kristian Sveen +%as part of the matPIV toolbox. It has been adapted for use as part of GIV. +%It is distributed under the terms of the Gnu General Public License +%manager. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + +if length(winsize)==1 + M=winsize; +elseif length(winsize)==2 + M=winsize(1); winsize=winsize(2); +end +overlap=overlap; [sy,sx]=size(A); +if nargin < 6 || isempty(initialdx) || isempty(initialdy) + initialdx=zeros(floor(sy/(winsize*(1-overlap))),floor(sx/(M*(1-overlap)))); + initialdy=zeros(floor(sy/(winsize*(1-overlap))),floor(sx/(M*(1-overlap)))); +end +xx=zeros(ceil((size(A,1)-winsize)/((1-overlap)*winsize))+1, ... + ceil((size(A,2)-M)/((1-overlap)*M)) +1); +yy=xx; datax=xx; datay=xx; + +IN=zeros(size(A)); +cj=1; +for jj=1:((1-overlap)*winsize):sy-winsize+1 + ci=1; + for ii=1:((1-overlap)*M):sx-M+1 + + if IN(jj+winsize/2,ii+M/2)~=1 + + if isnan(initialdx(cj,ci)) + initialdx(cj,ci)=0; + end + if isnan(initialdy(cj,ci)) + initialdy(cj,ci)=0; + end + if jj+initialdy(cj,ci)<1 + initialdy(cj,ci)=1-jj; + elseif jj+initialdy(cj,ci)>sy-winsize+1 + initialdy(cj,ci)=sy-winsize+1-jj; + end + if ii+initialdx(cj,ci)<1 + initialdx(cj,ci)=1-ii; + elseif ii+initialdx(cj,ci)>sx-M+1 + initialdx(cj,ci)=sx-M+1-ii; + end + + C=A(jj:jj+winsize-1,ii:ii+M-1); + D=B(jj+initialdy(cj,ci):jj+winsize-1+initialdy(cj,ci),ii+initialdx(cj,ci):ii+M-1+initialdx(cj,ci)); + + C=C-mean(C(:)); D=D-mean(D(:)); %C(C<0)=0; D(D<0)=0; + stad1=std(C(:)); stad2=std(D(:)); + + if stad1==0, stad1=nan;end + if stad2==0, stad2=nan; end + + %%%%%%%%%%%%%%%%%%%%%%%Calculate the normalized correlation: + R=xcorrelate(C,D)/(winsize*M*stad1*stad2); + + %%%%%%%%%%%%%%%%%%%%%% Find the position of the maximal value of R + if size(R,1)==(winsize-1) + [max_y1,max_x1]=find(R==max(R(:))); + else + [max_y1,max_x1]=find(R==max(max(R(0.5*winsize+2:1.5*winsize-3,0.5*M+2:1.5*M-3)))); + end + + if length(max_x1)>1 + max_x1=round(sum(max_x1.*(1:length(max_x1))')./sum(max_x1)); + max_y1=round(sum(max_y1.*(1:length(max_y1))')./sum(max_y1)); + elseif isempty(max_x1) + initialdx(cj,ci)=nan; initialdy(cj,ci)=nan; max_x1=nan; max_y1=nan; + end + %%%%%%%%%%%%%%%%%%%%%% Store the displacements in variable datax/datay + datax(cj,ci)=-(max_x1-(M))+initialdx(cj,ci); + datay(cj,ci)=-(max_y1-(winsize))+initialdy(cj,ci); + xx(cj,ci)=ii+M/2; yy(cj,ci)=jj+winsize/2; + ci=ci+1; + else + xx(cj,ci)=ii+M/2; yy(cj,ci)=jj+winsize/2; + datax(cj,ci)=NaN; datay(cj,ci)=NaN; ci=ci+1; + end + end + cj=cj+1; +end + + + +% now we inline the function xcorrelate to shave off some time. + +function c = xcorrelate(a,b) +% c = xcorrf2(a,b) +% +% +% Two-dimensional cross-correlation using Fourier transforms. + +%This function is based upon an adaptation of the xcorrf tool written by +%R. Johnson. It has been adapted for use as part of GIV. + + + if nargin<3 + pad='yes'; + end + + + [ma,na] = size(a); + if nargin == 1 + % for autocorrelation + b = a; + end + [mb,nb] = size(b); + % make reverse conjugate of one array + b = conj(b(mb:-1:1,nb:-1:1)); + + if strcmp(pad,'yes'); + % use power of 2 transform lengths + mf = 2^nextpow2(ma+mb); + nf = 2^nextpow2(na+nb); + at = fft2(b,mf,nf); + bt = fft2(a,mf,nf); + elseif strcmp(pad,'no'); + at = fft2(b); + bt = fft2(a); + else + disp('Wrong input to xcorrelate'); return + end + + % multiply transforms then inverse transform + c = ifft2(at.*bt); + % make real output for real input + if ~any(any(imag(a))) & ~any(any(imag(b))) + c = real(c); + end + % trim to standard size + if strcmp(pad,'yes'); + c(ma+mb:mf,:) = []; + c(:,na+nb:nf) = []; + elseif strcmp(pad,'no'); + c=fftshift(c(1:end-1,1:end-1)); + + end +end +end \ No newline at end of file diff --git a/functions/image cross correlation/GIVtrackmultipeak.m b/functions/image cross correlation/GIVtrackmultipeak.m new file mode 100644 index 0000000..2029c98 --- /dev/null +++ b/functions/image cross correlation/GIVtrackmultipeak.m @@ -0,0 +1,76 @@ +function [x0,y0]=GIVtrackmultipeak(x1,y1,R,Rxm1,Rxp1,Rym1,Ryp1,method,N) +% +% INTPEAK - sub-pixel peak finder +% +% function [x0,y0]=intpeak(x1,x2,x3,y1,y2,y3,method,N) +% METHOD = +% 1 for centroid fit, +% 2 for gaussian fit, +% 3 for parabolic fit +% x1 and y1 are maximal values in respective directions. +% N is interrogation window size. N is either 1x1 or 1x2 +% + +%This function is based upon a multipass solver written by Kristian Sveen +%as part of the matPIV toolbox. It has been adapted for use as part of GIV. +%It is distributed under the terms of the Gnu General Public License +%manager. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + +if length(N)==2 + M=N(1); N=N(2); +else + M=N; +end + +if any(find(([R Rxm1 Rxp1 Rym1 Ryp1])==0)) + % to avoid Log of Zero warnings + method=1; +end + +if method==1 + x01=(((x1-1)*Rxm1)+(x1*R)+((x1+1)*Rxp1)) / (Rxm1+ R+Rxp1); + y01=(((y1-1)*Rym1)+(y1*R)+((y1+1)*Ryp1)) / (Rym1+ R+Ryp1); + x0=x01-(M); + y0=y01-(N); +elseif method==2 + x01=x1 + ( (log(Rxm1)-log(Rxp1))/( (2*log(Rxm1))-(4*log(R))+(2*log(Rxp1))) ); + y01=y1 + ( (log(Rym1)-log(Ryp1))/( (2*log(Rym1))-(4*log(R))+(2*log(Ryp1))) ); + x0=x01-(M); + y0=y01-(N); +elseif method==3 + x01=x1 + ( (Rxm1-Rxp1)/( (2*Rxm1)-(4*R)+(2*Rxp1)) ); + y01=y1 + ( (Rym1-Ryp1)/( (2*Rym1)-(4*R)+(2*Ryp1)) ); + x0=x01-(M); + y0=y01-(N); + + +else + + disp(['Please include your desired peakfitting function; 1 for',... + ' 3-point fit, 2 for gaussian fit, 3 for parabolic fit']) + +end + +x0=real(x0); +y0=real(y0); diff --git a/functions/image cross correlation/fillnan.m b/functions/image cross correlation/fillnan.m new file mode 100644 index 0000000..9652495 --- /dev/null +++ b/functions/image cross correlation/fillnan.m @@ -0,0 +1,105 @@ +function [u,v]=fillnan(u,v,varargin) +% function [u,v]=naninterp(u,v,method,mask,x,y) +% +% Interpolates NaN's in a vectorfield. Used by GLOBFILT, MEDIANFILT and +% VALIDATE. Sorts all spurious vectors based on the number of spurous +% neighbors to a point. Uses FILLMISS.M to replace NaN's +% [u,v]=NANINTERP(u,v) Will replace all NaN's in u and v +% [u,v]=NANINTERP(u,v,[idxw idyw],x,y) Will replace NaN's but leave out +% areas that have been masked out (using MASK.M) Using the MASK option +% requires the x and y matrices input along with the u and v. METHOD +% should be 'linear' or 'weighted' and defaults to 'linear'. + +%This function is based upon a multipass solver written by Kristian Sveen +%as part of the matPIV toolbox. It has been adapted for use as part of GIV. +%It is distributed under the terms of the Gnu General Public License +%manager. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + +usr=1; +if ~any(strcmp(varargin,'linear')) & ~any(strcmp(varargin,'weighted')) + met='linear'; +else + tm=cellfun('isclass',varargin,'char'); + if sum(tm)==3 + disp('Wrong input to naninterp!'); return + end + met=varargin(tm(1)); +end + +%%%%%%%%%%%%%%%%%%%%% +if strcmp(met,'weighted')==1 & ~strcmp(met,'linear')==1 + + if length(varargin)==4 + maske=varargin{2}; if ischar(maske) & ~isempty(maske), maske=load(maske); maske=maske.maske; end + if isempty(maske) + [u,v]=fillnan2(u,v); usr=any(isnan(u(:))); + else + xx=varargin{3}; yy=varargin{4}; + while usr~=0 + in2=zeros(size(xx)); + for i=1:length(maske) + in=inpolygon(xx,yy,maske(i).idxw,maske(i).idyw); + in2=in2+double(in); + end + in2=logical(in2); + % interpolate NaN's using FILLMISS.M + u(in2)=0; v(in2)=0; + u=fillmiss(u); v=fillmiss(v); + usr=any(isnan(u(:))); + u(in2)=nan; v(in2)=nan; + end + u(in2)=NaN; v(in2)=NaN; + numm=size(in2,1)*size(in2,2); + end + else + while usr~=0 + numm=sum(isnan(u(:))); + % interpolate NaN's using FILLMISS.M + u=fillmiss(u); v=fillmiss(v); + usr=any(isnan(u(:))); + end + end + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +elseif strcmp(met,'linear')==1 & ~strcmp(met,'weighted')==1 + + if length(varargin)==4 + maske=varargin{2}; if ischar(maske) & ~isempty(maske),maske=load(maske);maske=maske.maske; end + if isempty(maske) + [u,v]=fillnan2(u,v); usr=any(isnan(u(:))); + else + xx=varargin{3}; yy=varargin{4}; + maske=rmfield(maske,'msk'); % this is done to avoid the large matrix + %being copied into the next function. + [u,v]=fillnan2(u,v,maske,xx,yy); + end + else + while usr~=0 + % interpolate NaN's using fillnan2.M + [u,v]=fillnan2(u,v); usr=any(isnan(u(:))); + end + end +else + disp('Something is EXTREMELY wrong with your input'); return +end + diff --git a/functions/image cross correlation/fillnan2.m b/functions/image cross correlation/fillnan2.m new file mode 100644 index 0000000..9c1f711 --- /dev/null +++ b/functions/image cross correlation/fillnan2.m @@ -0,0 +1,138 @@ +function [u,v]=fillnan2(u,v,mask,xx,yy) +% function [u,v]=fillnan2(u,v,mask,x,y) +% +% Interpolates NaN's in a vectorfield. Used by GLOBFILT, +% MEDIANFILT and VALIDATE. Sorts all spurious vectors based on the +% number of spurous neighbors to a point. Interpolation starts with +% the ones that have the least number of outliers in their +% neighborhood and loops until no NaN's are present in the field. +% + + +%This function is based upon a multipass solver written by Kristian Sveen +%as part of the matPIV toolbox. It has been adapted for use as part of GIV. +%It is distributed under the terms of the Gnu General Public License +%manager. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + +% determine Calling m-file: +[stru,II]=dbstack; +if length(stru)>2 + test=stru(3).name; + I2=findstr(test,'multipass'); + if isempty(I2), I2=0; end +else + I2=0; +end +if nargin==2 + [py,px]=find(isnan(u)==1); +else + py2=[];px2=[]; ipol2=zeros(size(xx)); + for i=1:size(mask,2) + if I2~=0 + ipol1=inpolygon(xx,yy,mask(i).idx,mask(i).idy); + ipol2=ipol2+ipol1; + else + ipol1=inpolygon(xx,yy,mask(i).idxw,mask(i).idyw); + ipol2=ipol2+ipol1; + end + end + [py,px]=find(isnan(u)==1 & ~ipol2 ); +end + +numm=size(py); +[dy,dx]=size(u); +teller=1; +lp=1; +tel=1; +% Now sort the NaN's after how many neighbors they have that are +% physical values. Then we first interpolate those that have 8 +% neighbors, followed by 7, 6, 5, 4, 3, 2 and 1 +% use SORTROWS to sort the numbers +%pcolor(u), hold on +while ~isempty(py) + % check number of neighbors + for i=1:length(py) + %correction if vector is on edge of matrix + corx1=0; corx2=0; cory1=0; cory2=0; + if py(i)==1, cory1=1; cory2=0; + elseif py(i)==dy, cory1=0; cory2=-1; end + if px(i)==1, corx1=1; corx2=0; + elseif px(i)==dx, corx1=0; corx2=-1; end + ma = u( py(i)-1+cory1:py(i)+1+cory2, px(i)-1+corx1:px(i)+1+corx2 ); + nei(i,1)=sum(~isnan(ma(:))); + nei(i,2)=px(i); + nei(i,3)=py(i); + end + % now sort the rows of NEI to interpolate the vectors with the + % fewest spurious neighbors. + nei=flipud(sortrows(nei,1)); + % reconstruct the sorted outlier-vectors. + % and only interpolate the first 50% of vectors + ind=find(nei(:,1)>=8); + while isempty(ind) + ind=find(nei(:,1)>=8-tel); + tel=tel+1; + end + tel=1; + py=nei(ind,3); + px=nei(ind,2); + for j=1:size(py,1) + corx1=0; corx2=0; cory1=0; cory2=0; + if py(j)==1 + cory1=1; cory2=0; + elseif py(j)==dy + cory1=0; cory2=-1; + end + if px(j)==1 + corx1=1; corx2=0; + elseif px(j)==dx + corx1=0; corx2=-1; + end + tmpu=u(py(j)-1+cory1:py(j)+1+cory2, px(j)-1+corx1:px(j)+1+corx2); + tmpv=v(py(j)-1+cory1:py(j)+1+cory2, px(j)-1+corx1:px(j)+1+corx2); + u(py(j),px(j))=nanmean(tmpu(:)); + v(py(j),px(j))=nanmean(tmpv(:)); + if lp>numm(1), u(py(j),px(j))=0;v(py(j),px(j))=0;end + teller=teller+1; + end + tt=length(py); + + if nargin==2 + [py,px]=find(isnan(u)==1); + else + %in2=zeros(size(xx)); + %for i=1:length(mask) + % in=inpolygon(xx,yy,mask(i).idxw,mask(i).idyw); + % in2=in2+double(in); + %end + [py,px]=find(isnan(u)==1 & ~ipol2 ); + end + + lp=lp+1; +end +if numm(1)~=0 + +else + fprintf('Nothing to interpolate \n') +end \ No newline at end of file diff --git a/functions/image cross correlation/make_mask.m b/functions/image cross correlation/make_mask.m new file mode 100644 index 0000000..675bc1f --- /dev/null +++ b/functions/image cross correlation/make_mask.m @@ -0,0 +1,18 @@ +function [mask] = make_mask(smoothsize) +% generates a neighborhood kernel in the form of a diamond, +% though excludes the central pixel +% input: +% smoothsize - integer value +% output: +% mask - logical array +% +%Note: this function was contributed by Anonymous Reviewer 2 of The +%Cryosphere manuscript. We thank them for a very thoughtful and +%constructive review. + +if nargin<1, smoothsize = 3; end +mask_radius = floor(smoothsize/2); +mask = strel('diamond', mask_radius); % make a diamond shape +mask = double(mask.Neighborhood); %added a 'double' +mask(mask_radius+1, mask_radius+1) = 0; % exclude the central element +end \ No newline at end of file diff --git a/functions/image cross correlation/neighbourfilter.m b/functions/image cross correlation/neighbourfilter.m new file mode 100644 index 0000000..22224cf --- /dev/null +++ b/functions/image cross correlation/neighbourfilter.m @@ -0,0 +1,140 @@ +function [hu,hv]=neighbourfilter(x,y,u,v,method,kernelsize,threshold) +% +% +% This function is a filter that will remove vectors that deviate from +% the median or the mean of their surrounding neighbors by the factor +% THRESHOLD times the standard deviation of the neighbors. +% +% METHOD (optional) should be either 'median' or 'mean'. Default is +% 'median'. +% +% KERNELSIZE is optional and is specified as number, typically 3 or 5 +% which defines the number of vectors contributing to the median or mean +% value of each vector. +% +% MASK can be applied to save calculation time. LOCALFILT is relatively +% slow on large matrices and exlcuding "non-interesting" regions with MASK +% can increase speed in some cases. +% + + + +%This function is based upon a multipass solver written by Kristian Sveen +%as part of the matPIV toolbox. It has been adapted for use as part of GIV. +%It is distributed under the terms of the Gnu General Public License +%manager. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +IN=zeros(size(u)); + + + if any(strcmp(method,'median')) + method='mnanmedian'; stat='median'; ff=1; + elseif any(strcmp(method,'mean')) + method='mnanmean'; stat='mean'; ff=2; + end + if ~any(strcmp(method,'mean')) & ~any(strcmp(method,'median')) + method='mnanmedian'; stat='median'; + end + + + + +nu=zeros(size(u)+2*floor(kernelsize/2))*nan; +nv=zeros(size(u)+2*floor(kernelsize/2))*nan; +nu(floor(kernelsize/2)+1:end-floor(kernelsize/2),floor(kernelsize/2)+1:end-floor(kernelsize/2))=u; +nv(floor(kernelsize/2)+1:end-floor(kernelsize/2),floor(kernelsize/2)+1:end-floor(kernelsize/2))=v; + +INx=zeros(size(nu)); +INx(floor(kernelsize/2)+1:end-floor(kernelsize/2),floor(kernelsize/2)+1:end-floor(kernelsize/2))=IN; + +prev=isnan(nu); previndx=find(prev==1); +U2=nu+i*nv; teller=1; [ma,na]=size(U2); histo=zeros(size(nu)); +histostd=zeros(size(nu));hista=zeros(size(nu));histastd=zeros(size(nu)); + +for ii=kernelsize-1:1:na-kernelsize+2 + for jj=kernelsize-1:1:ma-kernelsize+2 + if INx(jj,ii)~=1 + + tmp=U2(jj-floor(kernelsize/2):jj+floor(kernelsize/2),ii-floor(kernelsize/2):ii+floor(kernelsize/2)); + tmp(ceil(kernelsize/2),ceil(kernelsize/2))=NaN; + if ff==1 + usum=nanmedian(tmp(:)); + elseif ff==2 + usum=nanmean(tmp(:)); + end + histostd(jj,ii)=nanstd(tmp(:)); + else + usum=nan; tmp=NaN; histostd(jj,ii)=nan; + end + + histo(jj,ii)=usum; + end + +end + +%%%%ALTERNATIVE METHOD: NLFILTER +% % %Suppress pop-up +% % function wb = waitbar(varargin) +% % if nargout > 0 +% % wb = matlab.graphics.GraphicsPlaceholder; +% % end +% % end +% % +% % if ff==1 +% % fun_med = @(x) median(x(:)); +% % else +% % fun_med = @(x) mean(x(:)); +% % end +% % +% % fun_std = @(x) median(x(:)); +% % +% % histo = nlfilter(U2,[kernelsize kernelsize],fun_med); +% % +% % histostd = nlfilter(U2,[kernelsize kernelsize],fun_std); + +%%%%%%%% Locate gridpoints with a higher value than the threshold + +[cy,cx]=find( ( real(U2)>real(histo)+threshold*real(histostd) |... + imag(U2)>imag(histo)+threshold*imag(histostd) |... + real(U2)=0)&&(k<=n) + P=factorial(n)/(factorial(n-k)*factorial(k)); + else + P=0; + end \ No newline at end of file diff --git a/functions/image processing and filters/cropmask.m b/functions/image processing and filters/cropmask.m new file mode 100644 index 0000000..0bcc858 --- /dev/null +++ b/functions/image processing and filters/cropmask.m @@ -0,0 +1,132 @@ +function [images,inputs]=cropmask(images,inputs) +%%Crop images to a mask +% +%Inputs: 1- Array of images created by loadtimeseries.m +% 2- Inputs array generated by the GUI +% +%Outputs: Same as inputs, but with images array cropped and filtered. +% +%This function takes the original satellite images, crops them to a user +%determined mask and filters then according to the inputs. Possible image +%filters include an orientation mask, lowpass filters, contrast limited +%histogram equalization, intensity capping, Sobel filter and Laplacian +%filter. See user manual for details and recommended default settings. +% +% +%This mask should be a .png image with perfect white in all areas to be +%considered and any other color elsewhere. +%This can easly be made by opening one of the images from the timeseries in +%Paint or another image editor and simply drawing a white polygon over the +%area of interest. +% +%This should be named mask (.png) and saved in the same folder as the rest +%of the timeseries. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +% Read the mask. It can be a .png or .jpg. Shapefile masks should be added +% in a future version. + +if exist(fullfile(inputs.folder,'mask.png')) > 0 + cdata = imread(fullfile(inputs.folder,'mask.png')); +elseif exist(fullfile(inputs.folder,'mask.jpg')) >0 + cdata = imread(fullfile(inputs.folder,'mask.jpg')); +end + +% Create binary mask from pure white pixels +cdata = double(cdata); +cdata = double(cdata(:,:,1))+double(cdata(:,:,2))+double(cdata(:,:,3)); +cdata(cdata==765) = NaN; +cdata(cdata>0)= 0; +cdata(isnan(cdata))= 1; +mask_0_1 = cdata; +inputs.cropmask = mask_0_1; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%DIMENSION CHECK. IF IMAGES and MASK are different sizes, make them the +%same size. This will particularly be the case if you are e.g. combining +%sentinel and landsat data. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +size_matrix = zeros(size(images,1),2); +size_matrix(1,1) = size(mask_0_1,1); +size_matrix(1,2) = size(mask_0_1,2); + +for i = 2:size(images,1) + size_matrix(i,1) = size(images{i,3},1); + size_matrix(i,2) = size(images{i,3},2); +end + +for i = 2:size(images,1) + if size(images{i,3},3)>1 + temp = zeros(size(images{i,3},1),size(images{i,3},2)); + for ii = 1:size(images{i,3},3) + temp = temp + double(images{i,3}(:,:,ii)); + end + images{i,3} = temp; + end +end + +if min(size_matrix(:,1)) ~= max(size_matrix(:,1)) || min(size_matrix(:,2)) ~= max(size_matrix(:,2)) + rightsizey = min(size_matrix(:,1)); + rightsizex = min(size_matrix(:,2)); + + if size(mask_0_1,1) ~= rightsizey || size(mask_0_1,2) ~=rightsizex + mask_0_1 = interp2(mask_0_1, linspace(1, size(mask_0_1,2), rightsizex).', linspace(1, size(mask_0_1,1), rightsizey)); + end + + for i = 2:size(images,1) + if size(images{i,3},1) ~= rightsizey || size(images{i,3},2) ~=rightsizex + images{i,3} = interp2(images{i,3}, (linspace(1, size(images{i,3},2), rightsizex).'), linspace(1, size(images{i,3},1), rightsizey)); + end + end +end + +%% This portion performs the pre-processing and crops to mask +%It can be done in parralel for speed: +if strcmpi(inputs.parralelize, 'Yes') + newcol = {}; + + parfor l = 2:size(images,1) + a1 = double(imageprefilter(images{l,3}, inputs)); + newcol{l,3} = flipud(a1); + end + + for i=2:size(images,1) + images{i,3}=newcol{i,3}; + end + +%Or in series if parrelelisation is not desired. +elseif strcmpi(inputs.parralelize, 'No') + + for l = 2:size(images,1) + a1 = double(imageprefilter(images{l,3}, inputs)); + images{l,3} = flipud(a1); + l=l+1; + end + +end + + diff --git a/functions/image processing and filters/imageprefilter.m b/functions/image processing and filters/imageprefilter.m new file mode 100644 index 0000000..19efae8 --- /dev/null +++ b/functions/image processing and filters/imageprefilter.m @@ -0,0 +1,127 @@ +function out = imageprefilter (in, inputs) +%This function takes an initial image and filters it according to user +%inputted parameters to improve its potential for cross correlation. +% +%Inputs: 1- Input image +% 2- inputs array +% +%Outputs - Filtered image + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + +%Parts of this funtion are partially based on the matlab 'PIVlab' toolbox. +%Credit to the original authors for CLAHE and lowpass pre-processing. + +%Note that the order of filtering can be modified. I have tested it out and +%found that this order typically works best, but if you e.g. wish to +%combine lowpass and Sobel you may wish to re-arrange. + +%If the image has multiple bands, compress to one. +if size(in,3)>1 + temp = zeros(size(in,1),size(in,2)); + + for i = 1:size(in,3) + temp = temp + double(in(:,:,i)); + end + + in = temp; +end + +%Preprocess: + +x=1; +y=1; +width=size(in,2)-1; +height=size(in,1)-1; +in_roi=(in(y:y+height,x:x+width)); +out=in; +out(y:y+height,x:x+width)=in_roi; +out=double(out); + + +%Perform Orientation filtering. + +%Note that different filters can be used +%here, I tested many and found that the 45 degree filters (termed NAOF, +%described in more detail in the paper) seem to preserve feature uniqueness +%best. See Filch et al., 2002: +%http://www.bmva.org/bmvc/2002/papers/95/full_95.pdf for a description of +%orientation filtering and its advantages. The paper is very readable. + +if inputs.NAOF == 1 + filter_1 = [-1 2 -1]; + filter_2 = [-1; 2; -1]; + filter_3 = [-1 0 0;0 2 0; 0 0 -1]; + filter_4 = [0 0 -1;0 2 0; -1 0 0]; + out = real(exp(1i*atan2(imfilter(out,filter_1,'replicate'),imfilter(out,rot90(filter_1),'replicate'))))... + +real(exp(1i*atan2(imfilter(out,filter_2,'replicate'),imfilter(out,rot90(filter_2),'replicate'))))... + +real(exp(1i*atan2(imfilter(out,filter_3,'replicate'),imfilter(out,rot90(filter_3),'replicate'))))... + +real(exp(1i*atan2(imfilter(out,filter_4,'replicate'),imfilter(out,rot90(filter_4),'replicate')))); +end + +in = out; + +%Intensity Capping: a simple method to improve cross-correlation PIV results +%Uri Shavit Æ Ryan J. Lowe Æ Jonah V. Steinbuck +if inputs.intenscap == 1 + n = 2; + up_lim_im_1 = median(double(in(:))) + n*std2(in); % upper limit for image 1 + brightspots_im_1 = find(in > up_lim_im_1); % bright spots in image 1 + capped_im_1 = in; capped_im_1(brightspots_im_1) = up_lim_im_1; % capped image 1 + in=capped_im_1; +end + +%CLAHE evens contrasts out throughout image. It is very good for shaded or +%cloudy images, but often not necessary when images are already orientation +%filtered. +if inputs.CLAHE == 1 + numberoftiles1=round(size(in,1)/inputs.CLAHEsize); + numberoftiles2=round(size(in,2)/inputs.CLAHEsize); + + if numberoftiles1 < 2 + numberoftiles1=2; + end + + if numberoftiles2 < 2 + numberoftiles2=2; + end + + in=adapthisteq(in, 'NumTiles',[numberoftiles1 numberoftiles2], 'ClipLimit', 0.01, 'NBins', 256, 'Range', 'full', 'Distribution', 'uniform'); +end + +%Highpass filter +if inputs.hipass == 1 + h = fspecial('gaussian',inputs.hipasssize,inputs.hipasssize); + in=double(in-(imfilter(in,h,'replicate'))); + in=in/max(max(in))*255; +end + +%Sobel and Laplacian edge enhancing filters. +if inputs.sobel == 1 + in = SobelFilter(in,3); +end + +if inputs.laplacian == 1 + in = LaplaceFilter(in,4); +end + +out = in; \ No newline at end of file diff --git a/functions/other/GIV_circstats.m b/functions/other/GIV_circstats.m new file mode 100644 index 0000000..a639d6a --- /dev/null +++ b/functions/other/GIV_circstats.m @@ -0,0 +1,30 @@ +function [mean_fd,std_fd] = GIV_circstats(input,weighting) +%This function calculates the statistics (mean, standard deviation) of a +% circular (anglular) dataset. This is done in degrees. +% +%Inputs: -1 input circular dataset to calculate statistics on. Stats will +%be calculated in the 'y' dimension (column, dim=1) +% +%Outputs: -Mean +% -Standard deviation +% -Maximum +% -Minimum +% -Median +% +%Note: This is based on functions by Philipp Berens's CircStat, modified to +%tolerate NaN values and multi-column matrices. + +if nargin<2 %No weighting + mean_fd = circ_rad2ang(nancirc_mean(deg2rad(input),1)); + std_fd = circ_rad2ang(nancirc_std(deg2rad(input),1)); + +else %Weighting is applied + mean_fd = circ_rad2ang(nancirc_mean(deg2rad(input),1,weighting)); + std_fd = circ_rad2ang(nancirc_std(deg2rad(input),1,weighting)); + +end + + + +end + diff --git a/functions/other/GIVruntime.m b/functions/other/GIVruntime.m new file mode 100644 index 0000000..dfaa164 --- /dev/null +++ b/functions/other/GIVruntime.m @@ -0,0 +1,222 @@ +function GIVruntime(inputs) +%This function calculates the number of possible image pairs in a given +%dataset. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +%% load images +% +% Images to be tracked should be located in one single folder, and named +% with the following convention "yyyymmdd". This format is the most +% convinient for archiving time series, as images will sort into order. +% +%Any deviation from this naming convention will result in the images not +%being picked up correctly. +% +%Ideally at this point the images should be correctly georeferences +%(covering the same area). Downloaded Sentinel2 scenes should naturally +%have this property. Other images may need manually colocating in a GIS +%program prior to processing. +% +% +% Specify the folder where the files live. Copy paste the path from file +% explorer for example. An error message will be returned if it is somehow +% misspelt. +% +%Specify the first year of the timeseries (eg:2011) and the last year (eg: +%2017). + + +% Check to make sure that folder actually exists. Warn user if it doesn't. +if ~isdir(inputs.folder) + errorMessage = sprintf('Error: The following folder does not exist:\n%s', inputs.folder); + uiwait(warndlg(errorMessage)); + return; +end + +%The correct folder should now be located. The objective of the following +%loop is to read the images from the folder into an array named 'images' +%and extract relevant metadata. + +images = {}; % create an empty cell array to store everything + +%name columns for future clarity +images{1,1} = 'Image Number'; +images{1,2} = 'Image Date'; +images{1,3} = 'Image masked'; +images{1,4} = 'Date code'; +images{1,5} = 'Days from beginning'; +images{1,6} = 'Interval in years'; +k = 2; % index into cell array for next read image + +n_day = 0; +%load animate images +for y=inputs.minyear:inputs.maxyear; + y = num2str(y); + for m=inputs.minmonth:inputs.maxmonth; + if m < 10 + m = strcat('0',num2str(m)); + else + m = num2str(m); + end + + for d=inputs.minday:inputs.maxday + if d < 10 + d = strcat('0',num2str(d)); + else + d = num2str(d); + end + if strcmpi(inputs.isgeotiff,'No') + datejpg = strcat(y,m,d,'.jpg'); + datepng = strcat(y,m,d,'.png'); + if exist(fullfile(inputs.folder, datejpg),'file') + % read k onto first column + % read date into second column + % read the image into the kth position of the cell array on the + % third column + %create n_day, the number of days between different images + n_day = datenum(str2num(y),str2num(m),str2num(d)); + %load n_day to fouth column + images{k,1}=k; + images{k,2}=(strcat(y,m,d)); + images{k,3}=(imread(fullfile(inputs.folder,datejpg))); + images{k,4}=n_day; + % increment k for the next iteration + k=k+1; + elseif exist(fullfile(inputs.folder, datepng),'file') + % read k onto first column + % read date into second column + % read the image into the kth position of the cell array on the + % third column + %create n_day, the number of days between different images + n_day = datenum(str2num(y),str2num(m),str2num(d)); + %load n_day to fouth column + images{k,1}=k; + images{k,2}=(strcat(y,m,d)); + images{k,3}=(imread(fullfile(inputs.folder,datepng))); + images{k,4}=n_day; + % increment k for the next iteration + k=k+1; + + end + else + datetif = strcat(y,m,d,'.tif'); + + if exist(fullfile(inputs.folder, datetif),'file') + n_day = datenum(str2num(y),str2num(m),str2num(d)); + %load n_day to fouth column + images{k,1}=k; + images{k,2}=(strcat(y,m,d)); + images{k,3}=(imread(fullfile(inputs.folder,datetif))); + images{k,4}=n_day; + % increment k for the next iteration + k=k+1; + end + end + end + end +end + +size_tocrop = size(images); +num_images = size_tocrop(1); +inputs.numimages = 'Number of Images + 1'; +inputs.numimages = num_images; + +%this loop extracts the number of days that have passed for a given image +%since the first image in the series +l = 2; +for l = 2:(num_images) + images{l,5} = images{l,4} - images{2,4}; + l=l+1; +end + +%This loop extracts the number of days between succesive images from the +%previous result. This information is necessary to calculate ice velocity. +c = 2; +for c = 2:num_images + if c < 3; + images{c,6} = 0; + else + c_2 = c-1; + images{c,6} = (images{c,5}(1) - images{c_2,5}(1))/365; + end + c = c+1; +end + +% At this point all the data we need should be loaded into one array, +% called 'images'. +% We can call the images, image time spacing, etc from this array. + + +%% Now calculate the time taken to calculate image pairs + +%%%%%%%%%%%%%%%%%%% code that calculates number of image pairs available +%%%%%%%%%%%%%%%%%%% for different temporal oversampling + +numpairs = zeros(inputs.numimages,3); +previous_number = 0; + +for i = 1:inputs.numimages + number_in_range = 0; + meta_dum = 0; + array_pos = 0; + emptycount_inner = 0; + emptycount_outer = 0; + +for time_loop = 1:i %for multisampling in time + for inner_loop = 2:inputs.numimages-time_loop %main loop + loop2 = inner_loop+time_loop; %for multisampling in time, will skip one for higher time_bracket + + %Work out time between two images. + A1_t= (images{inner_loop,5}); + B1_t= (images{loop2,5}); + timestep = (B1_t-A1_t)/365; + if timestep <= inputs.maxinterval && timestep >= inputs.mininterval + number_in_range = number_in_range + 1; + end + emptycount_outer = emptycount_outer + emptycount_inner; + emptycount_inner = 0; + meta_dum = meta_dum + inputs.numimages-time_loop-1; + array_pos = array_pos+1; + end +end + +numpairs(i,1) = i; +numpairs(i,2) = number_in_range; +numpairs(i,3) = number_in_range-previous_number; +previous_number = number_in_range; +end + + +%Line plot of total number of pairs vs t oversampling +figure; plot(numpairs(:,1),numpairs(:,2),'k') + title('Total number of image pairs') + xlabel('Temporal oversampling value') + ylabel('Number of pairs') +% % %Line plot of total number of pairs vs t oversampling, only first 10 +% % figure; plot(numpairs(1:10,1),numpairs(1:10,2),'k') +%Scatter plot of number of pairs for each oversampling +figure; bar(numpairs(:,1),numpairs(:,3),'k') + title('Number of image pairs per individual oversample') + xlabel('Temporal oversampling value') + ylabel('Number of pairs') diff --git a/functions/other/circ_ang2rad.m b/functions/other/circ_ang2rad.m new file mode 100644 index 0000000..ded0c2a --- /dev/null +++ b/functions/other/circ_ang2rad.m @@ -0,0 +1,11 @@ +function alpha = circ_ang2rad(alpha) + +% alpha = circ_ang2rad(alpha) +% converts values in degree to radians +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +alpha = alpha * pi /180; diff --git a/functions/other/circ_rad2ang.m b/functions/other/circ_rad2ang.m new file mode 100644 index 0000000..74570f7 --- /dev/null +++ b/functions/other/circ_rad2ang.m @@ -0,0 +1,15 @@ +function alpha = circ_rad2ang(alpha) + +% alpha = circ-rad2ang(alpha) +% converts values in radians to values in degree (0-360) +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +alpha = alpha / pi *180; + +pos = alpha<0; + +alpha(pos)=360+alpha(pos); \ No newline at end of file diff --git a/functions/other/circstat-matlab-master/Contents.m b/functions/other/circstat-matlab-master/Contents.m new file mode 100644 index 0000000..f6df6d1 --- /dev/null +++ b/functions/other/circstat-matlab-master/Contents.m @@ -0,0 +1,62 @@ +% CircStat Toolbox +% Toolbox for circular statistics with Matlab +% +% Descriptive Statistics. +% circ_mean - Mean direction of a sample of circular data +% circ_median - Median direction of a sample of circular data +% circ_r - Resultant vector length +% circ_var - Circular variance +% circ_std - Circular standard deviation +% circ_moment - Circular p-th moment +% circ_skewness - Circular skewness +% circ_kurtosis - Circular kurtosis +% +% Inferential Statistics. +% Testing for Circular Uniformity. +% circ_rtest - Rayleigh's test for nonuniformity +% circ_otest - Hodges-Ajne test (omnibus test) for nonuniformity +% circ_raotest - Rao's spacing test for nonuniformity +% circ_vtest - V-Test for nonuniformity with known mean direction +% +% Tests Concerning Mean and Median. +% circ_confmean - Confidence intervals for mean direction +% circ_mtest - One-sample test for specified mean direction +% circ_medtest - Test for median angle +% circ_symtest - Test for symmetry around median angle +% +% Paired and Multisample Tests. +% circ_wwtest - Two and multi-sample test for equal means; +% one-factor ANOVA +% circ_hktest - Two-factor ANOVA +% circ_cmtest - Non-parametric multi-sample test for equal medians +% circ_ktest - Test for equal concentration parameter +% circ_kuipertest - Test for equality of distributions (KS-test) +% +% Measures of Association. +% circ_corrcc - Circular-circular correlation coefficient +% circ_corrcl - Circular-linear correlation coefficient +% +% The Von Mises Distribution +% circ_vmpdf - Probability density function of the von Mises +% distribution +% circ_vmpar - Parameter estimation +% circ_vmrnd - Random number generation +% +% Others. +% circ_axial - Convert axial data to common scale +% circ_dist - Distances around a circle +% circ_dist2 - Pairwise distances around a circle +% circ_stats - Summary statistics +% circ_kappa - Compute concentration parameter of a VM distribution +% circ_plot - Visualization for circular data +% circ_clust - Simple clustering +% circ_rad2ang - Convert radian to angular values +% circ_ang2rad - Convert angular to radian values +% circ_samplecdf - Evaluate CDF of a sample +% +% Reference: +% P. Berens, CircStat: A Matlab Toolbox for Circular Statistics, Journal of Statistical Software,Vol. 31, Issue 10, 2009 +% http://www.jstatsoft.org/v31/i10 +% +% Author: +% Philipp Berens & Marc J. Velasco, 2009 diff --git a/functions/other/circstat-matlab-master/README.md b/functions/other/circstat-matlab-master/README.md new file mode 100644 index 0000000..88095c5 --- /dev/null +++ b/functions/other/circstat-matlab-master/README.md @@ -0,0 +1,82 @@ +CircStat for Matlab +======================= + +Toolbox for circular statistics with Matlab. + +## Authors: +Philipp Berens + +*Email*: philipp.berens@uni-tuebingen.de + +*Homepage*: www.berenslab.org + +## Contributors: +Tal Krasovsky & Marc J. Velasco + +## Reference: +P. Berens, CircStat: A Matlab Toolbox for Circular Statistics, Journal of Statistical Software, Volume 31, Issue 10, 2009 +http://www.jstatsoft.org/v31/i10 + +Please cite this paper when the provided code is used. See licensing terms for details. + +## Contents: +- `circ_r` Resultant vector length +- `circ_mean` Mean direction of a sample of circular data +- `circ_axial` Mean direction for axial data +- `circ_median` Median direction of a sample of circular data +- `circ_std` Dispersion around the mean direction (std, mardia) +- `circ_var` Circular variance +- `circ_skewness` Circular skewness +- `circ_kurtosis` Circular kurtosis +- `circ_moment` Circular p-th moment +- `circ_dist` Distances around a circle +- `circ_dist2` Pairwise distances around a circle +- `circ_confmean` Confidence intervals for mean direction +- `circ_stats` Summary statistics + +  +- `circ_rtest` Rayleigh's test for nonuniformity +- `circ_otest` Hodges-Ajne test (omnibus test) for nonuniformity +- `circ_raotest` Rao's spacing test for nonuniformity +- `circ_vtest` V-Test for nonuniformity with known mean direction +- `circ_medtest` Test for median angle +- `circ_mtest` One-sample test for specified mean direction +- `circ_wwtest` Multi-sample test for equal means, one-factor ANOVA +- `circ_hktest` Two-factor ANOVA +- `circ_ktest` Test for equal concentration parameter +- `circ_symtest` Test for symmetry around median angle +- `circ_kuipertest` Test whether two distributions are identical (like KS test) + +  +- `circ_corrcc` Circular-circular correlation coefficient +- `circ_corrcl` Circular-linear correlation coefficient + +  +- `circ_kappa` Compute concentration parameter of a von Mises distribution +- `circ_plot` Visualization for circular data +- `circ_clust` Simple clustering for circular data +- `circ_samplecdf` Evaluate CDF of a sample of angles + +  +- `rad2ang` Convert radian to angular values +- `ang2rad` Convert angular to radian values + +All functions take arguments in radians (expect for `ang2rad`). For a detailed description of arguments and outputs consult the help text in the files. + +Since 2010, most functions for descriptive statistics can be used in Matlab style matrix computations. As a last argument, add the dimension along which you want to average. This changes the behavior slightly from previous relaeses, in that input is not reshaped anymore into vector format. Per default, all computations are performed columnwise (along dimension 1). If you prefer to use the old functions, for now they are contained in the subdirectory 'old'. + +## References: +- E. Batschelet, Circular Statistics in Biology, Academic Press, 1981 +- N.I. Fisher, Statistical analysis of circular data, Cambridge University Press, 1996 +- S.R. Jammalamadaka et al., Topics in circular statistics, World Scientific, 2001 +- J.H. Zar, Biostatistical Analysis, Prentice Hall, 1999 + + +The implementation follows in most cases 'Biostatistical Analysis' and all referenced equations and tables are taken from this book, if not otherwise noted. In some cases, the other books were preferred for implementation was more straightforward for solutions presented there. + +If you have suggestions, bugs or feature requests or want to contribute code, please email us. + +## Disclaimer: +All functions in this toolbox were implemented with care and tested on the examples presented in 'Biostatistical Analysis' were possible. Nevertheless, they may contain errors or bugs, which may affect the outcome of your analysis. We do not take responsibility for any harm coming from using this toolbox, neither if it is caused by errors in the software nor if it is caused by its improper application. Please email us any bugs you find. + +Distributed under Open Source BSD License diff --git a/functions/other/circstat-matlab-master/circ_ang2rad.m b/functions/other/circstat-matlab-master/circ_ang2rad.m new file mode 100644 index 0000000..f8d7dd0 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_ang2rad.m @@ -0,0 +1,12 @@ +function alpha = circ_ang2rad(alpha) + +% alpha = circ_ang2rad(alpha) +% converts values in degree to radians +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +alpha = alpha * pi /180; +end diff --git a/functions/other/circstat-matlab-master/circ_axial.m b/functions/other/circstat-matlab-master/circ_axial.m new file mode 100644 index 0000000..1cccc51 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_axial.m @@ -0,0 +1,30 @@ +function alpha = circ_axial(alpha, p) +% +% alpha = circ_axial(alpha, p) +% Transforms p-axial data to a common scale. +% +% Input: +% alpha sample of angles in radians +% [p number of modes] +% +% Output: +% alpha transformed data +% +% PHB 2009 +% +% References: +% Statistical analysis of circular data, N. I. Fisher +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + + + +if nargin < 2 + p = 1; +end + +alpha = mod(alpha*p,2*pi); +end diff --git a/functions/other/circstat-matlab-master/circ_axialmean.m b/functions/other/circstat-matlab-master/circ_axialmean.m new file mode 100644 index 0000000..dce22a2 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_axialmean.m @@ -0,0 +1,44 @@ +function [r, mu] = circ_axialmean(alphas, m, dim) +% +% mu = circ_axialmean(alpha, w) +% Computes the mean direction for circular data with axial +% correction. +% +% Input: +% alpha sample of angles in radians +% [m axial correction (2,3,4,...)] +% [dim statistic computed along this dimension, default: 1st non-singular dimension] +% +% Output: +% r mean resultant length +% mu mean direction +% +% PHB 7/6/2008 +% +% References: +% Statistical analysis of circular data, N. I. Fisher +% Topics in circular statistics, S. R. Jammalamadaka et al. +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html +% Distributed under Open Source BSD License + +if nargin < 3 + dim = find(size(alphas) > 1, 1, 'first'); + if isempty(dim) + dim = 1; + end +end + +if nargin < 2 || isempty(m) + m = 1; +end + +zbarm = mean(exp(1i*alphas*m),dim); + +r = abs(zbarm); +mu = angle(zbarm)/m; +end diff --git a/functions/other/circstat-matlab-master/circ_clust.m b/functions/other/circstat-matlab-master/circ_clust.m new file mode 100644 index 0000000..b95450f --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_clust.m @@ -0,0 +1,150 @@ +function [cid, alpha, mu] = circ_clust(alpha, numclust, disp) +% +% [cid, alpha, mu] = circClust(alpha, numclust, disp) +% Performs a simple agglomerative clustering of angular data. +% +% Input: +% alpha sample of angles +% numclust number of clusters desired, default: 2 +% disp show plot at each step, default: false +% +% Output: +% cid cluster id for each entry of alpha +% alpha sorted angles, matched with cid +% mu mean direction of angles in each cluster +% +% Run without any input arguments for demo mode. +% +% Circular Statistics Toolbox for Matlab + +% By Marc J. Velasco and Philipp Berens, 2009 +% velasco@ccs.fau.edu +% Distributed under Open Source BSD License + + +if nargin < 2, numclust = 5; end; +if nargin < 3, disp = 0; end +if nargin < 1 + % demo mode + n = 20; + alpha = 2*pi*rand(n,1)-pi; + numclust = 4; + disp = 1; +end; + +n = length(alpha); +if n < numclust, error('Not enough data for clusters.'), end + +% prepare data +cid = (1:n)'; + +% main clustering loop +num_unique = length(unique(cid)); +num_clusters_wanted = numclust; + +while(num_unique > num_clusters_wanted) + + % find centroid means... + + % calculate the means for each putative cluster + mu = NaN(n,1); + for j=1:n + if sum(cid==j)>0 + mu(j) = circ_mean(alpha(cid==j)'); + end + end + + % find distance between centroids... + mudist = abs(circ_dist2(mu)); + + % find closest pair of clusters/datapoints + mindist = min(mudist(tril(ones(size(mudist)),-1)==1)); + [row, col] = find(mudist==mindist); + + % update cluster id's + cid(cid==max(row)) = min(col); + + % update stop criteria + num_unique = length(unique(cid)); + +end + +% renumber cluster ids (so cids [1 3 7 10] => [1 2 3 4] +cid2 = cid; +uniquecids = unique(cid); +for j=1:length(uniquecids) + cid(cid2==uniquecids(j)) = j; +end + +% compute final cluster means +mu = NaN(num_unique,1); +r = NaN(num_unique,1); +for j=1:num_unique + if sum(cid==j)>0 + mu(j) = circ_mean(alpha(cid==j)'); + r(j) = circ_r(alpha(cid==j)'); + end +end + +if disp + % plot output + z2 = exp(1i*alpha); + plotColor(real(z2), imag(z2), cid, 2) + zmu = r.*exp(1i*mu); + plotColor(real(zmu), imag(zmu), 1:num_unique, 2, '*', 10, 1) + + axis square + set(gca, 'XLim', [-1, 1]); + set(gca, 'YLim', [-1, 1]); +end + + +function plotColor(x, y, c, varargin) +% FUNCTION plotColor(x, y, c, [figurenum], [pstring], [markersize], [overlay_tf]); +% plots a scatter plot for x, y, using color values in c (c should be +% categorical info), with c same size as x and y; +% fourth argument can be figure#, otherwise, uses figure(1); +% +% colors should be positive integes + +% copyright (c) 2009 Marc J. Velasco + +if nargin < 4 + figurenum = 1; +else + figurenum = varargin{1}; +end +if nargin < 5 + pstring = '.'; +else + pstring = varargin{2}; +end +if nargin < 6 + ms = 10; +else + ms = varargin{3}; +end +if nargin < 7 + overlay = 0; +else + overlay = varargin{4}; +end + +csmall = unique(c); +figure(figurenum); +if ~overlay, close(figurenum); end +figure(figurenum); + +colors={'y', 'b', 'r', 'g', 'c', 'k', 'm'}; + +hold on; +for j=1:length(csmall) + + ci = (c == csmall(j)); + plot(x(ci), y(ci), strcat(pstring, colors{mod(j, length(colors))+1}), 'MarkerSize', ms); + +end +if ~overlay, hold off; end +figure(figurenum) +end +end diff --git a/functions/other/circstat-matlab-master/circ_cmtest.m b/functions/other/circstat-matlab-master/circ_cmtest.m new file mode 100644 index 0000000..dce7864 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_cmtest.m @@ -0,0 +1,91 @@ +function [pval, med, P] = circ_cmtest(varargin) +% +% [pval, med, P] = circ_cmtest(alpha, idx) +% [pval, med, P] = circ_cmtest(alpha1, alpha2) +% Non parametric multi-sample test for equal medians. Similar to a +% Kruskal-Wallis test for linear data. +% +% H0: the s populations have equal medians +% HA: the s populations have unequal medians +% +% Input: +% alpha angles in radians +% idx indicates which population the respective angle in alpha +% comes from, 1:s +% +% Output: +% pval p-value of the common median multi-sample test. Discard H0 if +% pval is small. +% med best estimate of shared population median if H0 is not +% discarded at the 0.05 level and NaN otherwise. +% P test statistic of the common median test. +% +% +% PHB 7/19/2009 +% +% References: +% Fisher NI, 1995 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +[alpha, idx] = processInput(varargin{:}); + +% number of groups +u = unique(idx); +s = length(u); + +% number of samples +N = length(idx); + +% total median +med = circ_median(alpha); + +% compute relevant quantitites +n = zeros(s,1); m = n; +for t=1:s + pidx = idx == u(t); + n(t) = sum(pidx); + + d = circ_dist(alpha(pidx),med); + + m(t) = sum(d<0); +end + +if any(n<10) + warning('CIRCSTAT:circ_cmtest:sampleSizeTooSmall', ... + 'Test not applicable. Sample size in at least one group too small.') %#ok +end + + +M = sum(m); +P = (N^2/(M*(N-M))) * sum(m.^2 ./ n) - N*M/(N-M); + +pval = 1 - chi2cdf(P,s-1); + +if pval < 0.05 + med = NaN; +end +end + + + +function [alpha, idx] = processInput(varargin) + +if nargin==2 && sum(abs(round(varargin{2})-varargin{2}))>1e-5 + alpha1 = varargin{1}(:); + alpha2 = varargin{2}(:); + alpha = [alpha1; alpha2]; + idx = [ones(size(alpha1)); 2*ones(size(alpha2))]; +elseif nargin==2 + alpha = varargin{1}(:); + idx = varargin{2}(:); + if ~(size(idx,1)==size(alpha,1)) + error('Input dimensions do not match.') + end +else + error('Invalid use of circ_wwtest. Type help circ_wwtest.') +end +end diff --git a/functions/other/circstat-matlab-master/circ_confmean.m b/functions/other/circstat-matlab-master/circ_confmean.m new file mode 100644 index 0000000..9acb322 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_confmean.m @@ -0,0 +1,80 @@ +function t = circ_confmean(alpha, xi, w, d, dim) +% +% t = circ_mean(alpha, xi, w, d, dim) +% Computes the confidence limits on the mean for circular data. +% +% Input: +% alpha sample of angles in radians +% [xi (1-xi)-confidence limits are computed, default 0.05] +% [w number of incidences in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r, in radians (!)] +% [dim compute along this dimension, default: 1st non-singular dimension] +% +% Output: +% t mean +- d yields upper/lower (1-xi)% confidence limit +% +% PHB 7/6/2008 +% +% References: +% Statistical analysis of circular data, N. I. Fisher +% Topics in circular statistics, S. R. Jammalamadaka et al. +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if nargin < 5 + dim = find(size(alpha) > 1, 1, 'first'); + if isempty(dim) + dim = 1; + end +end + +if nargin < 4 || isempty(d) + % per default do not apply correct for binned data + d = 0; +end + +if nargin < 3 || isempty(w) + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) ~= size(alpha,2) || size(w,1) ~= size(alpha,1) + error('Input dimensions do not match'); + end +end + +% set confidence limit size to default +if nargin < 2 || isempty(xi) + xi = 0.05; +end + +% compute ingredients for conf. lim. +r = circ_r(alpha,w,d,dim); +n = sum(w,dim); +R = n.*r; +c2 = chi2inv((1-xi),1); + +% check for resultant vector length and select appropriate formula +t = zeros(size(r)); + +for i = 1:numel(r) + if r(i) < .9 && r(i) > sqrt(c2/2/n(i)) + t(i) = sqrt((2*n(i)*(2*R(i)^2-n(i)*c2))/(4*n(i)-c2)); % equ. 26.24 + elseif r(i) >= .9 + t(i) = sqrt(n(i)^2-(n(i)^2-R(i)^2)*exp(c2/n(i))); % equ. 26.25 + else + t(i) = NaN; + warning('CIRCSTAT:circ_confmean:requirementsNotMet', ... + 'Requirements for confidence levels not met.'); + end +end + +% apply final transform +t = acos(t./R); +end diff --git a/functions/other/circstat-matlab-master/circ_corrcc.m b/functions/other/circstat-matlab-master/circ_corrcc.m new file mode 100644 index 0000000..78d0808 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_corrcc.m @@ -0,0 +1,53 @@ +function [rho, pval] = circ_corrcc(alpha1, alpha2) +% +% [rho pval] = circ_corrcc(alpha1, alpha2) +% Circular correlation coefficient for two circular random variables. +% +% Input: +% alpha1 sample of angles in radians +% alpha2 sample of angles in radians +% +% Output: +% rho correlation coefficient +% pval p-value +% +% References: +% Topics in circular statistics, S.R. Jammalamadaka et al., p. 176 +% +% PHB 6/7/2008 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if size(alpha1,2) > size(alpha1,1) + alpha1 = alpha1'; +end + +if size(alpha2,2) > size(alpha2,1) + alpha2 = alpha2'; +end + +if length(alpha1)~=length(alpha2) + error('Input dimensions do not match.') +end + +% compute mean directions +n = length(alpha1); +alpha1_bar = circ_mean(alpha1); +alpha2_bar = circ_mean(alpha2); + +% compute correlation coeffcient from p. 176 +num = sum(sin(alpha1 - alpha1_bar) .* sin(alpha2 - alpha2_bar)); +den = sqrt(sum(sin(alpha1 - alpha1_bar).^2) .* sum(sin(alpha2 - alpha2_bar).^2)); +rho = num / den; + +% compute pvalue +l20 = mean(sin(alpha1 - alpha1_bar).^2); +l02 = mean(sin(alpha2 - alpha2_bar).^2); +l22 = mean((sin(alpha1 - alpha1_bar).^2) .* (sin(alpha2 - alpha2_bar).^2)); + +ts = sqrt((n * l20 * l02)/l22) * rho; +pval = 2 * (1 - normcdf(abs(ts))); +end diff --git a/functions/other/circstat-matlab-master/circ_corrcl.m b/functions/other/circstat-matlab-master/circ_corrcl.m new file mode 100644 index 0000000..1610403 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_corrcl.m @@ -0,0 +1,50 @@ +function [rho, pval] = circ_corrcl(alpha, x) +% +% [rho pval] = circ_corrcc(alpha, x) +% Correlation coefficient between one circular and one linear random +% variable. +% +% Input: +% alpha sample of angles in radians +% x sample of linear random variable +% +% Output: +% rho correlation coefficient +% pval p-value +% +% References: +% Biostatistical Analysis, J. H. Zar, p. 651 +% +% PHB 6/7/2008 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + + +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +if size(x,2) > size(x,1) + x = x'; +end + +if length(alpha)~=length(x) + error('Input dimensions do not match.') +end + +n = length(alpha); + +% compute correlation coefficent for sin and cos independently +rxs = corr(x,sin(alpha)); +rxc = corr(x,cos(alpha)); +rcs = corr(sin(alpha),cos(alpha)); + +% compute angular-linear correlation (equ. 27.47) +rho = sqrt((rxc^2 + rxs^2 - 2*rxc*rxs*rcs)/(1-rcs^2)); + +% compute pvalue +pval = 1 - chi2cdf(n*rho^2,2); +end diff --git a/functions/other/circstat-matlab-master/circ_dist.m b/functions/other/circstat-matlab-master/circ_dist.m new file mode 100644 index 0000000..b9a90ae --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_dist.m @@ -0,0 +1,29 @@ +function r = circ_dist(x,y) +% +% r = circ_dist(alpha, beta) +% Pairwise difference x_i-y_i around the circle computed efficiently. +% +% Input: +% alpha sample of linear random variable +% beta sample of linear random variable or one single angle +% +% Output: +% r matrix with differences +% +% References: +% Biostatistical Analysis, J. H. Zar, p. 651 +% +% PHB 3/19/2009 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + + +if size(x,1)~=size(y,1) && size(x,2)~=size(y,2) && length(y)~=1 + error('Input dimensions do not match.') +end + +r = angle(exp(1i*x)./exp(1i*y)); +end diff --git a/functions/other/circstat-matlab-master/circ_dist2.m b/functions/other/circstat-matlab-master/circ_dist2.m new file mode 100644 index 0000000..f260475 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_dist2.m @@ -0,0 +1,37 @@ +function r = circ_dist2(x,y) +% +% r = circ_dist2(alpha, beta) +% All pairwise difference x_i-y_j around the circle computed efficiently. +% +% Input: +% alpha sample of linear random variable +% beta sample of linear random variable +% +% Output: +% r matrix with pairwise differences +% +% References: +% Biostatistical Analysis, J. H. Zar, p. 651 +% +% PHB 3/19/2009 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if nargin < 2 + y = x; +end + +if size(x,2)>size(x,1) + x = x'; +end + +if size(y,2)>size(y,1) + y = y'; +end + +r = angle(repmat(exp(1i*x),1,length(y)) ... + ./ repmat(exp(1i*y'),length(x),1)); +end diff --git a/functions/other/circstat-matlab-master/circ_hktest.m b/functions/other/circstat-matlab-master/circ_hktest.m new file mode 100644 index 0000000..46c3cc8 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_hktest.m @@ -0,0 +1,241 @@ +function [pval, table] = circ_hktest(alpha, idp, idq, inter, fn) + +% +% [pval, stats] = circ_hktest(alpha, idp, idq, inter, fn) +% Parametric two-way ANOVA for circular data with interations. +% +% Input: +% alpha angles in radians +% idp indicates the level of factor 1 (1:p) +% idq indicates the level of factor 2 (1:q) +% inter 0 or 1 - whether to include effect of interaction or not +% fn cell array containing strings with the names of the factors +% +% +% Output: +% pval vector of pvalues testing column, row and interaction effects +% table cell array containg the anova table +% +% The test assumes underlying von-Mises distributrions. +% All groups are assumed to have a common concentration parameter k, +% between 0 and 2. +% +% Update 2012 +% PHB 7/19/2009 with code by Tal Krasovsky, Mc Gill University +% +% References: +% Harrison, D. and Kanji, G. K. (1988). The development of analysis of variance for +% circular data. Journal of applied statistics, 15(2), 197-223. +% +% Circular Statistics Toolbox for Matlab + +% process inputs +alpha = alpha(:); idp = idp(:); idq = idq(:); + +if nargin < 4 + inter = true; +end + +if nargin < 5 + fn = {'A','B'}; +end + + +% number of groups for every factor +pu = unique(idp); +p = length(pu); +qu = unique(idq); +q = length(qu); + +% number of samples +n = length(alpha); + +% compute important sums for the test statistics +cn = zeros(p,q); cr = cn; +pm = zeros(p,1); pr = pm; pn = pm; +qm = zeros(q,1); qr = qm; qn = qm; +for pp = 1:p + p_id = idp == pu(pp); % indices of factor1 = pp + for qq = 1:q + q_id = idq == qu(qq); % indices of factor2 = qq + idx = p_id & q_id; + cn(pp,qq) = sum(idx); % number of items in cell + cr(pp,qq) = cn(pp,qq) * circ_r(alpha(idx)); % R of cell + end + % R and mean angle for factor 1 + pr(pp) = sum(p_id) * circ_r(alpha(p_id)); + pm(pp) = circ_mean(alpha(p_id)); + pn(pp) = sum(p_id); +end + +% R and mean angle for factor 2 +for qq = 1:q + q_id = idq == qu(qq); + qr(qq) = sum(q_id) * circ_r(alpha(q_id)); + qm(qq) = circ_mean(alpha(q_id)); + qn(qq) = sum(q_id); +end + +% R and mean angle for whole sample (total) +tr = n * circ_r(alpha); + +% estimate kappa +kk = circ_kappa(tr/n); + +% different formulas for different width of the distribution +if kk > 2 + % large kappa + + % effect of factor 1 + eff_1 = sum(pr.^2 ./ sum(cn,2)) - tr.^2/n; + df_1 = p-1; + ms_1 = eff_1 / df_1; + + % effect of factor 2 + eff_2 = sum(qr.^2 ./ sum(cn,1)') - tr.^2/n; + df_2 = q-1; + ms_2 = eff_2 / df_2; + + % total effect + eff_t = n - tr.^2/n; + df_t = n-1; + + m = mean(cn(:)); + + if inter + + % correction factor for improved F statistic + beta = 1/(1-1/(5*kk)-1/(10*(kk^2))); + + % residual effects + eff_r = n - sum(sum(cr.^2./cn)); + df_r = p*q*(m-1); + ms_r = eff_r / df_r; + + % interaction effects + eff_i = sum(sum(cr.^2./cn)) - sum(qr.^2./qn) ... + - sum(pr.^2./pn) + tr.^2/n; + df_i = (p-1)*(q-1); + ms_i = eff_i/df_i; + + % interaction test statistic + FI = ms_i / ms_r; + pI = 1-fcdf(FI,df_i,df_r); + + else + + % residual effect + eff_r = n - sum(qr.^2./qn)- sum(pr.^2./pn) + tr.^2/n; + df_r = (p-1)*(q-1); + ms_r = eff_r / df_r; + + % interaction effects + eff_i = []; + df_i = []; + ms_i =[]; + + % interaction test statistic + FI = []; + pI = NaN; + beta = 1; + end + + % compute all test statistics as + % F = beta * MS(A) / MS(R); + + F1 = beta * ms_1 / ms_r; + p1 = 1 - fcdf(F1,df_1,df_r); + + F2 = beta * ms_2 / ms_r; + p2 = 1 - fcdf(F2,df_2,df_r); + +else + % small kappa + + % correction factor + rr = besseli(1,kk) / besseli(0,kk); + f = 2/(1-rr^2); + + chi1 = f * (sum(pr.^2./pn)- tr.^2/n); + df_1 = 2*(p-1); + p1 = 1 - chi2cdf(chi1, df_1); + + chi2 = f * (sum(qr.^2./qn)- tr.^2/n); + df_2 = 2*(q-1); + p2 = 1 - chi2cdf(chi2, df_2); + + chiI = f * (sum(sum(cr.^2 ./ cn)) - sum(pr.^2./pn) ... + - sum(qr.^2./qn)+ tr.^2/n); + df_i = (p-1) * (q-1); + % pI = 1 - chi2pdf(chiI, df_i); % bugfix 2012 + pI = 1 - chi2cdf(chiI, df_i); + +end + +na = nargout; +if na < 2 + printTable; +end + +prepareOutput; + + + + + function printTable + + if kk>2 + + fprintf('\nANALYSIS OF VARIANCE TABLE (HIGH KAPPA MODE)\n\n'); + + fprintf('%s\t\t\t\t%s\t%s\t\t%s\t\t%s\t\t\t%s\n', ' ' ,'d.f.', 'SS', 'MS', 'F', 'P-Value'); + fprintf('--------------------------------------------------------------------\n'); + fprintf('%s\t\t\t\t%u\t\t%.2f\t%.2f\t%.2f\t\t%.4f\n', fn{1}, df_1 , eff_1, ms_1, F1, p1); + fprintf('%s\t\t\t\t%u\t\t%.2f\t%.2f\t%.2f\t\t%.4f\n', fn{2}, df_2 , eff_2, ms_2, F2, p2); + if (inter) + fprintf('%s\t\t%u\t\t%.2f\t%.2f\t%.2f\t\t%.4f\n', 'Interaction', df_i , eff_i, ms_i, FI, pI); + end + fprintf('%s\t\t%u\t\t%.2f\t%.2f\n', 'Residual ', df_r, eff_r, ms_r); + fprintf('--------------------------------------------------------------------\n'); + fprintf('%s\t\t%u\t\t%.2f', 'Total ',df_t,eff_t); + fprintf('\n\n') + else + fprintf('\nANALYSIS OF VARIANCE TABLE (LOW KAPPA MODE)\n\n'); + + fprintf('%s\t\t\t\t%s\t%s\t\t\t%s\n', ' ' ,'d.f.', 'CHI2', 'P-Value'); + fprintf('--------------------------------------------------------------------\n'); + fprintf('%s\t\t\t\t%u\t\t%.2f\t\t\t%.4f\n', fn{1}, df_1 , chi1, p1); + fprintf('%s\t\t\t\t%u\t\t%.2f\t\t\t%.4f\n', fn{2}, df_2 , chi2, p2); + if (inter) + fprintf('%s\t\t%u\t\t%.2f\t\t\t%.4f\n', 'Interaction', df_i , chiI, pI); + end + fprintf('--------------------------------------------------------------------\n'); + fprintf('\n\n') + + end + + + end + + function prepareOutput + + pval = [p1 p2 pI]; + + if na > 1 + if kk>2 + table = {'Source','d.f.','SS','MS','F','P-Value'; ... + fn{1}, df_1 , eff_1, ms_1, F1, p1; ... + fn{2}, df_2 , eff_2, ms_2, F2, p2; ... + 'Interaction', df_i , eff_i, ms_i, FI, pI; ... + 'Residual', df_r, eff_r, ms_r, [], []; ... + 'Total',df_t,eff_t,[],[],[]}; + else + table = {'Source','d.f.','CHI2','P-Value'; ... + fn{1}, df_1 , chi1, p1; + fn{2}, df_2 , chi2, p2; + 'Interaction', df_i , chiI, pI}; + end + end + + end +end diff --git a/functions/other/circstat-matlab-master/circ_kappa.m b/functions/other/circstat-matlab-master/circ_kappa.m new file mode 100644 index 0000000..0628126 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_kappa.m @@ -0,0 +1,58 @@ +function kappa = circ_kappa(alpha,w) +% +% kappa = circ_kappa(alpha,[w]) +% Computes an approximation to the ML estimate of the concentration +% parameter kappa of the von Mises distribution. +% +% Input: +% alpha angles in radians OR alpha is length resultant +% [w number of incidences in case of binned angle data] +% +% Output: +% kappa estimated value of kappa +% +% References: +% Statistical analysis of circular data, Fisher, equation p. 88 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + + +alpha = alpha(:); + +if nargin<2 + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) > size(w,1) + w = w'; + end +end + +N = length(alpha); + +if N>1 + R = circ_r(alpha,w); +else + R = alpha; +end + +if R < 0.53 + kappa = 2*R + R^3 + 5*R^5/6; +elseif R>=0.53 && R<0.85 + kappa = -.4 + 1.39*R + 0.43/(1-R); +else + kappa = 1/(R^3 - 4*R^2 + 3*R); +end + +if N<15 && N>1 + if kappa < 2 + kappa = max(kappa-2*(N*kappa)^-1,0); + else + kappa = (N-1)^3*kappa/(N^3+N); + end +end +end diff --git a/functions/other/circstat-matlab-master/circ_ktest.m b/functions/other/circstat-matlab-master/circ_ktest.m new file mode 100644 index 0000000..fc5b5fd --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_ktest.m @@ -0,0 +1,54 @@ +function [pval, f] = circ_ktest(alpha1, alpha2) +% [pval, f] = circ_ktest(alpha1, alpha2) +% +% A parametric two-sample test to determine whether two concentration +% parameters are different. +% +% H0: The two concentration parameters are equal. +% HA: The two concentration parameters are different. +% +% Input: +% alpha1 fist sample (in radians) +% alpha2 second sample (in radians) +% +% Output: +% pval p-value that samples have different concentrations +% f f-statistic calculated +% +% Assumptions: both samples are drawn from von Mises type distributions +% and their joint resultant vector length should be > .7 +% +% References: +% Batschelet, 1980, section 6.9, pg 122-124 +% +% Circular Statistics Toolbox for Matlab + +% By Marc J. Velasco, 2009 +% velasco@ccs.fau.edu + +alpha1 = alpha1(:); +alpha2 = alpha2(:); + +n1 = length(alpha1); +n2 = length(alpha2); + +R1 = n1*circ_r(alpha1); +R2 = n2*circ_r(alpha2); + +% make sure that rbar > .7 +rbar = (R1+R2)/(n1+n2); + +if rbar < .7 + warning('CIRCSTAT:circ_ktest:vectorTooShort', ... + 'Resultant vector length should be > 0.7') %#ok +end + +% calculate test statistic +f = ((n2-1)*(n1-R1))/((n1-1)*(n2-R2)); +if f > 1 + pval = 2*(1-fcdf(f, n1, n2)); +else + f = 1/f; + pval = 2*(1-fcdf(f, n2, n1)); +end +end diff --git a/functions/other/circstat-matlab-master/circ_kuipertest.m b/functions/other/circstat-matlab-master/circ_kuipertest.m new file mode 100644 index 0000000..4b6cac9 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_kuipertest.m @@ -0,0 +1,113 @@ +function [pval, k, K] = circ_kuipertest(alpha1, alpha2, res, vis_on) + +% [pval, k, K] = circ_kuipertest(alpha1, alpha2, res, vis_on) +% +% The Kuiper two-sample test tests whether the two samples differ +% significantly.The difference can be in any property, such as mean +% location and dispersion. It is a circular analogue of the +% Kolmogorov-Smirnov test. +% +% H0: The two distributions are identical. +% HA: The two distributions are different. +% +% Input: +% alpha1 fist sample (in radians) +% alpha2 second sample (in radians) +% res resolution at which the cdf is evaluated +% vis_on display graph +% +% Output: +% pval p-value; the smallest of .10, .05, .02, .01, .005, .002, +% .001, for which the test statistic is still higher +% than the respective critical value. this is due to +% the use of tabulated values. if p>.1, pval is set to 1. +% k test statistic +% K critical value +% +% References: +% Batschelet, 1980, p. 112 +% +% Circular Statistics Toolbox for Matlab + +% Update 2012 +% By Marc J. Velasco and Philipp Berens, 2009 +% velasco@ccs.fau.edu + + +if nargin < 3 + res = 100; +end +if nargin < 4 + vis_on = 0; +end + +n = length(alpha1(:)); +m = length(alpha2(:)); + +% create cdfs of both samples +[phis1, cdf1, phiplot1, cdfplot1] = circ_samplecdf(alpha1, res); +[foo, cdf2, phiplot2, cdfplot2] = circ_samplecdf(alpha2, res); %#ok + +% maximal difference between sample cdfs +[dplus, gdpi] = max([0 cdf1-cdf2]); +[dminus, gdmi] = max([0 cdf2-cdf1]); + +% calculate k-statistic +k = n * m * (dplus + dminus); + +% find p-value +[pval, K] = kuiperlookup(min(n,m),k/sqrt(n*m*(n+m))); +K = K * sqrt(n*m*(n+m)); + + +% visualize +if vis_on + figure + plot(phiplot1, cdfplot1, 'b', phiplot2, cdfplot2, 'r'); + hold on + plot([phis1(gdpi-1), phis1(gdpi-1)], [cdf1(gdpi-1) cdf2(gdpi-1)], 'o:g'); + plot([phis1(gdmi-1), phis1(gdmi-1)], [cdf1(gdmi-1) cdf2(gdmi-1)], 'o:g'); + hold off + set(gca, 'XLim', [0, 2*pi]); + set(gca, 'YLim', [0, 1.1]); + xlabel('Circular Location') + ylabel('Sample CDF') + title('CircStat: Kuiper test') + h = legend('Sample 1', 'Sample 2', 'Location', 'Southeast'); + set(h,'box','off') + set(gca, 'XTick', pi*(0:.25:2)) + set(gca, 'XTickLabel', {'0', '', '', '', 'pi', '', '', '', '2pi'}) +end + + + +end + +function [p, K] = kuiperlookup(n, k) + +load kuipertable.mat; +alpha = [.10, .05, .02, .01, .005, .002, .001]; +nn = ktable(:,1); %#ok + +% find correct row of the table +[easy, row] = ismember(n, nn); +if ~easy + % find closest value if no entry is present) + row = length(nn) - sum(n + end +end + +% find minimal p-value and test-statistic +idx = find(ktable(row,2:end) 1, 1, 'first'); + if isempty(dim) + dim = 1; + end +end + +if nargin < 2 || isempty(w) + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) ~= size(alpha,2) || size(w,1) ~= size(alpha,1) + error('Input dimensions do not match'); + end +end + +% compute mean direction +R = circ_r(alpha,w,[],dim); +theta = circ_mean(alpha,w,dim); +[~, rho2] = circ_moment(alpha,w,2,true,dim); +[~, ~, mu2] = circ_moment(alpha,w,2,false,dim); + +% compute skewness +theta2 = repmat(theta, size(alpha)./size(theta)); +k = sum(w.*(cos(2*(circ_dist(alpha,theta2)))),dim)./sum(w,dim); +k0 = (rho2.*cos(circ_dist(mu2,2*theta))-R.^4)./(1-R).^2; % (formula 2.30) +end + diff --git a/functions/other/circstat-matlab-master/circ_mean.m b/functions/other/circstat-matlab-master/circ_mean.m new file mode 100644 index 0000000..5ff5a49 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_mean.m @@ -0,0 +1,61 @@ +function [mu, ul, ll] = circ_mean(alpha, w, dim) +% +% [mu ul ll] = circ_mean(alpha, w, dim) +% Computes the mean direction for circular data. +% +% Input: +% alpha sample of angles in radians +% [w weightings in case of binned angle data] +% [dim compute along this dimension, default: 1st non-singular dimension] +% +% If dim argument is specified, all other optional arguments can be +% left empty: circ_mean(alpha, [], dim) +% +% Output: +% mu mean direction +% ul upper 95% confidence limit +% ll lower 95% confidence limit +% +% PHB 7/6/2008 +% +% References: +% Statistical analysis of circular data, N. I. Fisher +% Topics in circular statistics, S. R. Jammalamadaka et al. +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if nargin < 3 + dim = find(size(alpha) > 1, 1, 'first'); + if isempty(dim) + dim = 1; + end +end + +if nargin < 2 || isempty(w) + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) ~= size(alpha,2) || size(w,1) ~= size(alpha,1) + error('Input dimensions do not match'); + end +end + +% compute weighted sum of cos and sin of angles +% r = sum(w.*exp(1i*alpha),dim); +r = nancov_circ(w,exp(1i*alpha),dim); %*size(alpha,1) + +% obtain mean by +mu = angle(r); + +% confidence limits if desired +if nargout > 1 + t = circ_confmean(alpha,0.05,w,[],dim); + ul = mu + t; + ll = mu - t; +end +end diff --git a/functions/other/circstat-matlab-master/circ_median.m b/functions/other/circstat-matlab-master/circ_median.m new file mode 100644 index 0000000..94fda4b --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_median.m @@ -0,0 +1,77 @@ +function med = circ_median(alpha,dim) +% +% med = circ_median(alpha, dim) +% Computes the median direction for circular data. +% +% Input: +% alpha sample of angles in radians +% [dim compute along this dimension, default: 1st non-singular dimension, must +% be either 1 or 2 for circ_median] +% +% Output: +% med median direction +% +% circ_median can be slow for large datasets +% +% Update 2012 +% PHB 3/19/2009 +% +% References: +% Biostatistical Analysis, J. H. Zar (26.6) +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if nargin < 2 + dim = find(size(alpha) > 1, 1, 'first'); + if isempty(dim) + dim = 1; + end +end + +M = size(alpha); +med = NaN(M(3-dim),1); +for i=1:M(3-dim) + if dim == 2 + beta = alpha(i,:)'; + elseif dim ==1 + beta = alpha(:,i); + else + error('circ_median only works along first two dimensions') + end + + beta = mod(beta,2*pi); + n = size(beta,1); + + dd = circ_dist2(beta,beta); + m1 = sum(dd>=0,1); + m2 = sum(dd<=0,1); + + dm = abs(m1-m2); + if mod(n,2)==1 + [m, idx] = min(dm); + else + m = min(dm); + idx = find(dm==m,2); + end + + if m > 1 + warning('CIRCSTAT:circ_median:tiesDetected', ... + 'Ties detected.') %#ok + end + + md = circ_mean(beta(idx)); + + if abs(circ_dist(circ_mean(beta),md)) > abs(circ_dist(circ_mean(beta),md+pi)) + md = mod(md+pi,2*pi); + end + + med(i) = md; +end + +if dim == 2 + med = med'; +end +end diff --git a/functions/other/circstat-matlab-master/circ_medtest.m b/functions/other/circstat-matlab-master/circ_medtest.m new file mode 100644 index 0000000..759bdac --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_medtest.m @@ -0,0 +1,43 @@ +function pval = circ_medtest(alpha,md) +% +% pval = circ_medtest(alpha, md) +% Tests for significance of the median. +% H0: the population has median angle md +% HA: the population has not median angle md +% +% Input: +% alpha sample of angles in radians +% md median to test for +% +% Output: +% pval p-value +% +% PHB 3/19/2009 +% +% References: +% Biostatistical Analysis, J. H. Zar, 27.4 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +if length(md)>1 + error('Median can only be a single value.') +end + +n = length(alpha); + +% compute deviations from median +d = circ_dist(alpha,md); + +n1 = sum(d<0); +n2 = sum(d>0); + +% compute p-value with binomial test +pval = sum(binopdf([0:min(n1,n2) max(n1,n2):n],n,0.5)); +end diff --git a/functions/other/circstat-matlab-master/circ_moment.m b/functions/other/circstat-matlab-master/circ_moment.m new file mode 100644 index 0000000..beb98c9 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_moment.m @@ -0,0 +1,71 @@ +function [mp, rho_p, mu_p] = circ_moment(alpha, w, p, cent, dim) + +% [mp rho_p mu_p] = circ_moment(alpha, w, p, cent, dim) +% Calculates the complex p-th centred or non-centred moment +% of the angular data in angle. +% +% Input: +% alpha sample of angles +% [w weightings in case of binned angle data] +% [p p-th moment to be computed, default is p=1] +% [cent if true, central moments are computed, default = false] +% [dim compute along this dimension, default is 1st non-singular dimension] +% +% If dim argument is specified, all other optional arguments can be +% left empty: circ_moment(alpha, [], [], [], dim) +% +% Output: +% mp complex p-th moment +% rho_p magnitude of the p-th moment +% mu_p angle of th p-th moment +% +% +% References: +% Statistical analysis of circular data, Fisher, p. 33/34 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de + +if nargin < 5 + dim = find(size(alpha) > 1, 1, 'first'); + if isempty(dim) + dim = 1; + end +end + +if nargin < 4 + cent = false; +end + +if nargin < 3 || isempty(p) + p = 1; +end + +if nargin < 2 || isempty(w) + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) ~= size(alpha,2) || size(w,1) ~= size(alpha,1) + error('Input dimensions do not match'); + end +end + + +if cent + theta = circ_mean(alpha,w,dim); + v = size(alpha)./size(theta); + alpha = circ_dist(alpha,repmat(theta,v)); +end + + +n = size(alpha,dim); +cbar = sum(cos(p*alpha).*w,dim)/n; +sbar = sum(sin(p*alpha).*w,dim)/n; +mp = cbar + 1i*sbar; + +rho_p = abs(mp); +mu_p = angle(mp); +end diff --git a/functions/other/circstat-matlab-master/circ_mtest.m b/functions/other/circstat-matlab-master/circ_mtest.m new file mode 100644 index 0000000..96b4492 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_mtest.m @@ -0,0 +1,70 @@ +function [h, mu, ul, ll] = circ_mtest(alpha, dir, xi, w, d) +% +% [h mu ul ll] = circ_mtest(alpha, dir, xi, w, d) +% One-Sample test for the mean angle. +% H0: the population has mean dir. +% HA: the population has not mean dir. +% +% Note: This is the equvivalent to a one-sample t-test with specified +% mean direction. +% +% Input: +% alpha sample of angles in radians +% dir assumed mean direction +% [xi alpha level of the test] +% [w number of incidences in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r, in radians (!)] +% +% Output: +% h 0 if H0 can not be rejected, 1 otherwise +% mu mean +% ul upper (1-xi) confidence level +% ll lower (1-xi) confidence level +% +% PHB 7/6/2008 +% +% References: +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +if nargin<3 + xi = 0.05; +end + +if nargin<4 + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) > size(w,1) + w = w'; + end + if length(alpha)~=length(w) + error('Input dimensions do not match.') + end +end + +if nargin<5 + % per default do not apply correct for binned data + d = 0; +end + +% compute ingredients +mu = circ_mean(alpha,w); +t = circ_confmean(alpha,xi,w,d); +ul = mu + t; +ll = mu - t; + +% compute test via confidence limits (example 27.3) +h = abs(circ_dist2(dir,mu)) > t; +end diff --git a/functions/other/circstat-matlab-master/circ_otest.m b/functions/other/circstat-matlab-master/circ_otest.m new file mode 100644 index 0000000..8942b42 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_otest.m @@ -0,0 +1,71 @@ +function [pval, m] = circ_otest(alpha, sz, w) +% +% [pval, m] = circ_otest(alpha,sz,w) +% Computes Omnibus or Hodges-Ajne test for non-uniformity of circular data. +% H0: the population is uniformly distributed around the circle +% HA: the population is not distributed uniformly around the circle +% +% Alternative to the Rayleigh and Rao's test. Works well for unimodal, +% bimodal or multimodal data. If requirements of the Rayleigh test are +% met, the latter is more powerful. +% +% Input: +% alpha sample of angles in radians +% [sz step size for evaluating distribution, default 1 degree +% [w number of incidences in case of binned angle data] +% +% Output: +% pval p-value +% m minimum number of samples falling in one half of the circle +% +% PHB 3/16/2009 +% +% References: +% Biostatistical Analysis, J. H. Zar +% A bivariate sign test, J. L. Hodges et al., 1955 +% A simple test for uniformity of a circular distribution, B. Ajne, 1968 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +if nargin < 2 || isempty(sz) + sz = circ_ang2rad(1); +end + +if nargin < 3 + w = ones(size(alpha)); +else + if length(alpha)~=length(w) + error('Input length does not match.') + end + w =w(:); +end + +alpha = mod(alpha,2*pi); +n = sum(w); +dg = 0:sz:pi; + +m1 = zeros(size(dg)); +m2 = zeros(size(dg)); +for i=1:length(dg) + m1(i) = sum((alpha > dg(i) & alpha < pi + dg(i)).*w); + m2(i) = n - m1(i); +end +m = min(min([m1;m2])); + +if n > 50 + % approximation by Ajne (1968) + A = pi*sqrt(n) / 2 / (n-2*m); + pval = sqrt(2*pi) / A * exp(-pi^2/8/A^2); +else + % exact formula by Hodges (1955) + % pval = 2^(1-n) * (n-2*m) * nchoosek(n,m); % revised below for numerical stability + pval = exp((1-n)*log(2) + log(n-2*m) + gammaln(n+1) - gammaln(m+1) - gammaln(n-m+1)); +end +end diff --git a/functions/other/circstat-matlab-master/circ_plot.m b/functions/other/circstat-matlab-master/circ_plot.m new file mode 100644 index 0000000..ca0a7ee --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_plot.m @@ -0,0 +1,144 @@ +function a = circ_plot(alpha, format, formats, varargin) +% +% a = circ_plot(alpha, ...) +% Plotting routines for circular data. +% +% Input: +% alpha sample of angles in radians +% [format specifies style of plot +% pretty, histogram, density, [] +% [formats standard matlab string for plot format (like '.r')] +% +% The different plotting styles take optional arguments: +% pretty: fourth argument toggles between showing mean direction +% and not showing it +% hist: fourth argument determines number of bins/bin centers +% fifth argument determines whether normalized or count +% histogram is shown +% sixth argument toggles between showing mean direction +% and not showing it +% +% All of these arguments can be left empty, i.e. set to [], so that +% the default value will be used. If additional arguments are +% supplied in the name-value style ('linewidth', 2, ...), these are +% used to change the properties of the mean resultant vector plot. +% +% Output: +% a axis handle +% +% Examples: +% alpha = randn(60,1)*.4+pi/2; +% figure +% subplot(2,2,1) +% circ_plot(alpha,'pretty','ro',true,'linewidth',2,'color','r'), +% title('pretty plot style') +% subplot(2,2,2) +% circ_plot(alpha,'hist',[],20,true,true,'linewidth',2,'color','r') +% title('hist plot style') +% subplot(2,2,3) +% circ_plot(alpha,[],'s') +% title('non-fancy plot style') +% +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens & Marc J. Velasco, 2009 +% velasco@ccs.fau.edu, berens@tuebingen.mpg.de + +if nargin < 2 || isempty(format) + format = ''; +end + + +switch format + case 'pretty' + % plot in 'pretty style' + % draws unit circle and marks points around the circle + % adds optionally the mean resultant vector + + if nargin < 3|| isempty(formats) + formats = 'o'; + end + + % convert angles to unit vectors + z = exp(1i*alpha); + + % create unit circle + zz = exp(1i*linspace(0, 2*pi, 101)); + + plot(real(z), imag(z), formats, real(zz), imag(zz), 'k', [-2 2], [0 0], 'k:', [0 0], [-2 2], 'k:'); + set(gca, 'XLim', [-1.1 1.1], 'YLim', [-1.1 1.1]) + + % plot mean directions with an overlaid arrow if desired + if nargin > 2 && ~isempty(varargin{1}) + s = varargin{1}; + else + s = true; + end + + if s + r = circ_r(alpha); + phi = circ_mean(alpha); + hold on; + zm = r*exp(1i*phi); + plot([0 real(zm)], [0, imag(zm)],varargin{2:end}) + hold off; + end + + axis square; + set(gca,'box','off') + set(gca,'xtick',[]) + set(gca,'ytick',[]) + text(1.2, 0, '0'); text(-.05, 1.2, '\pi/2'); text(-1.35, 0, '�\pi'); text(-.075, -1.2, '-\pi/2'); + + + case 'hist' + % plot in 'hist style' + % this is essentially a wrapper for the rose plot function of matlab + % adds optionally the mean resultant vector + + if nargin < 3|| isempty(formats) + formats = '-'; + end + + if nargin > 3 && ~isempty(varargin{1}) + x = varargin{1}; + else + x = 20; + end + + [t,r] = rose(alpha,x); + if nargin> 3 && varargin{2} + polar(t,2*r/sum(r),formats) + mr = max(2*r/sum(r)); + else + polar(t,r,formats) + mr = max(r); + end + + % plot mean directions with an overlaid arrow if desired + if nargin > 5 && ~isempty(varargin{3}) + s = varargin{3}; + else + s = true; + end + + if s + r = circ_r(alpha) * mr; + phi = circ_mean(alpha); + hold on; + zm = r*exp(1i*phi); + plot([0 real(zm)], [0, imag(zm)],varargin{4:end}) + hold off; + end + + + otherwise + if nargin < 3 + formats = 'o'; + end + polar(alpha, ones(size(alpha)), formats); +end + +a = gca; +end diff --git a/functions/other/circstat-matlab-master/circ_r.m b/functions/other/circstat-matlab-master/circ_r.m new file mode 100644 index 0000000..61fe18a --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_r.m @@ -0,0 +1,65 @@ +function r = circ_r(alpha, w, d, dim) +% r = circ_r(alpha, w, d, dim) +% Computes mean resultant vector length for circular data. +% +% Input: +% alpha sample of angles in radians +% [w number of incidences in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r, in radians (!)] +% [dim compute along this dimension, default: 1st non-singular dimension] +% +% If dim argument is specified, all other optional arguments can be +% left empty: circ_r(alpha, [], [], dim) +% +% Output: +% r mean resultant length +% +% PHB 7/6/2008 +% +% References: +% Statistical analysis of circular data, N.I. Fisher +% Topics in circular statistics, S.R. Jammalamadaka et al. +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if nargin < 4 + dim = find(size(alpha) > 1, 1, 'first'); + if isempty(dim) + dim = 1; + end +end + +if nargin < 2 || isempty(w) + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) ~= size(alpha,2) || size(w,1) ~= size(alpha,1) + error('Input dimensions do not match'); + end +end + +if nargin < 3 || isempty(d) + % per default do not apply correct for binned data + d = 0; +end + +% compute weighted sum of cos and sin of angles +r = sum(w.*exp(1i*alpha),dim); + +% obtain length +r = abs(r)./sum(w,dim); + +% for data with known spacing, apply correction factor to correct for bias +% in the estimation of r (see Zar, p. 601, equ. 26.16) +if d ~= 0 + c = d/2/sin(d/2); + r = c*r; +end +end diff --git a/functions/other/circstat-matlab-master/circ_rad2ang.m b/functions/other/circstat-matlab-master/circ_rad2ang.m new file mode 100644 index 0000000..d212d86 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_rad2ang.m @@ -0,0 +1,12 @@ +function alpha = circ_rad2ang(alpha) + +% alpha = circ_rad2ang(alpha) +% converts values in radians to values in degree +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +alpha = alpha / pi *180; +end diff --git a/functions/other/circstat-matlab-master/circ_raotest.m b/functions/other/circstat-matlab-master/circ_raotest.m new file mode 100644 index 0000000..3303106 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_raotest.m @@ -0,0 +1,126 @@ +function [p, U, UC] = circ_raotest(alpha) +% +% [p U UC] = circ_raotest(alpha) +% Calculates Rao's spacing test by comparing distances between points on +% a circle to those expected from a uniform distribution. +% +% H0: Data is distributed uniformly around the circle. +% H1: Data is not uniformly distributed around the circle. +% +% Alternative to the Rayleigh test and the Omnibus test. Less powerful +% than the Rayleigh test when the distribution is unimodal on a global +% scale but uniform locally. +% +% Due to the complexity of the distributioin of the test statistic, we +% resort to the tables published by +% Russell, Gerald S. and Levitin, Daniel J.(1995) +% 'An expanded table of probability values for rao's spacing test' +% Communications in Statistics - Simulation and Computation +% Therefore the reported p-value is the smallest alpha level at which the +% test would still be significant. If the test is not significant at the +% alpha=0.1 level, we return the critical value for alpha = 0.05 and p = +% 0.5. +% +% Input: +% alpha sample of angles +% +% Output: +% p smallest p-value at which test would be significant +% U computed value of the test-statistic u +% UC critical value of the test statistic at sig-level +% +% +% References: +% Batschelet, 1981, Sec 4.6 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de + +alpha = alpha(:); + +% for the purpose of the test, convert to angles +alpha = circ_rad2ang(alpha); +n = length(alpha); +alpha = sort(alpha); + +% compute test statistic +U = 0; +lambda = 360/n; +for j = 1:n-1 + ti = alpha(j+1) - alpha(j); + U = U + abs(ti - lambda); +end + +tn = (360 - alpha(n) + alpha(1)); +U = U + abs(tn-lambda); + +U = (1/2)*U; + +% get critical value from table +[p, UC] = getVal(n,U); + + + +function [p, UC] = getVal(N, U) + +% Table II from Russel and Levitin, 1995 + +alpha = [0.001, .01, .05, .10]; +table = [ 4 247.32, 221.14, 186.45, 168.02; + 5 245.19, 211.93, 183.44, 168.66; + 6 236.81, 206.79, 180.65, 166.30; + 7 229.46, 202.55, 177.83, 165.05; + 8 224.41, 198.46, 175.68, 163.56; + 9 219.52, 195.27, 173.68, 162.36; + 10 215.44, 192.37, 171.98, 161.23; + 11 211.87, 189.88, 170.45, 160.24; + 12 208.69, 187.66, 169.09, 159.33; + 13 205.87, 185.68, 167.87, 158.50; + 14 203.33, 183.90, 166.76, 157.75; + 15 201.04, 182.28, 165.75, 157.06; + 16 198.96, 180.81, 164.83, 156.43; + 17 197.05, 179.46, 163.98, 155.84; + 18 195.29, 178.22, 163.20, 155.29; + 19 193.67, 177.08, 162.47, 154.78; + 20 192.17, 176.01, 161.79, 154.31; + 21 190.78, 175.02, 161.16, 153.86; + 22 189.47, 174.10, 160.56, 153.44; + 23 188.25, 173.23, 160.01, 153.05; + 24 187.11, 172.41, 159.48, 152.68; + 25 186.03, 171.64, 158.99, 152.32; + 26 185.01, 170.92, 158.52, 151.99; + 27 184.05, 170.23, 158.07, 151.67; + 28 183.14, 169.58, 157.65, 151.37; + 29 182.28, 168.96, 157.25, 151.08; + 30 181.45, 168.38, 156.87, 150.80; + 35 177.88, 165.81, 155.19, 149.59; + 40 174.99, 163.73, 153.82, 148.60; + 45 172.58, 162.00, 152.68, 147.76; + 50 170.54, 160.53, 151.70, 147.05; + 75 163.60, 155.49, 148.34, 144.56; + 100 159.45, 152.46, 146.29, 143.03; + 150 154.51, 148.84, 143.83, 141.18; + 200 151.56, 146.67, 142.35, 140.06; + 300 148.06, 144.09, 140.57, 138.71; + 400 145.96, 142.54, 139.50, 137.89; + 500 144.54, 141.48, 138.77, 137.33; + 600 143.48, 140.70, 138.23, 136.91; + 700 142.66, 140.09, 137.80, 136.59; + 800 142.00, 139.60, 137.46, 136.33; + 900 141.45, 139.19, 137.18, 136.11; + 1000 140.99, 138.84, 136.94, 135.92 ]; + +ridx = find(table(:,1)>=N,1); +cidx = find(table(ridx,2:end) size(alpha,1) + alpha = alpha'; +end + +if nargin < 2 + r = circ_r(alpha); + n = length(alpha); +else + if length(alpha)~=length(w) + error('Input dimensions do not match.') + end + if nargin < 3 + d = 0; + end + r = circ_r(alpha,w(:),d); + n = sum(w); +end + +% compute Rayleigh's R (equ. 27.1) +R = n*r; + +% compute Rayleigh's z (equ. 27.2) +z = R^2 / n; + +% compute p value using approxation in Zar, p. 617 +pval = exp(sqrt(1+4*n+4*(n^2-R^2))-(1+2*n)); + +% outdated version: +% compute the p value using an approximation from Fisher, p. 70 +% pval = exp(-z); +% if n < 50 +% pval = pval * (1 + (2*z - z^2) / (4*n) - ... +% (24*z - 132*z^2 + 76*z^3 - 9*z^4) / (288*n^2)); +% end + +end diff --git a/functions/other/circstat-matlab-master/circ_samplecdf.m b/functions/other/circstat-matlab-master/circ_samplecdf.m new file mode 100644 index 0000000..5ffc54c --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_samplecdf.m @@ -0,0 +1,70 @@ +function [phis, cdf, phiplot, cdfplot] = circ_samplecdf(thetas, resolution) +% +% [phis, cdf, phiplot, cdfplot] = circ_samplecdf(thetas, resolution) +% +% Helper function for circ_kuipertest. +% Evaluates CDF of sample in thetas. +% +% Input: +% thetas sample (in radians) +% resolution resolution at which the cdf is evaluated +% +% Output: +% phis angles at which CDF is evaluated +% cdf CDF values at these angles +% phiplot as phi, for plotting +% cdfplot as cdf, for plotting +% +% +% Circular Statistics Toolbox for Matlab + +% By Marc J. Velasco, 2009 +% velasco@ccs.fau.edu + +if nargin < 2 + resolution = 100; +end + +phis = 0; +cdf = zeros(1, length(phis)); + +phis = linspace(0,2*pi,resolution+1); +phis = phis(1:end-1); + +% ensure all points in thetas are on interval [0, 2pi) +x = thetas(thetas<0); +thetas(thetas<0) = (2*pi-abs(x)); + +% compute cdf +thetas = sort(thetas); +dprob = 1/length(thetas); %incremental change in probability +cumprob = 0; %cumultive probability so far + +% for a little bit, we'll add on 2pi to the end of phis +phis = [phis 2*pi]; + +for j=1:resolution + minang = phis(j); + maxang = phis(j+1); + currcount = sum(thetas >= minang & thetas < maxang); + cdf(j) = cumprob + dprob*currcount; + cumprob = cdf(j); +end + +phis = phis(1:end-1); + +% for each point in x, duplicate it with the preceding value in y +phis2 = phis; +cdf2 = [0 cdf(1:end-1)]; + +cdfplottable = []; +phisplottable = []; + +for j=1:length(phis) + phisplottable = [phisplottable phis(j) phis2(j)]; %#ok + cdfplottable = [cdfplottable cdf2(j) cdf(j)]; %#ok +end + +phiplot = [phisplottable 2*pi]; +cdfplot = [cdfplottable 1]; +end diff --git a/functions/other/circstat-matlab-master/circ_skewness.m b/functions/other/circstat-matlab-master/circ_skewness.m new file mode 100644 index 0000000..e7ec085 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_skewness.m @@ -0,0 +1,54 @@ +function [b, b0] = circ_skewness(alpha, w, dim) +% +% [b b0] = circ_skewness(alpha,w,dim) +% Calculates a measure of angular skewness. +% +% Input: +% alpha sample of angles +% [w weightings in case of binned angle data] +% [dim statistic computed along this dimension, default: 1st non-singular dimension] +% +% If dim argument is specified, all other optional arguments can be +% left empty: circ_skewness(alpha, [], dim) +% +% Output: +% b skewness (from Pewsey) +% b0 alternative skewness measure (from Fisher) +% +% References: +% Pewsey, Metrika, 2004 +% Statistical analysis of circular data, Fisher, p. 34 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de + +if nargin < 3 + dim = find(size(alpha) > 1, 1, 'first'); + if isempty(dim) + dim = 1; + end +end + +if nargin < 2 || isempty(w) + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) ~= size(alpha,2) || size(w,1) ~= size(alpha,1) + error('Input dimensions do not match'); + end +end + + +% compute neccessary values +R = circ_r(alpha,w,[],dim); +theta = circ_mean(alpha,w,dim); +[~, rho2 mu2] = circ_moment(alpha,w,2,false,dim); + +% compute skewness +theta2 = repmat(theta, size(alpha)./size(theta)); +b = sum(w.*(sin(2*(circ_dist(alpha,theta2)))),dim)./sum(w,dim); +b0 = rho2.*sin(circ_dist(mu2,2*theta))./(1-R).^(3/2); % (formula 2.29) +end diff --git a/functions/other/circstat-matlab-master/circ_stats.m b/functions/other/circstat-matlab-master/circ_stats.m new file mode 100644 index 0000000..44a2250 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_stats.m @@ -0,0 +1,63 @@ +function stats = circ_stats(alpha, w, d) +% +% stats = circ_stats(alpha, w, d) +% Computes descriptive statistics for circular data. +% +% Input: +% alpha sample of angles in radians +% [w weightings in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r] +% +% Output: +% stats structure containing descriptive statistics +% +% References: +% Statistical analysis of circular data, N. I. Fisher +% Topics in circular statistics, S. R. Jammalamadaka et al. +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de + +alpha = alpha(:); +if nargin<2 + w = ones(size(alpha)); +end + +if nargin < 3 + d = 0; +end + +% mean +stats.mean = circ_mean(alpha,w); + +% median +if sum(w)==length(alpha) + if numel(alpha) > 1000 + idx = randperm(numel(alpha)); + idx = idx(1:1000); + else + idx = 1:numel(alpha); + end + stats.median = circ_median(alpha(idx)); +else + stats.median = NaN; +end + +% variance +stats.var = circ_var(alpha,w,d); + +% standard deviation +[stats.std, stats.std0] = circ_std(alpha,w,d); + + +% skewness +[stats.skewness, stats.skewness0] = circ_skewness(alpha,w); + +% kurtosis +[stats.kurtosis, stats.kurtosis0] = circ_kurtosis(alpha,w); +end diff --git a/functions/other/circstat-matlab-master/circ_std.m b/functions/other/circstat-matlab-master/circ_std.m new file mode 100644 index 0000000..802829b --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_std.m @@ -0,0 +1,58 @@ +function [s, s0] = circ_std(alpha, w, d, dim) +% [s, s0] = circ_std(alpha, w, d, dim) +% Computes circular standard deviation for circular data +% (equ. 26.20, Zar). +% +% Input: +% alpha sample of angles in radians +% [w weightings in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r] +% [dim compute along this dimension, default: 1st non-singular dimension] +% +% If dim argument is specified, all other optional arguments can be +% left empty: circ_std(alpha, [], [], dim) +% +% Output: +% s angular deviation +% s0 circular standard deviation +% +% PHB 6/7/2008 +% +% References: +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if nargin < 4 + dim = find(size(alpha) > 1, 1, 'first'); + if isempty(dim) + dim = 1; + end +end + +if nargin < 3 || isempty(d) + % per default do not apply correct for binned data + d = 0; +end + +if nargin < 2 || isempty(w) + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) ~= size(alpha,2) || size(w,1) ~= size(alpha,1) + error('Input dimensions do not match'); + end +end + +% compute mean resultant vector length +r = circ_r(alpha,w,d,dim); + +s = sqrt(2*(1-r)); % 26.20 +s0 = sqrt(-2*log(r)); % 26.21 +end diff --git a/functions/other/circstat-matlab-master/circ_symtest.m b/functions/other/circstat-matlab-master/circ_symtest.m new file mode 100644 index 0000000..f205a71 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_symtest.m @@ -0,0 +1,37 @@ +function pval = circ_symtest(alpha) +% +% pval = circ_symtest(alpha) +% Tests for symmetry about the median. +% H0: the population is symmetrical around the median +% HA: the population is not symmetrical around the median +% +% +% Input: +% alpha sample of angles in radians +% +% Output: +% pval p-value +% +% PHB 3/19/2009 +% +% References: +% Biostatistical Analysis, J. H. Zar, 27.4 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +% compute median +md = circ_median(alpha); + +% compute deviations from median +d = circ_dist(alpha,md); + +% compute wilcoxon sign rank test +pval = signrank(d); +end diff --git a/functions/other/circstat-matlab-master/circ_var.m b/functions/other/circstat-matlab-master/circ_var.m new file mode 100644 index 0000000..9bd8f10 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_var.m @@ -0,0 +1,61 @@ +function [S, s] = circ_var(alpha, w, d, dim) +% [S, s] = circ_var(alpha, w, d, dim) +% Computes circular variance for circular data +% (equ. 26.17/18, Zar). +% +% Input: +% alpha sample of angles in radians +% [w number of incidences in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r] +% [dim compute along this dimension, default: 1st non-singular dimension] +% +% If dim argument is specified, all other optional arguments can be +% left empty: circ_var(alpha, [], [], dim) +% +% Output: +% S circular variance 1-r +% s angular variance 2*(1-r) +% +% PHB 6/7/2008 +% +% References: +% Statistical analysis of circular data, N.I. Fisher +% Topics in circular statistics, S.R. Jammalamadaka et al. +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if nargin < 4 + dim = find(size(alpha) > 1, 1, 'first'); + if isempty(dim) + dim = 1; + end +end + +if nargin < 3 || isempty(d) + % per default do not apply correct for binned data + d = 0; +end + +if nargin < 2 || isempty(w) + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) ~= size(alpha,2) || size(w,1) ~= size(alpha,1) + error('Input dimensions do not match'); + end +end + +% compute mean resultant vector length +r = circ_r(alpha,w,d,dim); + +% apply transformation to var +S = 1 - r; +s = 2 * S; +end diff --git a/functions/other/circstat-matlab-master/circ_vmpar.m b/functions/other/circstat-matlab-master/circ_vmpar.m new file mode 100644 index 0000000..b79c858 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_vmpar.m @@ -0,0 +1,39 @@ +function [thetahat, kappa] = circ_vmpar(alpha,w,d) +% +% [thetahat, kappa] = circ_vmpar(alpha, w, d) +% Estimate the parameters of a von Mises distribution. +% +% Input: +% alpha sample of angles in radians +% [w number of incidences in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r, in radians (!)] +% +% Output: +% thetahat preferred direction +% kappa concentration parameter +% +% PHB 3/23/2009 +% +% References: +% Statistical analysis of circular data, N.I. Fisher +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de + +alpha = alpha(:); +if nargin < 2 + w = ones(size(alpha)); +end +if nargin < 3 + d = 0; +end + +r = circ_r(alpha,w,d); +kappa = circ_kappa(r); + +thetahat = circ_mean(alpha,w); +end diff --git a/functions/other/circstat-matlab-master/circ_vmpdf.m b/functions/other/circstat-matlab-master/circ_vmpdf.m new file mode 100644 index 0000000..11cc2ff --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_vmpdf.m @@ -0,0 +1,46 @@ +function [p, alpha] = circ_vmpdf(alpha, thetahat, kappa) +% +% [p alpha] = circ_vmpdf(alpha, thetahat, kappa) +% Computes the circular von Mises pdf with preferred direction thetahat +% and concentration kappa at each of the angles in alpha +% +% The vmpdf is given by f(phi) = +% (1/(2pi*I0(kappa))*exp(kappa*cos(phi-thetahat) +% +% Input: +% alpha angles to evaluate pdf at, if empty alphas are chosen to +% 100 uniformly spaced points around the circle +% [thetahat preferred direction, default is 0] +% [kappa concentration parameter, default is 1] +% +% Output: +% p von Mises pdf evaluated at alpha +% alpha angles at which pdf was evaluated +% +% +% References: +% Statistical analysis of circular data, Fisher +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens and Marc J. Velasco, 2009 +% velasco@ccs.fau.edu + +% if no angles are supplied, 100 evenly spaced points around the circle are +% chosen +if nargin < 1 || isempty(alpha) + alpha = linspace(0, 2*pi, 101)'; + alpha = alpha(1:end-1); +end +if nargin < 3 + kappa = 1; +end +if nargin < 2 + thetahat = 0; +end + +alpha = alpha(:); + +% evaluate pdf +p = exp( kappa*(cos(alpha-thetahat)-1) ) / (2*pi*besseli(0,kappa,1)); +end diff --git a/functions/other/circstat-matlab-master/circ_vmrnd.m b/functions/other/circstat-matlab-master/circ_vmrnd.m new file mode 100644 index 0000000..00285bc --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_vmrnd.m @@ -0,0 +1,82 @@ +function alpha = circ_vmrnd(theta, kappa, n) +% +% alpha = circ_vmrnd(theta, kappa, n) +% Simulates n random angles from a von Mises distribution, with preferred +% direction theta and concentration parameter kappa. +% +% Input: +% [theta preferred direction, default is 0] +% [kappa width, default is 1] +% [n number of samples, default is 10] +% +% If n is a vector with two entries (e.g. [2 10]), the function creates +% a matrix output with the respective dimensionality. +% +% Output: +% alpha samples from von Mises distribution +% +% +% References: +% Statistical analysis of circular data, Fisher, sec. 3.3.6, p. 49 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens and Marc J. Velasco, 2009 +% velasco@ccs.fau.edu + + +% default parameter +if nargin < 3 + n = 10; +end + +if nargin < 2 + kappa = 1; +end + +if nargin < 1 + theta = 0; +end + +if numel(n) > 2 + error('n must be a scalar or two-entry vector!') +elseif numel(n) == 2 + m = n; + n = n(1) * n(2); +end + +% if kappa is small, treat as uniform distribution +if kappa < 1e-6 + alpha = 2*pi*rand(n,1)-pi; + return +end + +% other cases +a = 1 + sqrt((1+4*kappa.^2)); +b = (a - sqrt(2*a))/(2*kappa); +r = (1 + b^2)/(2*b); + +alpha = zeros(n,1); +for j = 1:n + while true + u = rand(3,1); + + z = cos(pi*u(1)); + f = (1+r*z)/(r+z); + c = kappa*(r-f); + + if u(2) < c * (2-c) || ~(log(c)-log(u(2)) + 1 -c < 0) + break + end + + + end + + alpha(j) = theta + sign(u(3) - 0.5) * acos(f); + alpha(j) = angle(exp(1i*alpha(j))); +end + +if exist('m','var') + alpha = reshape(alpha,m(1),m(2)); +end +end diff --git a/functions/other/circstat-matlab-master/circ_vtest.m b/functions/other/circstat-matlab-master/circ_vtest.m new file mode 100644 index 0000000..28ccaa2 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_vtest.m @@ -0,0 +1,78 @@ +function [pval, v] = circ_vtest(alpha, dir, w, d) +% +% [pval, v] = circ_vtest(alpha, dir, w, d) +% Computes V test for non-uniformity of circular data with a specified +% mean direction dir. +% H0: the population is uniformly distributed around the circle +% HA: the population is not distributed uniformly around the circle but +% has a mean of dir. +% +% Note: Not rejecting H0 may mean that the population is uniformly +% distributed around the circle OR that it has a mode but that this mode +% is not centered at dir. +% +% The V test has more power than the Rayleigh test and is preferred if +% there is reason to believe in a specific mean direction. +% +% Input: +% alpha sample of angles in radians +% dir suspected mean direction +% [w number of incidences in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r, in radians (!)] +% +% Output: +% pval p-value of V test +% v value of the V statistic +% +% PHB 7/6/2008 +% +% References: +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + + +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +if nargin<3 + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) > size(w,1) + w = w'; + end + if length(alpha)~=length(w) + error('Input dimensions do not match.') + end +end + +if nargin<4 + % per default do not apply correct for binned data + d = 0; +end + +% compute some ingredients +r = circ_r(alpha,w,d); +mu = circ_mean(alpha,w); +n = sum(w); + +% compute Rayleigh's R (equ. 27.1) +R = n * r; + +% compute the V statistic (equ. 27.5) +v = R * cos(mu-dir); + +% compute u (equ. 27.6) +u = v * sqrt(2/n); + +% compute p-value from one tailed normal approximation +pval = 1 - normcdf(u); +end diff --git a/functions/other/circstat-matlab-master/circ_wwtest.m b/functions/other/circstat-matlab-master/circ_wwtest.m new file mode 100644 index 0000000..1127771 --- /dev/null +++ b/functions/other/circstat-matlab-master/circ_wwtest.m @@ -0,0 +1,162 @@ +function [pval, table] = circ_wwtest(varargin) +% +% [pval, table] = circ_wwtest(alpha, idx, [w]) +% [pval, table] = circ_wwtest(alpha1, alpha2, [w1, w2]) +% Parametric Watson-Williams multi-sample test for equal means. Can be +% used as a one-way ANOVA test for circular data. +% +% H0: the s populations have equal means +% HA: the s populations have unequal means +% +% Note: +% Use with binned data is only advisable if binning is finer than 10 deg. +% In this case, alpha is assumed to correspond +% to bin centers. +% +% The Watson-Williams two-sample test assumes underlying von-Mises +% distributrions. All groups are assumed to have a common concentration +% parameter k. +% +% Input: +% alpha angles in radians +% idx indicates which population the respective angle in alpha +% comes from, 1:s +% [w number of incidences in case of binned angle data] +% +% Output: +% pval p-value of the Watson-Williams multi-sample test. Discard H0 if +% pval is small. +% table cell array containg the ANOVA table +% +% PHB 3/19/2009 +% +% References: +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% Update 2012 +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +[alpha, idx, w] = processInput(varargin{:}); + +% number of groups +u = unique(idx); +s = length(u); + +% number of samples +n = sum(w); + +% compute relevant quantitites +pn = zeros(s,1); pr = pn; +for t=1:s + pidx = idx == u(t); + pn(t) = sum(pidx.*w); + pr(t) = circ_r(alpha(pidx),w(pidx)); +end + +r = circ_r(alpha,w); +rw = sum(pn.*pr)/n; + +% make sure assumptions are satisfied +checkAssumption(rw,mean(pn)) + +% test statistic +kk = circ_kappa(rw); +beta = 1+3/(8*kk); % correction factor +A = sum(pr.*pn) - r*n; +B = n - sum(pr.*pn); + +F = beta * (n-s) * A / (s-1) / B; +pval = 1 - fcdf(F,s-1,n-s); + +na = nargout; +if na < 2 + printTable; +end +prepareOutput; + + + function printTable + + fprintf('\nANALYSIS OF VARIANCE TABLE (WATSON-WILLIAMS TEST)\n\n'); + fprintf('%s\t\t\t\t%s\t%s\t\t%s\t\t%s\t\t\t%s\n', ' ' ,'d.f.', 'SS', 'MS', 'F', 'P-Value'); + fprintf('--------------------------------------------------------------------\n'); + fprintf('%s\t\t\t%u\t\t%.2f\t%.2f\t%.2f\t\t%.4f\n', 'Columns', s-1 , A, A/(s-1), F, pval); + fprintf('%s\t\t%u\t\t%.2f\t%.2f\n', 'Residual ', n-s, B, B/(n-s)); + fprintf('--------------------------------------------------------------------\n'); + fprintf('%s\t\t%u\t\t%.2f', 'Total ',n-1,A+B); + fprintf('\n\n') + + end + + function prepareOutput + + if na > 1 + table = {'Source','d.f.','SS','MS','F','P-Value'; ... + 'Columns', s-1 , A, A/(s-1), F, pval; ... + 'Residual ', n-s, B, B/(n-s), [], []; ... + 'Total',n-1,A+B,[],[],[]}; + end + end +end + + + +function checkAssumption(rw,n) + + if n >= 11 && rw<.45 + warning('CIRCSTAT:circ_wwtest:vectorTooShort', ... + 'Test not applicable. Average resultant vector length < 0.45.') %#ok + elseif n<11 && n>=7 && rw<.5 + warning('CIRCSTAT:circ_wwtest:sampleSize6x11AndVectorTooShort', ... + 'Test not applicable. Average number of samples per population 6 < x < 11 and average resultant vector length < 0.5.') %#ok + elseif n>=5 && n<7 && rw<.55 + warning('CIRCSTAT:circ_wwtest:sampleSize4x7AndVectorTooShort', ... + 'Test not applicable. Average number of samples per population 4 < x < 7 and average resultant vector length < 0.55.') %#ok + elseif n < 5 + warning('CIRCSTAT:circ_wwtest:sampleSizeTooSmall', ... + 'Test not applicable. Average number of samples per population < 5.') %#ok + end + +end + + +function [alpha, idx, w] = processInput(varargin) + + if nargin == 4 + alpha1 = varargin{1}(:); + alpha2 = varargin{2}(:); + w1 = varargin{3}(:); + w2 = varargin{4}(:); + alpha = [alpha1; alpha2]; + idx = [ones(size(alpha1)); ones(size(alpha2))]; + w = [w1; w2]; + elseif nargin==2 && sum(abs(round(varargin{2})-varargin{2}))>1e-5 + alpha1 = varargin{1}(:); + alpha2 = varargin{2}(:); + alpha = [alpha1; alpha2]; + idx = [ones(size(alpha1)); 2*ones(size(alpha2))]; + w = ones(size(alpha)); + elseif nargin==2 + alpha = varargin{1}(:); + idx = varargin{2}(:); + if ~(size(idx,1)==size(alpha,1)) + error('Input dimensions do not match.') + end + w = ones(size(alpha)); + elseif nargin==3 + alpha = varargin{1}(:); + idx = varargin{2}(:); + w = varargin{3}(:); + if ~(size(idx,1)==size(alpha,1)) + error('Input dimensions do not match.') + end + if ~(size(w,1)==size(alpha,1)) + error('Input dimensions do not match.') + end + else + error('Invalid use of circ_wwtest. Type help circ_wwtest.') + end +end diff --git a/functions/other/circstat-matlab-master/kuipertable.mat b/functions/other/circstat-matlab-master/kuipertable.mat new file mode 100644 index 0000000..9d58897 Binary files /dev/null and b/functions/other/circstat-matlab-master/kuipertable.mat differ diff --git a/functions/other/circstat-matlab-master/readme.txt b/functions/other/circstat-matlab-master/readme.txt new file mode 100644 index 0000000..fe194bc --- /dev/null +++ b/functions/other/circstat-matlab-master/readme.txt @@ -0,0 +1,83 @@ +CircStat for Matlab +======================= + +Toolbox for circular statistics with Matlab. + +Authors: Philipp Berens & Marc J. Velasco +Email: berens@tuebingen.mpg.de +Homepage: http://www.kyb.tuebingen.mpg.de/~berens/circStat.html + +Contributors: +Tal Krasovsky + +Reference: +P. Berens, CircStat: A Matlab Toolbox for Circular Statistics, Journal of Statistical Software, Volume 31, Issue 10, 2009 +http://www.jstatsoft.org/v31/i10 + +Please cite this paper when the provided code is used. See licensing terms for details. + +Contents: +circ_r Resultant vector length +circ_mean Mean direction of a sample of circular data +circ_axial Mean direction for axial data +circ_median Median direction of a sample of circular data +circ_std Dispersion around the mean direction (std, mardia) +circ_var Circular variance +circ_skewness Circular skewness +circ_kurtosis Circular kurtosis +circ_moment Circular p-th moment +circ_dist Distances around a circle +circ_dist2 Pairwise distances around a circle +circ_confmean Confidence intervals for mean direction +circ_stats Summary statistics + +circ_rtest Rayleigh's test for nonuniformity +circ_otest Hodges-Ajne test (omnibus test) for nonuniformity +circ_raotest Rao's spacing test for nonuniformity +circ_vtest V-Test for nonuniformity with known mean direction +circ_medtest Test for median angle +circ_mtest One-sample test for specified mean direction +circ_wwtest Multi-sample test for equal means, one-factor ANOVA +circ_hktest Two-factor ANOVA +circ_ktest Test for equal concentration parameter +circ_symtest Test for symmetry around median angle +circ_kuipertest Test whether two distributions are identical (like KS test) + + +circ_corrcc Circular-circular correlation coefficient +circ_corrcl Circular-linear correlation coefficient + +circ_kappa Compute concentration parameter of a vm distribution + +circ_plot Visualization for circular data +circ_clust Simple clustering for circular data +circ_samplecdf Evaluate CDF of a sample of angles + +rad2ang Convert radian to angular values +ang2rad Convert angular to radian values + +All functions take arguments in radians (expect for ang2rad). For a detailed description of arguments and outputs consult the help text in the files. + +Since 2010, most functions for descriptive statistics can be used in Matlab style matrix computations. As a last argument, add the dimension along which you want to average. This changes the behavior slightly from previous relaeses, in that input is not reshaped anymore into vector format. Per default, all computations are performed columnwise (along dimension 1). If you prefer to use the old functions, for now they are contained in the subdirectory 'old'. + +References: +- E. Batschelet, Circular Statistics in Biology, Academic Press, 1981 +- N.I. Fisher, Statistical analysis of circular data, Cambridge University Press, 1996 +- S.R. Jammalamadaka et al., Topics in circular statistics, World Scientific, 2001 +- J.H. Zar, Biostatistical Analysis, Prentice Hall, 1999 + + +The implementation follows in most cases 'Biostatistical Analysis' and all referenced equations and tables are taken from this book, if not otherwise noted. In some cases, the other books were preferred for implementation was more straightforward for solutions presented there. + +If you have suggestions, bugs or feature requests or want to contribute code, please email us. + +Disclaimer: +All functions in this toolbox were implemented with care and tested on the examples presented in 'Biostatistical Analysis' were possible. Nevertheless, they may contain errors or bugs, which may affect the outcome of your analysis. We do not take responsibility for any harm coming from using this toolbox, neither if it is caused by errors in the software nor if it is caused by its improper application. Please email us any bugs you find. + +By Philipp Berens and Marc J. Velasco, 2009 +berens@tuebingen.mpg.de , velasco@ccs.fau.edu - www.kyb.mpg.de/~berens/circStat.html +Distributed under Open Source BSD License + + + + diff --git a/functions/other/circstat-matlab-master/todo.txt.txt b/functions/other/circstat-matlab-master/todo.txt.txt new file mode 100644 index 0000000..43ea923 --- /dev/null +++ b/functions/other/circstat-matlab-master/todo.txt.txt @@ -0,0 +1,10 @@ +Um, what happened to my comment? What I wrote was that an typo error appears to have been introduced in circ_kuipertest.m in the advance to version 2011f. In 2010e, line 48 of the file reads: +[phis2 cdf2 phiplot2 cdfplot2] = circ_samplecdf(alpha2, res); + +and in version 2011f, that line reads: +[~, cdf2 phiplot2 cdfplot2] = circ_samplecdf(alpha2, res); + +and matlab complains of incorrect statement or expression. + + +------------------- diff --git a/functions/other/coordtom.m b/functions/other/coordtom.m new file mode 100644 index 0000000..6769d4f --- /dev/null +++ b/functions/other/coordtom.m @@ -0,0 +1,49 @@ +function [d]=coordtom(latlon1,latlon2) +% format: d=coordtom(coordinate pair 1,coordinate pair 12) +% +%Calculates the distance between two lat-long coordinates using the +%haversine formula. +% +%Based on function originally written by M Sohrabinia on mathworks +%(https://www.mathworks.com/matlabcentral/fileexchange/38812-latlon-distance) +% +% +% +% +% +%-------------------------------------------------------------------------- + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +radius=6365; +lat1=latlon1(1)*pi/180; +lat2=latlon2(1)*pi/180; +lon1=latlon1(2)*pi/180; +lon2=latlon2(2)*pi/180; +deltaLat=lat2-lat1; +deltaLon=lon2-lon1; +a=sin((deltaLat)/2)^2 + cos(lat1)*cos(lat2) * sin(deltaLon/2)^2; +c=2*atan2(sqrt(a),sqrt(1-a)); +d=radius*c*1000; %Haversine distance +end \ No newline at end of file diff --git a/functions/other/filtall.m b/functions/other/filtall.m new file mode 100644 index 0000000..1a519c3 --- /dev/null +++ b/functions/other/filtall.m @@ -0,0 +1,325 @@ +function [images, images_stack]=filtall(images,inputs) +% %% Take newly created velocity maps and filter based upon entire time series +% % +% %Aim here is to use the information from the entire dataset to filter +% %individual velocity maps- including the knowledge that glacier velocity +% %will be smoothly varying through time (no jumps) and will only vary at a +% %relatively slow rate in general. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + +%% calculate velocity statistics + +%Initialize +meta_dum = 0; +array_pos = 0; +emptycount_inner = 0; +emptycount_outer = 0; +number_in_range = 0; +number_with_values = (size(images,2)-6)/2; + +%loop through all images +for time_loop = 1:number_with_values + position1 = 6+time_loop*2; + for inner_loop = 2:inputs.numimages-time_loop + if ~isempty(images{inner_loop,position1}) + number_in_range = number_in_range + 1; + end + end +end + +%Create matrix to store all velocities and fd +full_v = NaN(number_in_range,inputs.sizevel(1)*inputs.sizevel(2)+2); +full_fd = NaN(number_in_range,inputs.sizevel(1)*inputs.sizevel(2)+2); + +%loop through all +for time_loop = 1:number_with_values + position1 = time_loop + 6 + array_pos; + position2 = time_loop + 7 + array_pos; + for inner_loop = 2:inputs.numimages-time_loop + if ~isempty(images{inner_loop,position1}) + %calculate time interval + time_gap = (images{inner_loop+time_loop,5}-images{inner_loop,5}); + % Here calculates a median date for the interval that we will use + date_current = round(images{inner_loop+time_loop,4}-(time_gap/2)); + full_v(inner_loop+meta_dum-1-emptycount_inner-emptycount_outer,1)= date_current; + full_fd(inner_loop+meta_dum-1-emptycount_inner-emptycount_outer,1)= date_current; + + %Linearize each velocity map + lin_v = reshape(images{inner_loop,position1},[1 inputs.sizevel(1)*inputs.sizevel(2)]); + full_v(inner_loop+meta_dum-1-emptycount_inner-emptycount_outer,3:inputs.sizevel(1)*inputs.sizevel(2)+2)= lin_v; + + %Linearize each flow direction map + lin_fd = reshape(images{inner_loop,position2},[1 inputs.sizevel(1)*inputs.sizevel(2)]); + lin_fd(lin_fd==0)=NaN; + full_fd(inner_loop+meta_dum-1-emptycount_inner-emptycount_outer,3:inputs.sizevel(1)*inputs.sizevel(2)+2)= lin_fd; + else + emptycount_inner = emptycount_inner + 1; + end + end + +emptycount_outer = emptycount_outer + emptycount_inner; +emptycount_inner = 0; +meta_dum = meta_dum + inputs.numimages-time_loop-1; +array_pos = array_pos + 1; +end + +%Create a column with sequential numbers in order for the initial order to +%be recovered (we are going to sort by date to filter). Add to second +%column so that sortrows function can sort by date (looks at first column). +numbers_order=(1:size(full_v,1))'; +full_v(:,2) = numbers_order; +full_fd(:,2) = numbers_order; + +% Sort based on date. +full_v = sortrows(full_v, 1); +full_fd = sortrows(full_fd, 1); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%strip the numbering and date list off the main array and store separately. +only_datelist = full_v(:,1); %list of dates +only_numlist = full_v(:,2); %list of numbers for re-ordering + +%delete first two columns to leave just data itself +full_v(:,1:2)=[]; +full_fd(:,1:2)=[]; + +%% remove outliers in stack +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% First let's do this with the FLOW DIRECTION. + +%Calculate mean and standard deviation using circular statistics +[mean_fd,std_fd] = GIV_circstats(full_fd); + +% find points in the stack that are more than 2 standard deviations outside +% of the mean. +low_fd = mean_fd - 2 * std_fd; +templow_fd = mean_fd - 2 * std_fd; +high_fd = mean_fd + 2 * std_fd; +temphigh_fd = mean_fd + 2 * std_fd; +%Find if any are out of 0-360 circle +poslow = low_fd<0; +poshigh = temphigh_fd>360; +%flip where needed +high_fd(poslow)=360+templow_fd(poslow); +low_fd(poslow)=temphigh_fd(poslow); +low_fd(poshigh)=temphigh_fd(poshigh)-360; +high_fd(poshigh)=templow_fd(poshigh); + +%make full arrays of limits +full_low_fd = []; +full_high_fd = []; +for index = 1:size(full_fd,1) + full_low_fd(index,:) = low_fd; + full_high_fd(index,:) = high_fd; +end + +% where is it out of limit in BOTH (i.e. not caused by the boundary) +out_limits_fd = double((double(full_fdfull_high_fd))>=1); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Secondly, lets do this for the velocities. +mean_vel = nanmean(full_v); +std_vel = nanstd(full_v); + +% find points in the stack that are more than 2 standard deviations outside +% of the mean. +low_vel = mean_vel - 2 * std_vel; +high_vel = mean_vel + 2 * std_vel; +full_low_vel = []; +full_high_vel = []; + +for index = 1:size(full_v,1) %make full arrays of limits + full_low_vel(index,:) = low_vel; + full_high_vel(index,:) = high_vel; +end + +out_limits_low_vel = double(full_v < full_low_vel); +out_limits_high_vel = double(full_v > full_high_vel); +out_limits_vel = double((out_limits_low_vel + out_limits_high_vel)>=1); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%remove values more than 2 std away from mean in data +full_v(out_limits_fd==1)=NaN; +full_fd(out_limits_fd==1)=NaN; +full_v(out_limits_vel==1)=NaN; +full_fd(out_limits_vel==1)=NaN; + +%% Filter data in time and space if requested + +%(Only filter velocity, these filters are not built for cyclical values) +%TIME FILTER +if strcmpi(inputs.finalsmooth, 'Time') + full_v = nanfill_time(full_v, inputs, 2, 3); +%TIME AND SPACE FILTER +elseif strcmpi(inputs.finalsmooth, 'Time and Space') + full_v = nanfill_timeandspace(full_v, inputs, 4, 3); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%recalculate mean and std values with filtered dataset (only if >1 image) + +%Flow Direction +if size(full_fd,1)>1 + [mean_fd,std_fd] = GIV_circstats(full_fd); +else + mean_fd = (full_fd); + std_fd = (full_fd); %meaningless +end + + +%Velocity +if size(full_v,1)>1 + mean_v = nanmean(full_v); +else + mean_v = (full_v); +end + +if size(full_v,1)>1 + std_v = nanstd(full_v); +else + std_v = (full_v); %meaningless +end + +%reshape mean and std datasets +mean_fd = (reshape(mean_fd,inputs.sizevel)); %flipud +std_fd = (reshape(std_fd,inputs.sizevel)); %flipud +mean_v = (reshape(mean_v,inputs.sizevel)); %flipud +std_v = (reshape(std_v,inputs.sizevel)); %flipud + +%local smoothing and NaN filling +mean_fd = nanfillsm(mean_fd, inputs, 4, 3); +std_fd = nanfillsm(std_fd, inputs, 4, 3); +mean_v = nanfillsm(mean_v, inputs, 4, 3); +std_v = nanfillsm(std_v, inputs, 4, 3); + +%% Replace files in images array + +%Add back in numbering scheme, sort rows back into order then remove it +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +ordered_v(:,2:inputs.sizevel(1)*inputs.sizevel(2)+1)=full_v; ordered_v(:,1)=only_numlist; +ordered_fd(:,2:inputs.sizevel(1)*inputs.sizevel(2)+1)=full_fd; ordered_v(:,1)=only_numlist; +ordered_v = sortrows(ordered_v, 1); +ordered_fd = sortrows(ordered_fd, 1); +ordered_v(:,1)=[]; +ordered_fd(:,1)=[]; + +%Reinitialize loop parameters +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +meta_dum = 0; +array_pos = 0; +emptycount_inner = 0; +emptycount_outer = 0; + +%Run loop +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +for time_loop = 1:number_with_values + position1 = time_loop + 6 + array_pos; + position2 = time_loop + 7 + array_pos; + for inner_loop = 2:inputs.numimages-time_loop + if ~isempty(images{inner_loop,position1}) + %Replace velocity in array + images{inner_loop,position1} = (reshape(ordered_v(inner_loop+meta_dum-1-emptycount_inner-emptycount_outer,:),inputs.sizevel));%flipud + %Replace flow direction in array + images{inner_loop,position2} = (reshape(ordered_fd(inner_loop+meta_dum-1-emptycount_inner-emptycount_outer,:),inputs.sizevel)); %flipud + else + emptycount_inner = emptycount_inner + 1; + end +end + +emptycount_outer = emptycount_outer + emptycount_inner; +emptycount_inner = 0; +meta_dum = meta_dum + inputs.numimages-time_loop-1; +array_pos = array_pos + 1; +end + + +%% Create output array with useful data in it + +%initialize stack +images_stack = {}; + +%Load data into it +%All velocities (for plotting timeseries and querying points) +images_stack{1,1} = 'Full Velocity Array'; images_stack{1,2} = ordered_v; + +%All flow directions (for plotting timeseries and querying points) +images_stack{2,1} = 'Full Flow Direction Array'; images_stack{2,2} = ordered_fd; + +%Mean and standard deviation of velocity arrays +images_stack{3,1} = 'Mean Velocity'; images_stack{3,2} = mean_v; +images_stack{5,1} = 'Velocity Standard Deviation'; images_stack{5,2} = std_v; + +%Mean and standard deviation of velocity arrays +images_stack{4,1} = 'Mean Flow Direction'; images_stack{4,2} = mean_fd; +images_stack{6,1} = 'Flow Direction Standard Deviation'; images_stack{6,2} = std_fd; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Calculate some additional statistics: Minimum, Maximum, Median, 'Percent +%error' +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%Calculate values +if size(full_fd,1)>1 + max_fd = nanmax(full_fd); + max_v = nanmax(full_v); + min_fd = nanmin(full_fd); + min_v = nanmin(full_v); + median_fd = mean_fd; %Cyclical median calculations did not work for some reason, will try and fix + median_v = nanmedian(full_v); +else %(if only one single map) + max_fd = (full_fd); + max_v = (full_v); + min_fd = (full_fd); + min_v = (full_v); + median_fd = (full_fd); + median_v = (full_v); +end + +%reshape mean and std datasets +max_fd = (reshape(max_fd,inputs.sizevel));%flipud +max_v = (reshape(max_v,inputs.sizevel));%flipud +min_fd = (reshape(min_fd,inputs.sizevel));%flipud +min_v = (reshape(min_v,inputs.sizevel));%flipud +median_fd = (reshape(median_fd,inputs.sizevel));%flipud +median_v = (reshape(median_v,inputs.sizevel));%flipud + +%local smoothing and NaN filling +max_fd = nanfillsm(max_fd, inputs, 4, 3); +max_v = nanfillsm(max_v, inputs, 4, 3); +min_fd = nanfillsm(min_fd, inputs, 4, 3); +min_v = nanfillsm(min_v, inputs, 4, 3); +median_fd = nanfillsm(median_fd, inputs, 4, 3); +median_v = nanfillsm(median_v, inputs, 4, 3); +perc_error_v = 100*std_v./mean_v; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Load additional statistics into output array +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +images_stack{7,1} = 'Median Velocity'; images_stack{7,2} = median_v; +images_stack{8,1} = 'Median Flow Direction'; images_stack{8,2} = median_fd; +images_stack{9,1} = 'Maximum Velocity'; images_stack{9,2} = max_v; +images_stack{10,1} = 'Maximum Flow Direction'; images_stack{10,2} = max_fd; +images_stack{11,1} = 'Minimum Velocity'; images_stack{11,2} = min_v; +images_stack{12,1} = 'Minimum flow direction'; images_stack{12,2} = min_fd; +images_stack{13,1} = 'Percentage Error-Variability in Velocity'; images_stack{13,2} = perc_error_v; diff --git a/functions/other/im2month.m b/functions/other/im2month.m new file mode 100644 index 0000000..fc41ad0 --- /dev/null +++ b/functions/other/im2month.m @@ -0,0 +1,1774 @@ +function [monthly_averages]=im2month(images,inputs,images_stack) +% This fucntion takes the 'randomly spaced' images from the timeseries and +% creates an evenly spaced timeseries of monthly averages. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + +%First create array of first and last dates for each velocity map + +meta_dum = 0; +array_pos = 0; +emptycount_inner = 0; +emptycount_outer = 0; +number_with_values = (size(images,2)-6)/2; + + +for time_loop = 1:number_with_values + dum1 = time_loop + 6 + array_pos; + dum2 = time_loop + 7 + array_pos; + for inner_loop = 2:inputs.numimages-time_loop + + if ~isempty(images{inner_loop,dum1}) + + %calculate first and last date + + Start_interval = images{inner_loop,4}; + + End_interval = images{inner_loop+time_loop,4}; + + % Add these to master arrays + + first_date(inner_loop+meta_dum-1-emptycount_inner-emptycount_outer,1)= Start_interval; + + last_date(inner_loop+meta_dum-1-emptycount_inner-emptycount_outer,1)= End_interval; + + else + emptycount_inner = emptycount_inner + 1; + end + + end + + +emptycount_outer = emptycount_outer + emptycount_inner; +emptycount_inner = 0; +meta_dum = meta_dum + inputs.numimages-time_loop-1; +array_pos = array_pos + 1; +end + +%This has now created arrays with the DATE CODE of each image (date code is +%numbered as 1 at the first of Jan year 0, and so on. This is not so +%workable. Let's append the year, month and day to each array + +first_date(:,2) = year(datetime(first_date(:,1),'ConvertFrom','datenum')); +first_date(:,3) = month(datetime(first_date(:,1),'ConvertFrom','datenum')); +first_date(:,4) = day(datetime(first_date(:,1),'ConvertFrom','datenum')); + +last_date(:,2) = year(datetime(last_date(:,1),'ConvertFrom','datenum')); +last_date(:,3) = month(datetime(last_date(:,1),'ConvertFrom','datenum')); +last_date(:,4) = day(datetime(last_date(:,1),'ConvertFrom','datenum')); + +%Now let's find the first month we have data for, the last month we have +%data for and the amount of months between them. + +first_year = min(first_date(:,2)); +last_year = max(last_date(:,2)); + +% first_year_first=first_date(:,2); +% +% first_year_first(first_year_first>first_year)=[]; +% +% first_year_filtered = first_date; +% +% first_year_filtered(numel(first_year_first)+1:end,:) = []; + +first_month = month(datetime(min(first_date(:,1)),'ConvertFrom','datenum')); + +last_month = month(datetime(max(last_date(:,1)),'ConvertFrom','datenum')); + +% last_year_first=last_date(:,2); +% +% last_year_first(last_year_first= last_date(inner_loop,1) && last_date(inner_loop,1)>= first_day_code))... + | ((first_date(inner_loop,1) <= first_day_code && last_date(inner_loop,1) >= last_day_code)) + + %Create weight parameter for this particular velocity map, + %this will be equal to 1 if it is entirely within the + %month, or equal to 'percentage of velocity map averaging + %time period within this month' if not. For instance if the + %velocity is averaged over 2 months from 1 March to 30 + %April, its weight will be 0.5 for March and April. + + if first_date(inner_loop,1) >= first_day_code && last_date(inner_loop,1)<= last_day_code + + %If both true, velocity map is entirely within this + %month. + weight = 1; + + elseif first_date(inner_loop,1) <= first_day_code && last_date(inner_loop,1) <= last_day_code + + %If it starts prior to the month relevant but finishes + %prior to end of it. + weight = (last_date(inner_loop,1)-first_day_code)/(last_date(inner_loop,1)-first_date(inner_loop,1)); + + elseif first_date(inner_loop,1) >= first_day_code && last_date(inner_loop,1) >= last_day_code + + %If it ends after the month relevant but begins within + %it. + weight = (last_day_code-first_date(inner_loop,1))/(last_date(inner_loop,1)-first_date(inner_loop,1)); + + elseif first_date(inner_loop,1) <= first_day_code && last_date(inner_loop,1) >= last_day_code + + %If it both begins before month in question and ends + %after it. + weight = (last_day_code-first_day_code)/(last_date(inner_loop,1)-first_date(inner_loop,1)); + end + + %Add weighting parameter to the first column + + current_month_v(inner_parameter, 1) = weight; + + current_month_fd(inner_parameter, 1) = weight; + + + %Add velocities to the remainder of the row + + %Make NANs 0 + + %velocity + + temporary_row_v = images_stack{1,2}(inner_loop,:); + + temporary_row_v(isnan(temporary_row_v))=0; + + temporary_row_v(isnan(mask_lin)) = NaN; + + current_month_v(inner_parameter, 2:end) = temporary_row_v; + + + %flow direction + + + temporary_row_fd = images_stack{2,2}(inner_loop,:); + + temporary_row_fd(isnan(temporary_row_fd))=0; + + temporary_row_fd(isnan(mask_lin)) = NaN; + + current_month_fd(inner_parameter, 2:end) = temporary_row_fd; + + inner_parameter = inner_parameter + 1; + end + + end + + %Calculate total weight for this month + total_monthly_weight = sum(current_month_v(:, 1)); + + %Calculate a weighted mean of velocities + weighted_monthly_velocity = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); + for weighting_loop = 1:size(current_month_v,1) + weighted_monthly_velocity = weighted_monthly_velocity + current_month_v(weighting_loop,2:end)*current_month_v(weighting_loop,1); + end + + %Calculate a weighted mean of flow directions + weighting = repmat(current_month_fd(:,1),1,size(current_month_fd,2)-1); + [weighted_monthly_fd,~] = GIV_circstats(current_month_fd(:,2:end),weighting); + weighted_monthly_fd(weighted_monthly_fd==0)=NaN; + +% % % %A little more complex for flod directions because of the 0-360 +% % % %boundary. We are going to again create an 'offset' flow +% % % %direction plot (where 0-180 become 360-540), then calculate +% % % %the standard devitation of each matrix. Where the 0-360 +% % % %boundary is being crossed, standard deviation will be higher +% % % %and the other matix (-180) will be selected. +% % % +% % % %first create the offset flow direction +% % % +% % % current_month_fd_540 = current_month_fd; +% % % +% % % %Transpose it +% % % +% % % findless180 = (double(current_month_fd_540<180).*current_month_fd_540)+360; +% % % +% % % findless180(findless180 == 360) = 0; +% % % +% % % current_month_fd_540(current_month_fd_540<180)=0; +% % % +% % % current_month_fd_540 = current_month_fd_540 + findless180; +% % % +% % % %Now calculate the standard deviation for each array +% % % +% % % st_dev_fd = nanstd(current_month_fd,0,1); +% % % +% % % st_dev_fd_540 = nanstd(current_month_fd_540,0,1); +% % % +% % % +% % % %find where the standard deviation is lower in 540 array. +% % % +% % % boundary_crossed = st_dev_fd_540-st_dev_fd; +% % % +% % % boundary_crossed(boundary_crossed< 0) =1; +% % % +% % % boundary_crossed(boundary_crossed> 0) =0; +% % % +% % % boundary_crossed(:,1)=[]; +% % % +% % % %Calculate weighted averages for each. +% % % +% % % weighted_monthly_fd = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); +% % % for weighting_loop = 1:size(current_month_fd,1) +% % % weighted_monthly_fd = weighted_monthly_fd + current_month_fd(weighting_loop,2:end)*current_month_fd(weighting_loop,1); +% % % end +% % % +% % % weighted_monthly_fd_540 = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); +% % % for weighting_loop = 1:size(current_month_fd_540,1) +% % % weighted_monthly_fd_540 = weighted_monthly_fd_540 + current_month_fd_540(weighting_loop,2:end)*current_month_fd(weighting_loop,1); +% % % end +% % % + %Calculate weighting in each location (to account for NaN + %values) + + local_weight_fd = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); + for weighting_loop = 1:size(current_month_fd,1) + portion = current_month_fd(weighting_loop,2:end); + portion(isnan(portion)) = 0; + portion(portion~=0)=current_month_fd(weighting_loop,1); + local_weight_fd = local_weight_fd + portion; + end + + local_weight_v = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); + for weighting_loop = 1:size(current_month_v,1) + portion = current_month_v(weighting_loop,2:end); + portion(isnan(portion)) = 0; + portion(portion~=0)=current_month_v(weighting_loop,1); + local_weight_v = local_weight_v + portion; + end +% % % +% % % +% % % %Put the 360-540 portion back in its place. +% % % +% % % findmore360 = (double(weighted_monthly_fd_540>360).*weighted_monthly_fd_540)-360; +% % % +% % % findmore360(findmore360 == 360) = 0; +% % % +% % % weighted_monthly_fd_540(weighted_monthly_fd_540>360)=0; +% % % +% % % weighted_monthly_fd_540 = weighted_monthly_fd_540 + findmore360; +% % % +% % % +% % % %Replace with the _540 values where std is lower +% % % +% % % weighted_monthly_fd(boundary_crossed==1) = 0; +% % % +% % % add_part = boundary_crossed.*weighted_monthly_fd_540; +% % % +% % % weighted_monthly_fd = weighted_monthly_fd+add_part; + + % + + if ~isnan(nanmean(local_weight_fd,'all')) + + + + + weighted_monthly_velocity = weighted_monthly_velocity./local_weight_v; + + +% weighted_monthly_fd = weighted_monthly_fd./local_weight_fd; + end + + %We now have a linear matrix with the weighted velocities, we + %simply need to make it the right shape. + + weighted_monthly_velocity = (reshape(weighted_monthly_velocity,inputs.sizevel)); %flipud + + weighted_monthly_fd = (reshape(weighted_monthly_fd,inputs.sizevel));%flipud + + + %Infill isolated NaNs and do some slight smoothing + + weighted_monthly_velocity = nanfillsm(weighted_monthly_velocity, inputs, 4, 3); + + weighted_monthly_fd = nanfillsm(weighted_monthly_fd, inputs, 4, 3); + + + %Finally we need to load the data into the outputs array. First + %we determine the position we are at in this array: + + position_in_array = 12*(year_loop-first_year) + month_loop-first_month + 1; + + %Then at last we load the data into this array! + + %First column is the year + monthly_averages{position_in_array,1} = year_loop; + + %Second column is the month + monthly_averages{position_in_array,2} = month_loop; + + %Third column is the mean velocity + monthly_averages{position_in_array,3} = weighted_monthly_velocity; + + %Fourth column is the mean flow direction + monthly_averages{position_in_array,4} = weighted_monthly_fd; + + %Fifth column is the quality of data for this month, as + %determined from the total monthly weight. This uses the + %following formula: + %Low Reliability data : total monthly weight <= 1 + %Moderate Reliability data : 1 < total monthly weight <= 2.5 + %High Reliability data : 2.5 < total monthly weight + if total_monthly_weight <= 1 + monthly_averages{position_in_array,5} = 'Low Reliability data'; + elseif 1 < total_monthly_weight <= 2.5 + monthly_averages{position_in_array,5} = 'Moderate Reliability data'; + elseif 2.5 < total_monthly_weight + monthly_averages{position_in_array,5} = 'High Reliability data'; + end + + end + + + elseif year_loop ~= first_year && year_loop ~= last_year + for month_loop = 1:12 + + %First lets create a number string with the first and last day + %of this month + + first_day_code = datenum(year_loop,month_loop,01); + if month_loop ~= 12 + last_day_code = datenum(year_loop,month_loop+1,01)-1; + elseif month_loop == 12 + last_day_code = datenum(year_loop+1,01,01)-1; + end + + %Now let's find which velocity maps are relevant to this month + + inner_parameter = 1; + + %Let's create a temporary array to store this and the + %velocities in. And a second for the flow direction. + + current_month_v = NaN(1,inputs.sizevel(1)*inputs.sizevel(2) + 1); + + current_month_fd = NaN(1,inputs.sizevel(1)*inputs.sizevel(2) + 1); + + + for inner_loop = 1:size(first_date,1) + %This long formula is determining if the interval is in + %range + if ((first_day_code <= first_date(inner_loop,1) && first_date(inner_loop,1) <= last_day_code))... + | ((last_day_code >= last_date(inner_loop,1) && last_date(inner_loop,1)>= first_day_code))... + | ((first_date(inner_loop,1) <= first_day_code && last_date(inner_loop,1) >= last_day_code)) + + %Create weight parameter for this particular velocity map, + %this will be equal to 1 if it is entirely within the + %month, or equal to 'percentage of velocity map averaging + %time period within this month' if not. For instance if the + %velocity is averaged over 2 months from 1 March to 30 + %April, its weight will be 0.5 for March and April. + + if first_date(inner_loop,1) >= first_day_code && last_date(inner_loop,1)<= last_day_code + + %If both true, velocity map is entirely within this + %month. + weight = 1; + + elseif first_date(inner_loop,1) <= first_day_code && last_date(inner_loop,1) <= last_day_code + + %If it starts prior to the month relevant but finishes + %prior to end of it. + weight = (last_date(inner_loop,1)-first_day_code)/(last_date(inner_loop,1)-first_date(inner_loop,1)); + + elseif first_date(inner_loop,1) >= first_day_code && last_date(inner_loop,1) >= last_day_code + + %If it ends after the month relevant but begins within + %it. + weight = (last_day_code-first_date(inner_loop,1))/(last_date(inner_loop,1)-first_date(inner_loop,1)); + + elseif first_date(inner_loop,1) <= first_day_code && last_date(inner_loop,1) >= last_day_code + + %If it both begins before month in question and ends + %after it. + weight = (last_day_code-first_day_code)/(last_date(inner_loop,1)-first_date(inner_loop,1)); + end + +%Add weighting parameter to the first column + + current_month_v(inner_parameter, 1) = weight; + + current_month_fd(inner_parameter, 1) = weight; + + + %Add velocities to the remainder of the row + + %Make NANs 0 + + %velocity + + temporary_row_v = images_stack{1,2}(inner_loop,:); + + temporary_row_v(isnan(temporary_row_v))=0; + + temporary_row_v(isnan(mask_lin)) = NaN; + + current_month_v(inner_parameter, 2:end) = temporary_row_v; + + + %flow direction + + + temporary_row_fd = images_stack{2,2}(inner_loop,:); + + temporary_row_fd(isnan(temporary_row_fd))=0; + + temporary_row_fd(isnan(mask_lin)) = NaN; + + current_month_fd(inner_parameter, 2:end) = temporary_row_fd; + + inner_parameter = inner_parameter + 1; + end + + end + + %Calculate total weight for this month + total_monthly_weight = sum(current_month_v(:, 1)); + + %Calculate a weighted mean of velocities + weighted_monthly_velocity = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); + for weighting_loop = 1:size(current_month_v,1) + weighted_monthly_velocity = weighted_monthly_velocity + current_month_v(weighting_loop,2:end)*current_month_v(weighting_loop,1); + end + + %Calculate a weighted mean of flow directions + weighting = repmat(current_month_fd(:,1),1,size(current_month_fd,2)-1); + [weighted_monthly_fd,~] = GIV_circstats(current_month_fd(:,2:end),weighting); + weighted_monthly_fd(weighted_monthly_fd==0)=NaN; + +% % % % %A little more complex for flod directions because of the 0-360 +% % % % %boundary. We are going to again create an 'offset' flow +% % % % %direction plot (where 0-180 become 360-540), then calculate +% % % % %the standard devitation of each matrix. Where the 0-360 +% % % % %boundary is being crossed, standard deviation will be higher +% % % % %and the other matix (-180) will be selected. +% % % % +% % % % %first create the offset flow direction +% % % % +% % % % current_month_fd_540 = current_month_fd; +% % % % +% % % % %Transpose it +% % % % +% % % % findless180 = (double(current_month_fd_540<180).*current_month_fd_540)+360; +% % % % +% % % % findless180(findless180 == 360) = 0; +% % % % +% % % % current_month_fd_540(current_month_fd_540<180)=0; +% % % % +% % % % current_month_fd_540 = current_month_fd_540 + findless180; +% % % % +% % % % %Now calculate the standard deviation for each array +% % % % +% % % % st_dev_fd = nanstd(current_month_fd,0,1); +% % % % +% % % % st_dev_fd_540 = nanstd(current_month_fd_540,0,1); +% % % % +% % % % +% % % % %find where the standard deviation is lower in 540 array. +% % % % +% % % % boundary_crossed = st_dev_fd_540-st_dev_fd; +% % % % +% % % % boundary_crossed(boundary_crossed< 0) =1; +% % % % +% % % % boundary_crossed(boundary_crossed> 0) =0; +% % % % +% % % % boundary_crossed(:,1)=[]; +% % % % +% % % % %Calculate weighted averages for each. +% % % % +% % % % weighted_monthly_fd = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); +% % % % for weighting_loop = 1:size(current_month_fd,1) +% % % % weighted_monthly_fd = weighted_monthly_fd + current_month_fd(weighting_loop,2:end)*current_month_fd(weighting_loop,1); +% % % % end +% % % % +% % % % weighted_monthly_fd_540 = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); +% % % % for weighting_loop = 1:size(current_month_fd_540,1) +% % % % weighted_monthly_fd_540 = weighted_monthly_fd_540 + current_month_fd_540(weighting_loop,2:end)*current_month_fd(weighting_loop,1); +% % % % end +% % % % + %Calculate weighting in each location (to account for NaN + %values) + local_weight_fd = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); + for weighting_loop = 1:size(current_month_fd,1) + portion = current_month_fd(weighting_loop,2:end); + portion(isnan(portion)) = 0; + portion(portion~=0)=current_month_fd(weighting_loop,1); + local_weight_fd = local_weight_fd + portion; + end + + local_weight_v = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); + for weighting_loop = 1:size(current_month_v,1) + portion = current_month_v(weighting_loop,2:end); + portion(isnan(portion)) = 0; + portion(portion~=0)=current_month_v(weighting_loop,1); + local_weight_v = local_weight_v + portion; + end +% % % % +% % % % %Put the 360-540 portion back in its place. +% % % % +% % % % findmore360 = (double(weighted_monthly_fd_540>360).*weighted_monthly_fd_540)-360; +% % % % +% % % % findmore360(findmore360 == 360) = 0; +% % % % +% % % % weighted_monthly_fd_540(weighted_monthly_fd_540>360)=0; +% % % % +% % % % weighted_monthly_fd_540 = weighted_monthly_fd_540 + findmore360; +% % % % +% % % % +% % % % %Replace with the _540 values where std is lower +% % % % +% % % % weighted_monthly_fd(boundary_crossed==1) = 0; +% % % % +% % % % add_part = boundary_crossed.*weighted_monthly_fd_540; +% % % % +% % % % weighted_monthly_fd = weighted_monthly_fd+add_part; + + % + + if ~isnan(nanmean(local_weight_fd,'all')) + + + + + weighted_monthly_velocity = weighted_monthly_velocity./local_weight_v; + + +% weighted_monthly_fd = weighted_monthly_fd./local_weight_fd; + end + + + %We now have a linear matrix with the weighted velocities, we + %simply need to make it the right shape. + + weighted_monthly_velocity = (reshape(weighted_monthly_velocity,inputs.sizevel)); %flipud + + weighted_monthly_fd = (reshape(weighted_monthly_fd,inputs.sizevel)); %flipud + + + %Infill isolated NaNs and do some slight smoothing + + weighted_monthly_velocity = nanfillsm(weighted_monthly_velocity, inputs, 4, 3); + + weighted_monthly_fd = nanfillsm(weighted_monthly_fd, inputs, 4, 3); + + + %Finally we need to load the data into the outputs array. First + %we determine the position we are at in this array: + + position_in_array = 12*(year_loop-first_year) + month_loop-first_month + 1; + + %Then at last we load the data into this array! + + %First column is the year + monthly_averages{position_in_array,1} = year_loop; + + %Second column is the month + monthly_averages{position_in_array,2} = month_loop; + + %Third column is the mean velocity + monthly_averages{position_in_array,3} = weighted_monthly_velocity; + + %Fourth column is the mean flow direction + monthly_averages{position_in_array,4} = weighted_monthly_fd; + + %Fifth column is the quality of data for this month, as + %determined from the total monthly weight. This uses the + %following formula: + %Low Reliability data : total monthly weight <= 1 + %Moderate Reliability data : 1 < total monthly weight <= 2.5 + %High Reliability data : 2.5 < total monthly weight + if total_monthly_weight <= 1 + monthly_averages{position_in_array,5} = 'Low Reliability data'; + elseif 1 < total_monthly_weight <= 2.5 + monthly_averages{position_in_array,5} = 'Moderate Reliability data'; + elseif 2.5 < total_monthly_weight + monthly_averages{position_in_array,5} = 'High Reliability data'; + end + + end + elseif year_loop ~= first_year && year_loop == last_year + for month_loop = 1:last_month + + %First lets create a number string with the first and last day + %of this month + + first_day_code = datenum(year_loop,month_loop,01); + if month_loop ~= 12 + last_day_code = datenum(year_loop,month_loop+1,01)-1; + elseif month_loop == 12 + last_day_code = datenum(year_loop+1,01,01)-1; + end + + %Now let's find which velocity maps are relevant to this month + + inner_parameter = 1; + + %Let's create a temporary array to store this and the + %velocities in. And a second for the flow direction. + + current_month_v = NaN(1,inputs.sizevel(1)*inputs.sizevel(2) + 1); + + current_month_fd = NaN(1,inputs.sizevel(1)*inputs.sizevel(2) + 1); + + for inner_loop = 1:size(first_date,1) + %This long formula is determining if the interval is in + %range + if ((first_day_code <= first_date(inner_loop,1) && first_date(inner_loop,1) <= last_day_code))... + | ((last_day_code >= last_date(inner_loop,1) && last_date(inner_loop,1)>= first_day_code))... + | ((first_date(inner_loop,1) <= first_day_code && last_date(inner_loop,1) >= last_day_code)) + + %Create weight parameter for this particular velocity map, + %this will be equal to 1 if it is entirely within the + %month, or equal to 'percentage of velocity map averaging + %time period within this month' if not. For instance if the + %velocity is averaged over 2 months from 1 March to 30 + %April, its weight will be 0.5 for March and April. + + if first_date(inner_loop,1) >= first_day_code && last_date(inner_loop,1)<= last_day_code + + %If both true, velocity map is entirely within this + %month. + weight = 1; + + elseif first_date(inner_loop,1) <= first_day_code && last_date(inner_loop,1) <= last_day_code + + %If it starts prior to the month relevant but finishes + %prior to end of it. + weight = (last_date(inner_loop,1)-first_day_code)/(last_date(inner_loop,1)-first_date(inner_loop,1)); + + elseif first_date(inner_loop,1) >= first_day_code && last_date(inner_loop,1) >= last_day_code + + %If it ends after the month relevant but begins within + %it. + weight = (last_day_code-first_date(inner_loop,1))/(last_date(inner_loop,1)-first_date(inner_loop,1)); + + elseif first_date(inner_loop,1) <= first_day_code && last_date(inner_loop,1) >= last_day_code + + %If it both begins before month in question and ends + %after it. + weight = (last_day_code-first_day_code)/(last_date(inner_loop,1)-first_date(inner_loop,1)); + end + + + %Add weighting parameter to the first column + + current_month_v(inner_parameter, 1) = weight; + + current_month_fd(inner_parameter, 1) = weight; + + + %Add velocities to the remainder of the row + + %Make NANs 0 + + %velocity + + temporary_row_v = images_stack{1,2}(inner_loop,:); + + temporary_row_v(isnan(temporary_row_v))=0; + + temporary_row_v(isnan(mask_lin)) = NaN; + + current_month_v(inner_parameter, 2:end) = temporary_row_v; + + + %flow direction + + + temporary_row_fd = images_stack{2,2}(inner_loop,:); + + temporary_row_fd(isnan(temporary_row_fd))=0; + + temporary_row_fd(isnan(mask_lin)) = NaN; + + current_month_fd(inner_parameter, 2:end) = temporary_row_fd; + + inner_parameter = inner_parameter + 1; + end + + end + + %Calculate total weight for this month + total_monthly_weight = sum(current_month_v(:, 1)); + + %Calculate a weighted mean of velocities + weighted_monthly_velocity = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); + for weighting_loop = 1:size(current_month_v,1) + weighted_monthly_velocity = weighted_monthly_velocity + current_month_v(weighting_loop,2:end)*current_month_v(weighting_loop,1); + end + + %Calculate a weighted mean of flow directions + weighting = repmat(current_month_fd(:,1),1,size(current_month_fd,2)-1); + [weighted_monthly_fd,~] = GIV_circstats(current_month_fd(:,2:end),weighting); + weighted_monthly_fd(weighted_monthly_fd==0)=NaN; + +% % % % %A little more complex for flod directions because of the 0-360 +% % % % %boundary. We are going to again create an 'offset' flow +% % % % %direction plot (where 0-180 become 360-540), then calculate +% % % % %the standard devitation of each matrix. Where the 0-360 +% % % % %boundary is being crossed, standard deviation will be higher +% % % % %and the other matix (-180) will be selected. +% % % % +% % % % %first create the offset flow direction +% % % % +% % % % current_month_fd_540 = current_month_fd; +% % % % +% % % % %Transpose it +% % % % +% % % % findless180 = (double(current_month_fd_540<180).*current_month_fd_540)+360; +% % % % +% % % % findless180(findless180 == 360) = 0; +% % % % +% % % % current_month_fd_540(current_month_fd_540<180)=0; +% % % % +% % % % current_month_fd_540 = current_month_fd_540 + findless180; +% % % % +% % % % %Now calculate the standard deviation for each array +% % % % +% % % % st_dev_fd = nanstd(current_month_fd,0,1); +% % % % +% % % % st_dev_fd_540 = nanstd(current_month_fd_540,0,1); +% % % % +% % % % +% % % % %find where the standard deviation is lower in 540 array. +% % % % +% % % % boundary_crossed = st_dev_fd_540-st_dev_fd; +% % % % +% % % % boundary_crossed(boundary_crossed< 0) =1; +% % % % +% % % % boundary_crossed(boundary_crossed> 0) =0; +% % % % +% % % % boundary_crossed(:,1)=[]; +% % % % +% % % % %Calculate weighted averages for each. +% % % % +% % % % weighted_monthly_fd = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); +% % % % for weighting_loop = 1:size(current_month_fd,1) +% % % % weighted_monthly_fd = weighted_monthly_fd + current_month_fd(weighting_loop,2:end)*current_month_fd(weighting_loop,1); +% % % % end +% % % % +% % % % weighted_monthly_fd_540 = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); +% % % % for weighting_loop = 1:size(current_month_fd_540,1) +% % % % weighted_monthly_fd_540 = weighted_monthly_fd_540 + current_month_fd_540(weighting_loop,2:end)*current_month_fd(weighting_loop,1); +% % % % end +% % % % + %Calculate weighting in each location (to account for NaN + %values) + local_weight_fd = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); + for weighting_loop = 1:size(current_month_fd,1) + portion = current_month_fd(weighting_loop,2:end); + portion(isnan(portion)) = 0; + portion(portion~=0)=current_month_fd(weighting_loop,1); + local_weight_fd = local_weight_fd + portion; + end + + local_weight_v = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); + for weighting_loop = 1:size(current_month_v,1) + portion = current_month_v(weighting_loop,2:end); + portion(isnan(portion)) = 0; + portion(portion~=0)=current_month_v(weighting_loop,1); + local_weight_v = local_weight_v + portion; + end +% % % % +% % % % %Put the 360-540 portion back in its place. +% % % % +% % % % findmore360 = (double(weighted_monthly_fd_540>360).*weighted_monthly_fd_540)-360; +% % % % +% % % % findmore360(findmore360 == 360) = 0; +% % % % +% % % % weighted_monthly_fd_540(weighted_monthly_fd_540>360)=0; +% % % % +% % % % weighted_monthly_fd_540 = weighted_monthly_fd_540 + findmore360; +% % % % +% % % % +% % % % %Replace with the _540 values where std is lower +% % % % +% % % % weighted_monthly_fd(boundary_crossed==1) = 0; +% % % % +% % % % add_part = boundary_crossed.*weighted_monthly_fd_540; +% % % % +% % % % weighted_monthly_fd = weighted_monthly_fd+add_part; + + % + + if ~isnan(nanmean(local_weight_fd,'all')) + + + + + weighted_monthly_velocity = weighted_monthly_velocity./local_weight_v; + + +% weighted_monthly_fd = weighted_monthly_fd./local_weight_fd; + end + + + %We now have a linear matrix with the weighted velocities, we + %simply need to make it the right shape. + + weighted_monthly_velocity = (reshape(weighted_monthly_velocity,inputs.sizevel)); %flipud + + weighted_monthly_fd = (reshape(weighted_monthly_fd,inputs.sizevel)); %flipud + + + %Infill isolated NaNs and do some slight smoothing + + weighted_monthly_velocity = nanfillsm(weighted_monthly_velocity, inputs, 4, 3); + + weighted_monthly_fd = nanfillsm(weighted_monthly_fd, inputs, 4, 3); + + + %Finally we need to load the data into the outputs array. First + %we determine the position we are at in this array: + + position_in_array = 12*(year_loop-first_year) + month_loop-first_month + 1; + + %Then at last we load the data into this array! + + %First column is the year + monthly_averages{position_in_array,1} = year_loop; + + %Second column is the month + monthly_averages{position_in_array,2} = month_loop; + + %Third column is the mean velocity + monthly_averages{position_in_array,3} = weighted_monthly_velocity; + + %Fourth column is the mean flow direction + monthly_averages{position_in_array,4} = weighted_monthly_fd; + + %Fifth column is the quality of data for this month, as + %determined from the total monthly weight. This uses the + %following formula: + %Low Reliability data : total monthly weight <= 1 + %Moderate Reliability data : 1 < total monthly weight <= 2.5 + %High Reliability data : 2.5 < total monthly weight + if total_monthly_weight <= 1 + monthly_averages{position_in_array,5} = 'Low Reliability data'; + elseif 1 < total_monthly_weight <= 2.5 + monthly_averages{position_in_array,5} = 'Moderate Reliability data'; + elseif 2.5 < total_monthly_weight + monthly_averages{position_in_array,5} = 'High Reliability data'; + end + + end + elseif year_loop == first_year && year_loop == last_year + for month_loop = first_month:last_month + + %First lets create a number string with the first and last day + %of this month + + first_day_code = datenum(year_loop,month_loop,01); + if month_loop ~= 12 + last_day_code = datenum(year_loop,month_loop+1,01)-1; + elseif month_loop == 12 + last_day_code = datenum(year_loop+1,01,01)-1; + end + + %Now let's find which velocity maps are relevant to this month + + inner_parameter = 1; + + %Let's create a temporary array to store this and the + %velocities in. And a second for the flow direction. + + current_month_v = NaN(1,inputs.sizevel(1)*inputs.sizevel(2) + 1); + + current_month_fd = NaN(1,inputs.sizevel(1)*inputs.sizevel(2) + 1); + + + for inner_loop = 1:size(first_date,1) + %This long formula is determining if the interval is in + %range + if ((first_day_code <= first_date(inner_loop,1) && first_date(inner_loop,1) <= last_day_code))... + | ((last_day_code >= last_date(inner_loop,1) && last_date(inner_loop,1)>= first_day_code))... + | ((first_date(inner_loop,1) <= first_day_code && last_date(inner_loop,1) >= last_day_code)) + + %Create weight parameter for this particular velocity map, + %this will be equal to 1 if it is entirely within the + %month, or equal to 'percentage of velocity map averaging + %time period within this month' if not. For instance if the + %velocity is averaged over 2 months from 1 March to 30 + %April, its weight will be 0.5 for March and April. + + if first_date(inner_loop,1) >= first_day_code && last_date(inner_loop,1)<= last_day_code + + %If both true, velocity map is entirely within this + %month. + weight = 1; + + elseif first_date(inner_loop,1) <= first_day_code && last_date(inner_loop,1) <= last_day_code + + %If it starts prior to the month relevant but finishes + %prior to end of it. + weight = (last_date(inner_loop,1)-first_day_code)/(last_date(inner_loop,1)-first_date(inner_loop,1)); + + elseif first_date(inner_loop,1) >= first_day_code && last_date(inner_loop,1) >= last_day_code + + %If it ends after the month relevant but begins within + %it. + weight = (last_day_code-first_date(inner_loop,1))/(last_date(inner_loop,1)-first_date(inner_loop,1)); + + elseif first_date(inner_loop,1) <= first_day_code && last_date(inner_loop,1) >= last_day_code + + %If it both begins before month in question and ends + %after it. + weight = (last_day_code-first_day_code)/(last_date(inner_loop,1)-first_date(inner_loop,1)); + end + + % We now have a weighting parameter. + + %Add weighting parameter to the first column + + current_month_v(inner_parameter, 1) = weight; + + current_month_fd(inner_parameter, 1) = weight; + + + %Add velocities to the remainder of the row + + %Make NANs 0 + + %velocity + + temporary_row_v = images_stack{1,2}(inner_loop,:); + + temporary_row_v(isnan(temporary_row_v))=0; + + temporary_row_v(isnan(mask_lin)) = NaN; + + current_month_v(inner_parameter, 2:end) = temporary_row_v; + + + %flow direction + + + temporary_row_fd = images_stack{2,2}(inner_loop,:); + + temporary_row_fd(isnan(temporary_row_fd))=0; + + temporary_row_fd(isnan(mask_lin)) = NaN; + + current_month_fd(inner_parameter, 2:end) = temporary_row_fd; + + inner_parameter = inner_parameter + 1; + end + + end + + %Calculate total weight for this month + total_monthly_weight = sum(current_month_v(:, 1)); + + %Calculate a weighted mean of velocities + weighted_monthly_velocity = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); + for weighting_loop = 1:size(current_month_v,1) + weighted_monthly_velocity = weighted_monthly_velocity + current_month_v(weighting_loop,2:end)*current_month_v(weighting_loop,1); + end + + %Calculate a weighted mean of flow directions + weighting = repmat(current_month_fd(:,1),1,size(current_month_fd,2)-1); + [weighted_monthly_fd,~] = GIV_circstats(current_month_fd(:,2:end),weighting); + weighted_monthly_fd(weighted_monthly_fd==0)=NaN; + +% % % % %A little more complex for flod directions because of the 0-360 +% % % % %boundary. We are going to again create an 'offset' flow +% % % % %direction plot (where 0-180 become 360-540), then calculate +% % % % %the standard devitation of each matrix. Where the 0-360 +% % % % %boundary is being crossed, standard deviation will be higher +% % % % %and the other matix (-180) will be selected. +% % % % +% % % % %first create the offset flow direction +% % % % +% % % % current_month_fd_540 = current_month_fd; +% % % % +% % % % %Transpose it +% % % % +% % % % findless180 = (double(current_month_fd_540<180).*current_month_fd_540)+360; +% % % % +% % % % findless180(findless180 == 360) = 0; +% % % % +% % % % current_month_fd_540(current_month_fd_540<180)=0; +% % % % +% % % % current_month_fd_540 = current_month_fd_540 + findless180; +% % % % +% % % % %Now calculate the standard deviation for each array +% % % % +% % % % st_dev_fd = nanstd(current_month_fd,0,1); +% % % % +% % % % st_dev_fd_540 = nanstd(current_month_fd_540,0,1); +% % % % +% % % % +% % % % %find where the standard deviation is lower in 540 array. +% % % % +% % % % boundary_crossed = st_dev_fd_540-st_dev_fd; +% % % % +% % % % boundary_crossed(boundary_crossed< 0) =1; +% % % % +% % % % boundary_crossed(boundary_crossed> 0) =0; +% % % % +% % % % boundary_crossed(:,1)=[]; +% % % % +% % % % %Calculate weighted averages for each. +% % % % +% % % % weighted_monthly_fd = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); +% % % % for weighting_loop = 1:size(current_month_fd,1) +% % % % weighted_monthly_fd = weighted_monthly_fd + current_month_fd(weighting_loop,2:end)*current_month_fd(weighting_loop,1); +% % % % end +% % % % +% % % % weighted_monthly_fd_540 = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); +% % % % for weighting_loop = 1:size(current_month_fd_540,1) +% % % % weighted_monthly_fd_540 = weighted_monthly_fd_540 + current_month_fd_540(weighting_loop,2:end)*current_month_fd(weighting_loop,1); +% % % % end +% % % % + %Calculate weighting in each location (to account for NaN + %values) + local_weight_fd = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); + for weighting_loop = 1:size(current_month_fd,1) + portion = current_month_fd(weighting_loop,2:end); + portion(isnan(portion)) = 0; + portion(portion~=0)=current_month_fd(weighting_loop,1); + local_weight_fd = local_weight_fd + portion; + end + + local_weight_v = zeros(1,inputs.sizevel(1)*inputs.sizevel(2)); + for weighting_loop = 1:size(current_month_v,1) + portion = current_month_v(weighting_loop,2:end); + portion(isnan(portion)) = 0; + portion(portion~=0)=current_month_v(weighting_loop,1); + local_weight_v = local_weight_v + portion; + end +% % % % +% % % % %Put the 360-540 portion back in its place. +% % % % +% % % % findmore360 = (double(weighted_monthly_fd_540>360).*weighted_monthly_fd_540)-360; +% % % % +% % % % findmore360(findmore360 == 360) = 0; +% % % % +% % % % weighted_monthly_fd_540(weighted_monthly_fd_540>360)=0; +% % % % +% % % % weighted_monthly_fd_540 = weighted_monthly_fd_540 + findmore360; +% % % % +% % % % +% % % % %Replace with the _540 values where std is lower +% % % % +% % % % weighted_monthly_fd(boundary_crossed==1) = 0; +% % % % +% % % % add_part = boundary_crossed.*weighted_monthly_fd_540; +% % % % +% % % % weighted_monthly_fd = weighted_monthly_fd+add_part; + + % + + if ~isnan(nanmean(local_weight_fd,'all')) + + + + + weighted_monthly_velocity = weighted_monthly_velocity./local_weight_v; + + +% weighted_monthly_fd = weighted_monthly_fd./local_weight_fd; + end + + + %We now have a linear matrix with the weighted velocities, we + %simply need to make it the right shape. + + weighted_monthly_velocity = (reshape(weighted_monthly_velocity,inputs.sizevel)); %flipud + + weighted_monthly_fd = (reshape(weighted_monthly_fd,inputs.sizevel)); %flipud + + + %Infill isolated NaNs and do some slight smoothing + + weighted_monthly_velocity = nanfillsm(weighted_monthly_velocity, inputs, 4, 3); + + weighted_monthly_fd = nanfillsm(weighted_monthly_fd, inputs, 4, 3); + + + %Finally we need to load the data into the outputs array. First + %we determine the position we are at in this array: + + position_in_array = 12*(year_loop-first_year) + month_loop-first_month + 1; + + %Then at last we load the data into this array! + + %First column is the year + monthly_averages{position_in_array,1} = year_loop; + + %Second column is the month + monthly_averages{position_in_array,2} = month_loop; + + %Third column is the mean velocity + monthly_averages{position_in_array,3} = weighted_monthly_velocity; + + %Fourth column is the mean flow direction + monthly_averages{position_in_array,4} = weighted_monthly_fd; + + %Fifth column is the quality of data for this month, as + %determined from the total monthly weight. This uses the + %following formula: + %Low Reliability data : total monthly weight <= 1 + %Moderate Reliability data : 1 < total monthly weight <= 2.5 + %High Reliability data : 2.5 < total monthly weight + if total_monthly_weight <= 1 + monthly_averages{position_in_array,5} = 'Low Reliability data'; + elseif 1 < total_monthly_weight <= 2.5 + monthly_averages{position_in_array,5} = 'Moderate Reliability data'; + elseif 2.5 < total_monthly_weight + monthly_averages{position_in_array,5} = 'High Reliability data'; + end + + end + end +end + + + + + +if inputs.nummonthiter > 0 + + +% The first pass is now completed. We will now iterate for each image not +% fully located within a single month between 1) splitting it up into the +% constituant months by subtracting the averages calculated above and 2) +% recalculating the averages. This will be repeated a certain number of +% times until convergence is reached. + + +%%%%% Create matrix of percentage of each image within a given month. + + +%set the context +y_numel = size(monthly_averages,1)+1; + +x_numel = size(images_stack{1,2},1)+2; + +month_percent = num2cell(NaN(y_numel,x_numel)); + +for i = 2:size(month_percent,1) +month_percent{i,1} = monthly_averages{i-1,1}; +month_percent{i,2} = monthly_averages{i-1,2}; +end + +for i = 3:size(month_percent,2) +month_percent{1,i} = i-2; +end +% + +%Calculate the percentages + +%Firstly work out the length of averaging interval for each matrix. + +meta_dum = 0; + +array_pos = 0; + +emptycount_inner = 0; + +emptycount_outer = 0; + +number_in_range = 0; + +number_with_values = (size(images,2)-6)/2; + +for time_loop = 1:number_with_values + dum1 = 6+time_loop*2; + for inner_loop = 2:inputs.numimages-time_loop + + if ~isempty(images{inner_loop,dum1}) + + number_in_range = number_in_range + 1; + + end + + end +end; + +full_time = NaN(1,size(images_stack{1,2},1)); + + +for time_loop = 1:number_with_values + dum1 = time_loop + 6 + array_pos; + dum2 = time_loop + 7 + array_pos; + for inner_loop = 2:inputs.numimages-time_loop + + if ~isempty(images{inner_loop,dum1}) + + %calculate time interval + + time_gap = (images{inner_loop+time_loop,5}-images{inner_loop,5}); + +% % Here calculates a median date for the interval that we will use +% +% date_current = round(images{inner_loop+time_loop,4}-(time_gap/2)); + + full_time(1,inner_loop+meta_dum-1-emptycount_inner-emptycount_outer)= time_gap; + full_time(2,inner_loop+meta_dum-1-emptycount_inner-emptycount_outer)= images{inner_loop,4}; + full_time(3,inner_loop+meta_dum-1-emptycount_inner-emptycount_outer)= images{inner_loop+time_loop,4}; + + else + emptycount_inner = emptycount_inner + 1; + end + + end +emptycount_outer = emptycount_outer + emptycount_inner; +emptycount_inner = 0; +meta_dum = meta_dum + inputs.numimages-time_loop-1; +array_pos = array_pos + 1; +end + + +% For each velocity matrix, calculate which months it is located in, and +% fraction in each month + +for velocity_matrix_loop = 1:size(images_stack{1,2},1) + + %work out percentage in each month + + if year(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum'))== year(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum'))... + && month(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum'))== month(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')) + % IF the matrix is ENTIRELY within one month. + + local_year = year(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum')); + + local_month = month(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum')); + + position_in_array = 12*(local_year-first_year) + local_month-first_month + 1; + + month_percent{position_in_array+1,velocity_matrix_loop+2} = 1; + + elseif (year(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum'))== year(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum'))... + && month(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum'))+1== month(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')))||... + (year(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum'))+1== year(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')) ... + && month(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum'))-11 == month(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum'))) + %IF the matrix is entirely within TWO months. The OR is to account + %for if the start and end are in two different years. + + local_year_first = year(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum')); + + local_month_first = month(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum')); + + position_in_array_first = 12*(local_year_first-first_year) + local_month_first-first_month + 1; + + local_year_last = year(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')); + + local_month_last = month(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')); + + position_in_array_last = 12*(local_year_last-first_year) + local_month_last-first_month + 1; + + start_last_month = datenum(local_year_last,local_month_last,01); + + percentage_last_month = (full_time(3,velocity_matrix_loop)-start_last_month+0.5)/full_time(1,velocity_matrix_loop); + + month_percent{position_in_array_first+1,velocity_matrix_loop+2} = 1-percentage_last_month; + + month_percent{position_in_array_last+1,velocity_matrix_loop+2} = percentage_last_month; + + else + %If spans more than two months + + local_year_first = year(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum')); + + local_month_first = month(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum')); + + position_in_array_first = 12*(local_year_first-first_year) + local_month_first-first_month + 1; + + local_year_last = year(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')); + + local_month_last = month(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')); + + position_in_array_last = 12*(local_year_last-first_year) + local_month_last-first_month + 1; + + if local_month_first~=12 + end_first_month = datenum(local_year_first,local_month_first+1,01)-1; + else + end_first_month = datenum(local_year_first+1,1,01)-1; + end + + start_last_month = datenum(local_year_last,local_month_last,01); + + percentage_first_month =(end_first_month - full_time(2,velocity_matrix_loop)+0.5)/full_time(1,velocity_matrix_loop); + + percentage_last_month = (full_time(3,velocity_matrix_loop)-start_last_month+0.5)/full_time(1,velocity_matrix_loop); + + month_percent{position_in_array_first+1,velocity_matrix_loop+2} = percentage_first_month; + + month_percent{position_in_array_last+1,velocity_matrix_loop+2} = percentage_last_month; + + for percentage_loop = position_in_array_first+1:position_in_array_last-1 + month_percent{percentage_loop+1,velocity_matrix_loop+2} = (1-percentage_first_month-percentage_last_month)/(position_in_array_last-position_in_array_first-1); + end + + + end %if loops end + + +end %end velocity matrix loop + + + +global_standard_deviation_lin = reshape(images_stack{5,2},[1,inputs.sizevel(1)*inputs.sizevel(2)]); + +%%%%% Outside iterative loop + +for iterations = 1:inputs.nummonthiter + + %Create temporary matrix to read values into + + monthly_averages_temp = num2cell(NaN(size(monthly_averages))); + + %inner loop to loop between different months + for month_loop = 1:size(monthly_averages,1) + + %Create shell matrix to store data for this month + + %How many values overlap with this month? + value_counter = 0; + for i = 1:size(images_stack{1,2},1) + if ~isnan(month_percent{month_loop+1,i+2}) + value_counter = value_counter+1; + end + end + + one_month_v_temp = NaN(value_counter,inputs.sizevel(1)*inputs.sizevel(2)); + one_month_fd_temp = NaN(value_counter,inputs.sizevel(1)*inputs.sizevel(2)); + + numbering_system_temp = 1; + + %Second tier of loop to loop through velocity matrices + for velocity_matrix_loop = 1:size(images_stack{1,2},1) + + + + if ~isnan(month_percent{month_loop+1,velocity_matrix_loop+2}) + + + + + if year(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum'))== year(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum'))... + && month(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum'))== month(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')) + % IF the matrix is ENTIRELY within one month. + +% mask_lin = reshape(mask,[1,inputs.sizevel(1)*inputs.sizevel(2)]); + + one_month_v_temp(numbering_system_temp,:) = images_stack{1,2}(velocity_matrix_loop,:); + one_month_fd_temp(numbering_system_temp,:) = images_stack{2,2}(velocity_matrix_loop,:); + +% numbering_system_temp = numbering_system_temp+1; + + elseif (year(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum'))== year(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum'))... + && month(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum'))+1== month(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')))||... + (year(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum'))+1== year(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')) ... + && month(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum'))-11 == month(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum'))) + %IF the matrix is entirely within TWO months. The OR is to account + %for if the start and end are in two different years. + + local_year_first = year(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum')); + + local_month_first = month(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum')); + + position_in_array_first = 12*(local_year_first-first_year) + local_month_first-first_month + 1; + + local_year_last = year(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')); + + local_month_last = month(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')); + + position_in_array_last = position_in_array_first + 1; + + start_last_month = datenum(local_year_last,local_month_last,01); + + percentage_last_month = (full_time(3,velocity_matrix_loop)-start_last_month+0.5)/full_time(1,velocity_matrix_loop); + + month_percent{position_in_array_first+1,velocity_matrix_loop+2} = 1-percentage_last_month; + + month_percent{position_in_array_last+1,velocity_matrix_loop+2} = percentage_last_month; + + + + + + if month_loop == position_in_array_first + + temp_v_matrix = images_stack{1,2}(velocity_matrix_loop,:); + + temp_fd_matrix = images_stack{2,2}(velocity_matrix_loop,:); + + extra_v_matrix = reshape(monthly_averages{position_in_array_last,3},[1,inputs.sizevel(1)*inputs.sizevel(2)]); + + extra_fd_matrix = reshape(monthly_averages{position_in_array_last,4},[1,inputs.sizevel(1)*inputs.sizevel(2)]); + + %We have this month * this weight + other month * other weight = + %total + + %So this month = (total - (other month * other weight)) / this weight + + %replace NaNs in other month + + for i = 1:inputs.sizevel(1)*inputs.sizevel(2) + if isnan(extra_v_matrix(:,i)) && ~isnan(temp_v_matrix(:,i)) + extra_v_matrix(:,i) = temp_v_matrix(:,i); + extra_fd_matrix(:,i) = temp_fd_matrix(:,i); + elseif isnan(temp_v_matrix(:,i)) && ~isnan(extra_v_matrix(:,i)) + extra_v_matrix(:,i) = NaN; + extra_fd_matrix(:,i) = NaN; + end + end + + one_month_v_temp(numbering_system_temp,:) = (temp_v_matrix - (extra_v_matrix * percentage_last_month))/(1-percentage_last_month); + + for i = 1:inputs.sizevel(1)*inputs.sizevel(2) + if abs(extra_fd_matrix(:,i)-temp_fd_matrix(:,i))>270 || abs(temp_fd_matrix(:,i)-extra_fd_matrix(:,i))>270 + + if extra_fd_matrix(:,i) > temp_fd_matrix(:,i) + temp_fd_matrix(:,i) = temp_fd_matrix(:,i)+360; + else + extra_fd_matrix(:,i) = extra_fd_matrix(:,i) + 360; + end + + one_month_fd_temp(numbering_system_temp,i) = (temp_fd_matrix(:,i) - (extra_fd_matrix(:,i) * percentage_last_month))/(1-percentage_last_month); + if one_month_fd_temp(numbering_system_temp,i) > 360 + one_month_fd_temp(numbering_system_temp,i) = one_month_fd_temp(numbering_system_temp,i) - 360 ; + end + + else + one_month_fd_temp(numbering_system_temp,i) = (temp_fd_matrix(:,i) - (extra_fd_matrix(:,i) * percentage_last_month))/(1-percentage_last_month); + end + + end + + elseif month_loop == position_in_array_last + + temp_v_matrix = images_stack{1,2}(velocity_matrix_loop,:); + + temp_fd_matrix = images_stack{2,2}(velocity_matrix_loop,:); + + extra_v_matrix = reshape(monthly_averages{position_in_array_first,3},[1,inputs.sizevel(1)*inputs.sizevel(2)]); + + extra_fd_matrix = reshape(monthly_averages{position_in_array_first,4},[1,inputs.sizevel(1)*inputs.sizevel(2)]); + + %We have this month * this weight + other month * other weight = + %total + + %So this month = (total - (other month * other weight)) / this weight + + %replace NaNs in other month + + for i = 1:inputs.sizevel(1)*inputs.sizevel(2) + if isnan(extra_v_matrix(:,i)) && ~isnan(temp_v_matrix(:,i)) + extra_v_matrix(:,i) = temp_v_matrix(:,i); + extra_fd_matrix(:,i) = temp_fd_matrix(:,i); + elseif isnan(temp_v_matrix(:,i)) && ~isnan(extra_v_matrix(:,i)) + extra_v_matrix(:,i) = NaN; + extra_fd_matrix(:,i) = NaN; + end + end + + one_month_v_temp(numbering_system_temp,:) = (temp_v_matrix - (extra_v_matrix * (1-percentage_last_month)))/(percentage_last_month); + + for i = 1:inputs.sizevel(1)*inputs.sizevel(2) + if abs(extra_fd_matrix(:,i)-temp_fd_matrix(:,i))>270 || abs(temp_fd_matrix(:,i)-extra_fd_matrix(:,i))>270 + + if extra_fd_matrix(:,i) > temp_fd_matrix(:,i) + temp_fd_matrix(:,i) = temp_fd_matrix(:,i)+360; + else + extra_fd_matrix(:,i) = extra_fd_matrix(:,i) + 360; + end + + one_month_fd_temp(numbering_system_temp,i) = (temp_fd_matrix(:,i) - (extra_fd_matrix(:,i) * (1-percentage_last_month)))/(percentage_last_month); + if one_month_fd_temp(numbering_system_temp,i) > 360 + one_month_fd_temp(numbering_system_temp,i) = one_month_fd_temp(numbering_system_temp,i) - 360 ; + end + + else + one_month_fd_temp(numbering_system_temp,i) = (temp_fd_matrix(:,i) - (extra_fd_matrix(:,i) * (1-percentage_last_month)))/(percentage_last_month); + end + + end + + end %end if month loop... + + %calculate mean of nearby months. std doesn't work with too few + temp_mean(1,:) = temp_v_matrix; temp_mean(2,:) = extra_v_matrix; + + mean_months = nanmean(temp_mean,1); + + + + %loop (I am sure there is a more computationally efficient method + %here, revisit) + for findoutlier = 1:inputs.sizevel(1)*inputs.sizevel(2) + if ~isnan(one_month_v_temp(numbering_system_temp,findoutlier)) + if one_month_v_temp(numbering_system_temp,findoutlier) < 0 ||... + one_month_v_temp(numbering_system_temp,findoutlier) < (mean_months(1,findoutlier) - 3 * global_standard_deviation_lin(1,findoutlier)) ||... + one_month_v_temp(numbering_system_temp,findoutlier) > (mean_months(1,findoutlier) + 3 * global_standard_deviation_lin(1,findoutlier)) + + one_month_v_temp(numbering_system_temp,findoutlier) = NaN; + one_month_fd_temp(numbering_system_temp,findoutlier) = NaN; + + end + + end + end %end findoutlier loop + + one_month_v_temp(numbering_system_temp,:) = reshape(nanfillsm(reshape(nanmean(one_month_v_temp(numbering_system_temp,:),1)... + ,inputs.sizevel),inputs,2,2),[1,inputs.sizevel(1)*inputs.sizevel(2)]); %fill some of the NaNs + +% numbering_system_temp = numbering_system_temp+1; + + else + %If spans more than two months + + local_year_first = year(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum')); + + local_month_first = month(datetime(full_time(2,velocity_matrix_loop),'ConvertFrom','datenum')); + + position_in_array_first = 12*(local_year_first-first_year) + local_month_first-first_month + 1; + + local_year_last = year(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')); + + local_month_last = month(datetime(full_time(3,velocity_matrix_loop),'ConvertFrom','datenum')); + + position_in_array_last = 12*(local_year_last-first_year) + local_month_last-first_month + 1; + + if local_month_first~=12 + end_first_month = datenum(local_year_first,local_month_first+1,01)-1; + else + end_first_month = datenum(local_year_first+1,1,01)-1; + end + + start_last_month = datenum(local_year_last,local_month_last,01); + + percentage_first_month =(end_first_month - full_time(2,velocity_matrix_loop)+0.5)/full_time(1,velocity_matrix_loop); + + percentage_last_month = (full_time(3,velocity_matrix_loop)-start_last_month+0.5)/full_time(1,velocity_matrix_loop); + + month_percent{position_in_array_first+1,velocity_matrix_loop+2} = percentage_first_month; + + month_percent{position_in_array_last+1,velocity_matrix_loop+2} = percentage_last_month; + +% for percentage_loop = position_in_array_first+1:position_in_array_last-1 +% month_percent{percentage_loop+1,velocity_matrix_loop+2} = (1-percentage_first_month-percentage_last_month)/(position_in_array_last-position_in_array_first-1); +% end + + + + %We have this month * this weight + other month * other weight + ... = + %total + + %So this month = (total - (other month * other weight)-...) / this weight + + %replace NaNs in other month + + temp_v_matrix = images_stack{1,2}(velocity_matrix_loop,:); %total + + temp_fd_matrix = images_stack{2,2}(velocity_matrix_loop,:); %total + + temp_v_matrix_partial = temp_v_matrix; + + temp_fd_matrix_partial = temp_fd_matrix; + + previous_iteration_averages_array_v = NaN((position_in_array_last-position_in_array_first)+1,inputs.sizevel(1)*inputs.sizevel(2)); + previous_iteration_averages_array_fd = NaN((position_in_array_last-position_in_array_first)+2,inputs.sizevel(1)*inputs.sizevel(2)); + + for i = position_in_array_first:position_in_array_last + if i ~= month_loop %not for current month + previous_iteration_averages_array_v(i,:) = reshape(monthly_averages{i,3},[1,inputs.sizevel(1)*inputs.sizevel(2)]); + previous_iteration_averages_array_fd(i+1,:) = reshape(monthly_averages{i,4},[1,inputs.sizevel(1)*inputs.sizevel(2)]); + + + for innerloop = 1:inputs.sizevel(1)*inputs.sizevel(2) %make NaNs same as temp matrix + if isnan(previous_iteration_averages_array_v(i,innerloop)) && ~isnan(temp_v_matrix(1,innerloop)) + previous_iteration_averages_array_v(i,innerloop) = temp_v_matrix(1,innerloop); + previous_iteration_averages_array_fd(i+1,innerloop) = temp_fd_matrix(1,innerloop); + elseif isnan(temp_v_matrix(1,innerloop)) && ~isnan(previous_iteration_averages_array_v(i,innerloop)) + previous_iteration_averages_array_v(i,innerloop) = NaN; + previous_iteration_averages_array_fd(i+1,innerloop) = NaN; + end + end + + + temp_v_matrix_partial = temp_v_matrix_partial - (previous_iteration_averages_array_v(i,:)*month_percent{i+1,velocity_matrix_loop+2}); + %cant do quite this for fd, do it in new loop + + end + end + + one_month_v_temp(numbering_system_temp,:) = temp_v_matrix_partial/month_percent{month_loop+1,velocity_matrix_loop+2}; + + + %Work it out for FLOW DIRECTION + + previous_iteration_averages_array_fd(1,:) = temp_fd_matrix_partial; + + for i = 1:inputs.sizevel(1)*inputs.sizevel(2) + if (max(previous_iteration_averages_array_fd(:,i))- min(previous_iteration_averages_array_fd(:,i)))>270 + + for inner_loop = 1:size(previous_iteration_averages_array_fd,1) + if previous_iteration_averages_array_fd(inner_loop,i) < 90 + previous_iteration_averages_array_fd(inner_loop,i) = previous_iteration_averages_array_fd(inner_loop,i) + 360; + end + end + + for inner_loop = 2:size(previous_iteration_averages_array_fd,1) + + previous_iteration_averages_array_fd(1,i) = previous_iteration_averages_array_fd(1,i) -... + (previous_iteration_averages_array_fd(inner_loop,i)*month_percent{inner_loop,velocity_matrix_loop+2}); + + end + + previous_iteration_averages_array_fd(1,i) = previous_iteration_averages_array_fd(1,i) / month_percent{month_loop+1,velocity_matrix_loop+2}; + + if previous_iteration_averages_array_fd(1,i) > 360 + one_month_fd_temp(numbering_system_temp,i) = previous_iteration_averages_array_fd(1,i) - 360 ; + else + one_month_fd_temp(numbering_system_temp,i) = previous_iteration_averages_array_fd(1,i); + end + + end + end + + % Find outliers + + %calculate mean of nearby months. std doesn't work with too few + mean_months = nanmean(previous_iteration_averages_array_v,1); + + + + %loop (I am sure there is a more computationally efficient method + %here, revisit) + for findoutlier = 1:inputs.sizevel(1)*inputs.sizevel(2) + if ~isnan(one_month_v_temp(numbering_system_temp,findoutlier)) + if one_month_v_temp(numbering_system_temp,findoutlier) < 0 ||... + one_month_v_temp(numbering_system_temp,findoutlier) < (mean_months(1,findoutlier) - 3 * global_standard_deviation_lin(1,findoutlier)) ||... + one_month_v_temp(numbering_system_temp,findoutlier) > (mean_months(1,findoutlier) + 3 * global_standard_deviation_lin(1,findoutlier)) + + one_month_v_temp(numbering_system_temp,findoutlier) = NaN; + one_month_fd_temp(numbering_system_temp,findoutlier) = NaN; + + end + + end + end %end findoutlier loop + + one_month_v_temp(numbering_system_temp,:) = reshape(nanfillsm(reshape(nanmean(one_month_v_temp(numbering_system_temp,:),1)... + ,inputs.sizevel),inputs,2,2),[1,inputs.sizevel(1)*inputs.sizevel(2)]); %fill some of the NaNs + +% numbering_system_temp = numbering_system_temp+1; + + end %if loops end + + + numbering_system_temp = numbering_system_temp+1; + + end %end of ~isnan if condition + end %end of velocity matrix loop + + monthly_averages_temp{month_loop,3} = (reshape(nanmean(one_month_v_temp,1),inputs.sizevel)); %take mean and reshape to right size + + monthly_averages_temp{month_loop,4} = (reshape(nanmean(one_month_fd_temp,1),inputs.sizevel)); %take mean and reshape to right size + + end %end of month loop + + %replace old MONTHLY AVERAGES with new ones from this iteration[ + + for i = 1:size(monthly_averages,1) + monthly_averages{i,3} = monthly_averages_temp{i,3}; %replace velocities + monthly_averages{i,4} = monthly_averages_temp{i,4}; %replace flow directions + end + +end % end of iterative loop + + + for i = 1:size(monthly_averages,1) %Infill isolated NaNs and do some slight smoothing + monthly_averages{i,3} = nanfillsm(monthly_averages{i,3}, inputs, 3, 3); + monthly_averages{i,4} = nanfillsm(monthly_averages{i,4}, inputs, 3, 3); + end + + +end + + + + + + + + + + + + + + diff --git a/functions/other/loadtseries.m b/functions/other/loadtseries.m new file mode 100644 index 0000000..d301be1 --- /dev/null +++ b/functions/other/loadtseries.m @@ -0,0 +1,169 @@ +function [images,inputs]=loadtseries(inputs) +%% load images +% +% Images to be tracked should be located in one single folder, and named +% with the following convention "yyyymmdd". This format is the most +% convinient for archiving time series, as images will sort into order. +% +%Any deviation from this naming convention will result in the images not +%being picked up correctly. +% +%Ideally at this point the images should be correctly georeferences +%(covering the same area). Downloaded Sentinel2 scenes should naturally +%have this property. Other images may need manually colocating in a GIS +%program prior to processing. +% +% +% Specify the folder where the files live. Copy paste the path from file +% explorer for example. An error message will be returned if it is somehow +% misspelt. +% +%Specify the first year of the timeseries (eg:2011) and the last year (eg: +%2017). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +% Check to make sure that folder actually exists. Warn user if it doesn't. +if ~isdir(inputs.folder) + errorMessage = sprintf('Error: The following folder does not exist:\n%s', inputs.folder); + uiwait(warndlg(errorMessage)); + return; +end + +%The correct folder should now be located. The objective of the following +%loop is to read the images from the folder into an array named 'images' +%and extract relevant metadata. + +images = {}; % create an empty cell array to store everything +%name columns for future clarity +images{1,1} = 'Image Number'; +images{1,2} = 'Image Date'; +images{1,3} = 'Image masked'; +images{1,4} = 'Date code'; +images{1,5} = 'Days from beginning'; +images{1,6} = 'Interval in years'; +k = 2; % index into cell array for next read image + + +%load animate images +for y=inputs.minyear:inputs.maxyear + y = num2str(y); + for m=inputs.minmonth:inputs.maxmonth + if m < 10 + m = strcat('0',num2str(m)); + else + m = num2str(m); + end + + for d=inputs.minday:inputs.maxday + if d < 10 + d = strcat('0',num2str(d)); + else + d = num2str(d); + end + if strcmpi(inputs.isgeotiff,'No') + datejpg = strcat(y,m,d,'.jpg'); + datepng = strcat(y,m,d,'.png'); + if exist(fullfile(inputs.folder, datejpg),'file') + % read k onto first column + % read date into second column + % read the image into the kth position of the cell array on the + % third column + %create n_day, the number of days between different images + n_day = datenum(str2num(y),str2num(m),str2num(d)); + %load n_day to fouth column + images{k,1}=k; + images{k,2}=(strcat(y,m,d)); + images{k,3}=(imread(fullfile(inputs.folder,datejpg))); + images{k,4}=n_day; + % increment k for the next iteration + k=k+1; + elseif exist(fullfile(inputs.folder, datepng),'file') + % read k onto first column + % read date into second column + % read the image into the kth position of the cell array on the + % third column + %create n_day, the number of days between different images + n_day = datenum(str2num(y),str2num(m),str2num(d)); + %load n_day to fouth column + images{k,1}=k; + images{k,2}=(strcat(y,m,d)); + images{k,3}=(imread(fullfile(inputs.folder,datepng))); + images{k,4}=n_day; + % increment k for the next iteration + k=k+1; + + end + else + datetif = strcat(y,m,d,'.tif'); + + if exist(fullfile(inputs.folder, datetif),'file') + n_day = datenum(str2num(y),str2num(m),str2num(d)); + %load n_day to fouth column + images{k,1}=k; + images{k,2}=(strcat(y,m,d)); + images{k,3}=(imread(fullfile(inputs.folder,datetif))); + images{k,4}=n_day; + % increment k for the next iteration + k=k+1; + gooddatetif = datetif; + end + + end + end + end +end + +if strcmpi(inputs.isgeotiff,'Yes') +inputs.geotifflocationdata = geotiffinfo(fullfile(inputs.folder,gooddatetif)); +[~,inputs.geotiffreference] = geotiffread(fullfile(inputs.folder,gooddatetif)); +end + +size_tocrop = size(images); +num_images = size_tocrop(1); + +% inputs.folder = 'Number of Images + 1'; +inputs.numimages = num_images; + +%this loop extracts the number of days that have passed for a given image +%since the first image in the series +for l = 2:(num_images) + images{l,5} = images{l,4} - images{2,4}; + l=l+1; +end + +%This loop extracts the number of days between succesive images from the +%previous result. This information is necessary to calculate ice velocity. +for c = 2:num_images + if c < 3 + images{c,6} = 0; + else + c_2 = c-1; + images{c,6} = (images{c,5}(1) - images{c_2,5}(1))/365; + end + c = c+1; +end + +% At this point all the data we need should be loaded into one array, +% called 'images'. +% We can call the images, image time spacing, etc from this array. diff --git a/functions/other/myfilter.m b/functions/other/myfilter.m new file mode 100644 index 0000000..6f5c6f1 --- /dev/null +++ b/functions/other/myfilter.m @@ -0,0 +1,68 @@ +function out = myfilter(in, inputs) +%Exit file is a matrix the size of the input with 0 where no outlier was +%detected and 1 where an outlier was detected. Used to filter out poorly +%matched velocity values. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + +out = zeros(size(in)); + %% Maximum velocity filter + + %Firstly points with too fast velocities +ofilter = out; +out(in>inputs.maxvel) = 1; + +%% Lowpass filter outlier detection + +%Local, small filter area +nanX = isnan(in); +in(nanX) = 0; +mask = [0 1 0; 1 0 1; 0 1 0]; +in2 = conv2(in, mask, 'same') ./ ... + conv2(~nanX, mask, 'same'); + +in_diff = abs(in2 - in)./in; +out(in_diff>0.3)=1; %cannot be more than 30% different from mean of immediate neighbours + +%Larger area filter +nanX = isnan(in); +in(nanX) = 0; +mask = [0 0 0 1 0 0 0; 0 0 1 1 1 0 0; 1 1 1 1 1 1 1; 1 1 1 1 1 1 1; 1 1 1 1 1 1 1; 0 0 1 1 1 0 0; 0 0 0 1 0 0 0]; +in2 = conv2(in, mask, 'same') ./ ... + conv2(~nanX, mask, 'same'); + +in_diff = abs(in2 - in)./in; +out(in_diff>1.00)=1; %cannot be more than 100% different from regional mean + +%% Moving median and percentile detection (if needed) +% % +% % Out_param1 =~isoutlier(in,'movmedian',5); +% % +% % Out_param2 =~isoutlier(in,'percentiles',[0 100]); +% % +% % out(Out_param1 == 0) = 1; +% % +% % out(Out_param2 == 0) = 1; +% % + +out(in==0)=0; + diff --git a/functions/other/nancirc_mean.m b/functions/other/nancirc_mean.m new file mode 100644 index 0000000..96358c4 --- /dev/null +++ b/functions/other/nancirc_mean.m @@ -0,0 +1,54 @@ +function [mu ul ll] = nancirc_mean(alpha, dim, w) +% +% mu = circ_mean(alpha, w) +% Computes the mean direction for circular data. +% +% Input: +% alpha sample of angles in radians +% [w weightings in case of binned angle data] +% +% Output: +% mu mean direction +% ul upper 95% confidence limit +% ll lower 95% confidence limit +% +% PHB 7/6/2008 +% +% References: +% Statistical analysis of circular data, N. I. Fisher +% Topics in circular statistics, S. R. Jammalamadaka et al. +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +% check vector size +% if size(alpha,2) > size(alpha,1) +% alpha = alpha'; +% end + +if nargin<3 + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else +% if size(w,2) > size(w,1) +% w = w'; +% end +end + +% compute weighted sum of cos and sin of angles +% r = w'*exp(1i*alpha); +r = nancov_circ(w,exp(1i*alpha),dim); %*size(alpha,1) + +% obtain mean by +mu = angle(r); + +% % confidence limits if desired %Add file from toolbox if needed +% if nargout > 1 +% t = circ_confmean(alpha,0.05,w); +% ul = mu + t; +% ll = mu - t; +% end \ No newline at end of file diff --git a/functions/other/nancirc_r.m b/functions/other/nancirc_r.m new file mode 100644 index 0000000..4e9bc9a --- /dev/null +++ b/functions/other/nancirc_r.m @@ -0,0 +1,61 @@ +function r = circ_r(alpha, dim, w, d) +% r = circ_r(alpha, w, d) +% Computes mean resultant vector length for circular data. +% +% Input: +% alpha sample of angles in radians +% [w number of incidences in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r, in radians (!)] +% +% Output: +% r mean resultant length +% +% PHB 7/6/2008 +% +% References: +% Statistical analysis of circular data, N.I. Fisher +% Topics in circular statistics, S.R. Jammalamadaka et al. +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +% check vector size +% if size(alpha,2) > size(alpha,1) +% alpha = alpha'; +% end + +if nargin<3 + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +% else +% if size(w,2) > size(w,1) +% w = w'; +% end +end + +if nargin<3 + % per default do not apply correct for binned data + d = 0; +end + +% compute weighted sum of cos and sin of angles +% r = w'*exp(1i*alpha); +r = nancov_circ(w,exp(1i*alpha),dim); + +% obtain length +% r = abs(r)/sum(w,dim); +r = abs(r);%./sum(w,dim); + +% for data with known spacing, apply correction factor to correct for bias +% in the estimation of r (see Zar, p. 601, equ. 26.16) +if d ~= 0 + c = d/2/sin(d/2); + r = c*r; +end + diff --git a/functions/other/nancirc_std.m b/functions/other/nancirc_std.m new file mode 100644 index 0000000..a8ec146 --- /dev/null +++ b/functions/other/nancirc_std.m @@ -0,0 +1,58 @@ +function [s s0] = nancirc_std(alpha,dim, w, d) +% s = circ_std(alpha, w, d) +% Computes circular standard deviation for circular data +% (equ. 26.20, Zar). +% +% Input: +% alpha sample of angles in radians +% [w weightings in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r] +% +% Output: +% s angular deviation +% s circular standard deviation +% +% PHB 6/7/2008 +% +% References: +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +% check vector size +% if size(alpha,2) > size(alpha,1) +% alpha = alpha'; +% end + +if nargin<3 || isempty(w) + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); + d = 0; +else +% w = w(:); +d = 0; +end + +% if nargin<3 || isempty(d) +% % per default do not apply correction for binned data +% d = 0; +% end + +if nargin<4 + type = 'std'; +end + +% compute mean resultant vector length +r = nancirc_r(alpha,dim,w,d); + +s = sqrt(2*(1-r)); % 26.20 +s0 = sqrt(-2*log(r)); % 26.21 + + + diff --git a/functions/other/nancircstat/Contents.m b/functions/other/nancircstat/Contents.m new file mode 100644 index 0000000..3e0851c --- /dev/null +++ b/functions/other/nancircstat/Contents.m @@ -0,0 +1,57 @@ +% CircStat Toolbox +% Toolbox for circular statistics with Matlab +% +% Descriptive Statistics. +% circ_mean - Mean direction of a sample of circular data +% circ_median - Median direction of a sample of circular data +% circ_r - Resultant vector length +% circ_var - Circular variance +% circ_std - Circular standard deviation +% circ_moment - Circular p-th moment +% circ_skewness - Circular skewness +% circ_kurtosis - Circular kurtosis +% +% Inferential Statistics. +% Testing for Circular Uniformity. +% circ_rtest - Rayleigh's test for nonuniformity +% circ_otest - Hodges-Ajne test (omnibus test) for nonuniformity +% circ_raotest - Rao's spacing test for nonuniformity +% circ_vtest - V-Test for nonuniformity with known mean direction +% +% Tests Concerning Mean and Median. +% circ_confmean - Confidence intervals for mean direction +% circ_mtest - One-sample test for specified mean direction +% circ_medtest - Test for median angle +% circ_symtest - Test for symmetry around median angle +% +% Paired and Multisample Tests. +% circ_wwtest - Two and multi-sample test for equal means; +% one-factor ANOVA +% circ_hktest - Two-factor ANOVA +% circ_cmtest - Non-parametric multi-sample test for equal medians +% +% Measures of Association. +% circ_corrcc - Circular-circular correlation coefficient +% circ_corrcl - Circular-linear correlation coefficient +% +% The Von Mises Distribution +% circ_vmpdf - Probability density function of the von Mises +% distribution +% circ_vmpar - Parameter estimation +% circ_vmrnd - Random number generation +% +% Others. +% circ_axial - Convert axial data to common scale +% circ_dist - Distances around a circle +% circ_dist2 - Pairwise distances around a circle +% circ_stats - Summary statistics +% circ_kappa - Compute concentration parameter of a VM distribution +% circ_plot - Visualization for circular data +% circ_rad2ang - Convert radian to angular values +% circ_ang2rad - Convert angular to radian values +% +% +% +% Author: +% Philipp Berens, 2009 + diff --git a/functions/other/nancircstat/circ_axial.m b/functions/other/nancircstat/circ_axial.m new file mode 100644 index 0000000..57378b3 --- /dev/null +++ b/functions/other/nancircstat/circ_axial.m @@ -0,0 +1,29 @@ +function alpha = circ_axial(alpha, p) +% +% alpha = circ_axial(alpha, p) +% Transforms p-axial data to a common scale. +% +% Input: +% alpha sample of angles in radians +% [p number of modes] +% +% Output: +% alpha transformed data +% +% PHB 2009 +% +% References: +% Statistical analysis of circular data, N. I. Fisher +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + + + +if nargin < 2 + p = 1; +end + +alpha = mod(alpha*p,2*pi); diff --git a/functions/other/nancircstat/circ_cmtest.m b/functions/other/nancircstat/circ_cmtest.m new file mode 100644 index 0000000..59145fa --- /dev/null +++ b/functions/other/nancircstat/circ_cmtest.m @@ -0,0 +1,90 @@ +function [pval med P] = circ_cmtest(varargin) +% +% [pval, med, P] = circ_cmtest(alpha, idx) +% [pval, med, P] = circ_cmtest(alpha1, alpha2) +% Non parametric multi-sample test for equal medians. Similar to a +% Kruskal-Wallis test for linear data. +% +% H0: the s populations have equal medians +% HA: the s populations have unequal medians +% +% Input: +% alpha angles in radians +% idx indicates which population the respective angle in alpha +% comes from, 1:s +% +% Output: +% pval p-value of the common median multi-sample test. Discard H0 if +% pval is small. +% med best estimate of shared population median if H0 is not +% discarded at the 0.05 level and NaN otherwise. +% P test statistic of the common median test. +% +% +% PHB 7/19/2009 +% +% References: +% Fisher NI, 1995 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +[alpha, idx] = processInput(varargin{:}); + +% number of groups +u = unique(idx); +s = length(u); + +% number of samples +N = length(idx); + +% total median +med = circ_median(alpha); + +% compute relevant quantitites +n = zeros(s,1); m = n; +for t=1:s + pidx = idx == u(t); + n(t) = sum(pidx); + + d = circ_dist(alpha(pidx),med); + + m(t) = sum(d<0); +end + +if any(n<10) + warning('Test not applicable. Sample size in at least one group to small.') %#ok +end + + +M = sum(m); +P = (N^2/(M*(N-M))) * sum(m.^2 ./ n) - N*M/(N-M); + +pval = 1 - chi2cdf(P,s-1); + +if pval < 0.05 + med = NaN; +end + + + + +function [alpha, idx] = processInput(varargin) + +if nargin==2 && sum(abs(round(varargin{2})-varargin{2}))>1e-5 + alpha1 = varargin{1}(:); + alpha2 = varargin{2}(:); + alpha = [alpha1; alpha2]; + idx = [ones(size(alpha1)); 2*ones(size(alpha2))]; +elseif nargin==2 + alpha = varargin{1}(:); + idx = varargin{2}(:); + if ~(size(idx,1)==size(alpha,1)) + error('Input dimensions do not match.') + end +else + error('Invalid use of circ_wwtest. Type help circ_wwtest.') +end + diff --git a/functions/other/nancircstat/circ_confmean.m b/functions/other/nancircstat/circ_confmean.m new file mode 100644 index 0000000..03ea9cb --- /dev/null +++ b/functions/other/nancircstat/circ_confmean.m @@ -0,0 +1,82 @@ +function t = circ_confmean(alpha, xi, w, d) +% +% t = circ_mean(alpha, xi, w, d) +% Computes the confidence limits on the mean for circular data. +% +% Input: +% alpha sample of angles in radians +% [xi (1-xi)-confidence limits are computed, default 0.05] +% [w number of incidences in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r, in radians (!)] + +% +% Output: +% t mean +- d yields upper/lower (1-xi)% confidence limit +% +% PHB 7/6/2008 +% +% References: +% Statistical analysis of circular data, N. I. Fisher +% Topics in circular statistics, S. R. Jammalamadaka et al. +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + + +% check vector size +% if size(alpha,2) > size(alpha,1) +% alpha = alpha'; +% end + +% set confidence limit size to default +if nargin<2 || isempty(xi) + xi = 0.05; +end + +if nargin<3 + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else +% if size(w,2) > size(w,1) +% w = w'; +% end + + if length(alpha)~=length(w) + error('Input dimensions do not match.') + end + +end + +if nargin<4 + % per default do not apply correct for binned data + d = 0; +end + +% compute ingredients for conf. lim. +r = circ_r(alpha,w,d); +n = sum(w); +R = n*r; +c2 = chi2inv((1-xi),1); + +% check for resultant vector length and select appropriate formula +if r < .9 && r > sqrt(c2/2/n) + t = sqrt((2*n*(2*R^2-n*c2))/(4*n-c2)); % equ. 26.24 +elseif r >= .9 + t = sqrt(n^2-(n^2-R^2)*exp(c2/n)); % equ. 26.25 +else + t = NaN; + warning('Resultant vector does not allow to specify confidence limits on mean. \nResults may be wrong or inaccurate.'); +end + +% apply final transform +t = acos(t/R); + + + + diff --git a/functions/other/nancircstat/circ_corrcc.m b/functions/other/nancircstat/circ_corrcc.m new file mode 100644 index 0000000..68715ab --- /dev/null +++ b/functions/other/nancircstat/circ_corrcc.m @@ -0,0 +1,53 @@ +function [rho pval] = circ_corrcc(alpha1, alpha2) +% +% [rho pval ts] = circ_corrcc(alpha1, alpha2) +% Circular correlation coefficient for two circular random variables. +% +% Input: +% alpha1 sample of angles in radians +% alpha2 sample of angles in radians +% +% Output: +% rho correlation coefficient +% pval p-value +% +% References: +% Topics in circular statistics, S.R. Jammalamadaka et al., p. 176 +% +% PHB 6/7/2008 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if size(alpha1,2) > size(alpha1,1) + alpha1 = alpha1'; +end + +if size(alpha2,2) > size(alpha2,1) + alpha2 = alpha2'; +end + +if length(alpha1)~=length(alpha2) + error('Input dimensions do not match.') +end + +% compute mean directions +n = length(alpha1); +alpha1_bar = circ_mean(alpha1); +alpha2_bar = circ_mean(alpha2); + +% compute correlation coeffcient from p. 176 +num = sum(sin(alpha1 - alpha1_bar) .* sin(alpha2 - alpha2_bar)); +den = sqrt(sum(sin(alpha1 - alpha1_bar).^2) .* sum(sin(alpha2 - alpha2_bar).^2)); +rho = num / den; + +% compute pvalue +l20 = mean(sin(alpha1 - alpha1_bar).^2); +l02 = mean(sin(alpha2 - alpha2_bar).^2); +l22 = mean((sin(alpha1 - alpha1_bar).^2) .* (sin(alpha2 - alpha2_bar).^2)); + +ts = sqrt((n * l20 * l02)/l22) * rho; +pval = 2 * (1 - normcdf(abs(ts))); + diff --git a/functions/other/nancircstat/circ_corrcl.m b/functions/other/nancircstat/circ_corrcl.m new file mode 100644 index 0000000..113a0d5 --- /dev/null +++ b/functions/other/nancircstat/circ_corrcl.m @@ -0,0 +1,50 @@ +function [rho pval] = circ_corrcl(alpha, x) +% +% [rho pval ts] = circ_corrcc(alpha, x) +% Correlation coefficient between one circular and one linear random +% variable. +% +% Input: +% alpha sample of angles in radians +% x sample of linear random variable +% +% Output: +% rho correlation coefficient +% pval p-value +% +% References: +% Biostatistical Analysis, J. H. Zar, p. 651 +% +% PHB 6/7/2008 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + + +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +if size(x,2) > size(x,1) + x = x'; +end + +if length(alpha)~=length(x) + error('Input dimensions do not match.') +end + +n = length(alpha); + +% compute correlation coefficent for sin and cos independently +rxs = corr(x,sin(alpha)); +rxc = corr(x,cos(alpha)); +rcs = corr(sin(alpha),cos(alpha)); + +% compute angular-linear correlation (equ. 27.47) +rho = sqrt((rxc^2 + rxs^2 - 2*rxc*rxs*rcs)/(1-rcs^2)); + +% compute pvalue +pval = 1 - chi2cdf(n*rho^2,2); + diff --git a/functions/other/nancircstat/circ_dist.m b/functions/other/nancircstat/circ_dist.m new file mode 100644 index 0000000..5312c24 --- /dev/null +++ b/functions/other/nancircstat/circ_dist.m @@ -0,0 +1,36 @@ +function r = circ_dist(x,y) +% +% r = circ_dist(alpha, beta) +% Pairwise difference x_i-y_i around the circle computed efficiently. +% +% Input: +% alpha sample of linear random variable +% beta sample of linear random variable or one single angle +% +% Output: +% r matrix with differences +% +% References: +% Biostatistical Analysis, J. H. Zar, p. 651 +% +% PHB 3/19/2009 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + + +if size(x,2)>size(x,1) + x = x'; +end + +if size(y,2)>size(y,1) + y = y'; +end + +if length(x)~=length(y) && ~length(y)==1 + error('Input dimensions do not match.') +end + +r = angle(exp(1i*x)./exp(1i*y)); \ No newline at end of file diff --git a/functions/other/nancircstat/circ_dist2.m b/functions/other/nancircstat/circ_dist2.m new file mode 100644 index 0000000..d387341 --- /dev/null +++ b/functions/other/nancircstat/circ_dist2.m @@ -0,0 +1,38 @@ +function r = circ_dist2(x,y) +% +% r = circ_dist(alpha, beta) +% All pairwise difference x_i-y_j around the circle computed efficiently. +% +% Input: +% alpha sample of linear random variable +% beta sample of linear random variable +% +% Output: +% r matrix with pairwise differences +% +% References: +% Biostatistical Analysis, J. H. Zar, p. 651 +% +% PHB 3/19/2009 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if nargin < 2 + y = x; +end + +% if size(x,2)>size(x,1) +% x = x'; +% end +% +% if size(y,2)>size(y,1) +% y = y'; +% end + +% r = angle(repmat(exp(1i*x),1,length(y)) ... +% ./ repmat(exp(1i*y'),length(x),1)'); +r = angle(repmat(exp(1i*x),1,1) ... + ./ repmat(exp(1i*y'),1,1)'); \ No newline at end of file diff --git a/functions/other/nancircstat/circ_hktest.m b/functions/other/nancircstat/circ_hktest.m new file mode 100644 index 0000000..9389373 --- /dev/null +++ b/functions/other/nancircstat/circ_hktest.m @@ -0,0 +1,250 @@ +function [pval table] = circ_hktest(alpha, idp, idq, inter, fn) + +% +% [pval, stats] = circ_hktest(alpha, idp, idq, inter, fn) +% Parametric two-way ANOVA for circular data with interations. +% +% Input: +% alpha angles in radians +% idp indicates the level of factor 1 (1:p) +% idq indicates the level of factor 2 (1:q) +% inter 0 or 1 - whether to include effect of interaction or not +% fn cell array containing strings with the names of the factors +% +% +% Output: +% pval vector of pvalues testing column, row and interaction effects +% table cell array containg the anova table +% +% The test assumes underlying von-Mises distributrions. +% All groups are assumed to have a common concentration parameter k, +% between 0 and 2. +% +% PHB 7/19/2009 with code by Tal Krasovsky, Mc Gill University +% +% References: +% Harrison, D. and Kanji, G. K. (1988). The development of analysis of variance for +% circular data. Journal of applied statistics, 15(2), 197-223. +% +% Circular Statistics Toolbox for Matlab + +% process inputs +alpha = alpha(:); idp = idp(:); idq = idq(:); + +if nargin < 4 + inter = true; +end + +if nargin < 5 + fn = {'A','B'}; +end + + +% number of groups for every factor +pu = unique(idp); +p = length(pu); +qu = unique(idq); +q = length(qu); + +% number of samples +n = length(alpha); + +% compute important sums for the test statistics +cn = zeros(p,q); cr = cn; +pm = zeros(p,1); pr = pm; pn = pm; +qm = zeros(p,1); qr = qm; qn = pm; +for pp = 1:p + p_id = idp == pu(pp); % indices of factor1 = pp + for qq = 1:q + q_id = idq == qu(qq); % indices of factor2 = qq + idx = p_id & q_id; + cn(pp,qq) = sum(idx); % number of items in cell + cr(pp,qq) = cn(pp,qq) * circ_r(alpha(idx)); % R of cell + end + % R and mean angle for factor 1 + pr(pp) = sum(p_id) * circ_r(alpha(p_id)); + pm(pp) = circ_mean(alpha(p_id)); + pn(pp) = sum(p_id); +end + +% R and mean angle for factor 2 +for qq = 1:q + q_id = idq == qu(qq); + qr(qq) = sum(q_id) * circ_r(alpha(q_id)); + qm(qq) = circ_mean(alpha(q_id)); + qn(qq) = sum(q_id); +end + +% R and mean angle for whole sample (total) +tr = n * circ_r(alpha); + +% estimate kappa +kk = circ_kappa(tr/n); + +% different formulas for different width of the distribution +if kk > 2 + % large kappa + + % effect of factor 1 + eff_1 = sum(pr.^2 ./ sum(cn,2)) - tr.^2/n; + df_1 = p-1; + ms_1 = eff_1 / df_1; + + % effect of factor 2 + eff_2 = sum(qr.^2 ./ sum(cn,2)) - tr.^2/n; + df_2 = q-1; + ms_2 = eff_2 / df_2; + + % total effect + eff_t = n - tr.^2/n; + df_t = n-1; + + m = mean(cn(:)); + + if inter + + % correction factor for improved F statistic + beta = 1/(1-1/(5*kk)-1/(10*(kk^2))); + + % residual effects + eff_r = n - sum(sum(cr.^2./cn)); + df_r = p*q*(m-1); + ms_r = eff_r / df_r; + + % interaction effects + eff_i = sum(sum(cr.^2./cn)) - sum(qr.^2./qn) ... + - sum(pr.^2./pn) + tr.^2/n; + df_i = (p-1)*(q-1); + ms_i = eff_i/df_i; + + % interaction test statistic + FI = ms_i / ms_r; + pI = 1-fcdf(FI,df_i,df_r); + + else + + % residual effect + eff_r = n - sum(qr.^2./qn)- sum(pr.^2./pn) + tr.^2/n; + df_r = (p-1)*(q-1); + ms_r = eff_r / df_r; + + % interaction effects + eff_i = []; + df_i = []; + ms_i =[]; + + % interaction test statistic + FI = []; + pI = NaN; + end + + % compute all test statistics as + % F = beta * MS(A) / MS(R); + + F1 = beta * ms_1 / ms_r; + p1 = 1 - fcdf(F1,df_1,df_r); + + F2 = beta * ms_2 / ms_r; + p2 = 1 - fcdf(F2,df_2,df_r); + +else + % small kappa + + % correction factor + rr = besseli(1,kk) / besseli(0,kk); + f = 2/(1-rr^2); + + chi1 = f * (sum(pr.^2./pn)- tr.^2/n); + df_1 = 2*(q-1); + p1 = 1 - chi2cdf(chi1, df_1); + + chi2 = f * (sum(qr.^2./qn)- tr.^2/n); + df_2 = 2*(p-1); + p2 = 1 - chi2cdf(chi2, df_2); + + chiI = f * (sum(sum(cr.^2 ./ cn)) - sum(pr.^2./pn) ... + - sum(qr.^2./qn)+ tr.^2/n); + df_i = (p-1) * (q-1); + pI = 1 - chi2pdf(chiI, df_i); + +end + +na = nargout; +if na < 2 + printTable; +end + +prepareOutput; + + + + + function printTable + + if kk>2 + + fprintf('\nANALYSIS OF VARIANCE TABLE (HIGH KAPPA MODE)\n\n'); + + fprintf('%s\t\t\t\t%s\t%s\t\t%s\t\t%s\t\t\t%s\n', ' ' ,'d.f.', 'SS', 'MS', 'F', 'P-Value'); + fprintf('--------------------------------------------------------------------\n'); + fprintf('%s\t\t\t\t%u\t\t%.2f\t%.2f\t%.2f\t\t%.4f\n', fn{1}, df_1 , eff_1, ms_1, F1, p1); + fprintf('%s\t\t\t\t%u\t\t%.2f\t%.2f\t%.2f\t\t%.4f\n', fn{2}, df_2 , eff_2, ms_2, F2, p2); + if (inter) + fprintf('%s\t\t%u\t\t%.2f\t%.2f\t%.2f\t\t%.4f\n', 'Interaction', df_i , eff_i, ms_i, FI, pI); + end + fprintf('%s\t\t%u\t\t%.2f\t%.2f\n', 'Residual ', df_r, eff_r, ms_r); + fprintf('--------------------------------------------------------------------\n'); + fprintf('%s\t\t%u\t\t%.2f', 'Total ',df_t,eff_t); + fprintf('\n\n') + else + fprintf('\nANALYSIS OF VARIANCE TABLE (LOW KAPPA MODE)\n\n'); + + fprintf('%s\t\t\t\t%s\t%s\t\t\t%s\n', ' ' ,'d.f.', 'CHI2', 'P-Value'); + fprintf('--------------------------------------------------------------------\n'); + fprintf('%s\t\t\t\t%u\t\t%.2f\t\t\t%.4f\n', fn{1}, df_1 , chi1, p1); + fprintf('%s\t\t\t\t%u\t\t%.2f\t\t\t%.4f\n', fn{2}, df_2 , chi2, p2); + if (inter) + fprintf('%s\t\t%u\t\t%.2f\t\t\t%.4f\n', 'Interaction', df_i , chiI, pI); + end + fprintf('--------------------------------------------------------------------\n'); + fprintf('\n\n') + + end + + + end + + function prepareOutput + + pval = [p1 p2 pI]; + + if na > 1 + if kk>2 + table = {'Source','d.f.','SS','MS','F','P-Value'; ... + fn{1}, df_1 , eff_1, ms_1, F1, p1; ... + fn{2}, df_2 , eff_2, ms_2, F2, p2; ... + 'Interaction', df_i , eff_i, ms_i, FI, pI; ... + 'Residual', df_r, eff_r, ms_r, [], []; ... + 'Total',df_t,eff_t,[],[],[]}; + else + table = {'Source','d.f.','CHI2','P-Value'; ... + fn{1}, df_1 , chi1, p1; + fn{2}, df_2 , chi2, p2; + 'Interaction', df_i , chiI, pI}; + end + end + + end + + +end + + + + + + + + + + diff --git a/functions/other/nancircstat/circ_kappa.m b/functions/other/nancircstat/circ_kappa.m new file mode 100644 index 0000000..cb193f8 --- /dev/null +++ b/functions/other/nancircstat/circ_kappa.m @@ -0,0 +1,57 @@ +function kappa = circ_kappa(alpha,w) +% +% kappa = circ_kappa(alpha,[w]) +% Computes an approximation to the ML estimate of the concentration +% parameter kappa of the von Mises distribution. +% +% Input: +% alpha angles in radians OR alpha is length resultant +% [w number of incidences in case of binned angle data] +% +% Output: +% kappa estimated value of kappa +% +% References: +% Statistical analysis of circular data, Fisher, equation p. 88 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + + +alpha = alpha(:); + +if nargin<2 + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) > size(w,1) + w = w'; + end +end + +N = length(alpha); + +if N>1 + R = circ_r(alpha,w); +else + R = alpha; +end + +if R < 0.53 + kappa = 2*R + R^3 + 5*R^5/6; +elseif R>=0.53 && R<0.85 + kappa = -.4 + 1.39*R + 0.43/(1-R); +else + kappa = 1/(R^3 - 4*R^2 + 3*R); +end + +if N<15 && N>1 + if kappa < 2 + kappa = max(kappa-2*(N*kappa)^-1,0); + else + kappa = (N-1)^3*kappa/(N^3+N); + end +end diff --git a/functions/other/nancircstat/circ_medtest.m b/functions/other/nancircstat/circ_medtest.m new file mode 100644 index 0000000..23b0e22 --- /dev/null +++ b/functions/other/nancircstat/circ_medtest.m @@ -0,0 +1,46 @@ +function pval = circ_medtest(alpha,md) +% +% [pval, z] = circ_medtest(alpha,w) +% Tests for significance of the median. +% H0: the population has median angle md +% HA: the population has not median angle md +% +% Input: +% alpha sample of angles in radians +% md median to test for +% +% Output: +% pval p-value +% +% PHB 3/19/2009 +% +% References: +% Biostatistical Analysis, J. H. Zar, 27.4 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +if length(md)>1 + error('Median can only be a single value.') +end + +n = length(alpha); + +% compute deviations from median +d = circ_dist(alpha,md); + +n1 = sum(d<0); +n2 = sum(d>0); + +% compute p-value with binomial test +pval = sum(binopdf([0:min(n1,n2) max(n1,n2):n],n,0.5)); + + + + diff --git a/functions/other/nancircstat/circ_moment.m b/functions/other/nancircstat/circ_moment.m new file mode 100644 index 0000000..8ade34b --- /dev/null +++ b/functions/other/nancircstat/circ_moment.m @@ -0,0 +1,58 @@ +function [mp rho_p mu_p] = nancirc_moment(alpha, w, p, cent) + +% [mp cbar sbar] = circ_moment(alpha, w, p, cent) +% Calculates the complex p-th centred or non-centred moment +% of the angular data in angle. +% +% Input: +% alpha sample of angles +% [w weightings in case of binned angle data] +% [p p-th moment to be computed, default is p=1] +% [cent if true, central moments are computed, default = false] +% +% Output: +% mp complex p-th moment +% rho_p magnitude of the p-th moment +% mu_p angle of th p-th moment +% +% +% References: +% Statistical analysis of circular data, Fisher, p. 33/34 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de + + +alpha = alpha(:); + +if nargin < 2 || isempty(p) + w = ones(size(alpha)); +else + w = w(:); +end + +if nargin < 3 || isempty(p) + p = 1; +end + +if nargin < 4 + cent = false; +end + +if cent + theta = nancirc_mean(alpha,w); + alpha = circ_dist(alpha,theta); +end + + +n = length(alpha); +cbar = nansum(cos(p*alpha'*w))/n; +sbar = nansum(sin(p*alpha'*w))/n; +mp = cbar + i*sbar; + +rho_p = abs(mp); +mu_p = angle(mp); + + diff --git a/functions/other/nancircstat/circ_mtest.m b/functions/other/nancircstat/circ_mtest.m new file mode 100644 index 0000000..3757f51 --- /dev/null +++ b/functions/other/nancircstat/circ_mtest.m @@ -0,0 +1,69 @@ +function [h mu ul ll] = circ_mtest(alpha, dir, xi, w, d) +% +% [pval, z] = circ_mtest(alpha, dir, w, d) +% One-Sample test for the mean angle. +% H0: the population has mean dir. +% HA: the population has not mean dir. +% +% Note: This is the equvivalent to a one-sample t-test with specified +% mean direction. +% +% Input: +% alpha sample of angles in radians +% dir assumed mean direction +% [xi alpha level of the test] +% [w number of incidences in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r, in radians (!)] +% +% Output: +% h 0 if H0 can not be rejected, 1 otherwise +% mu mean +% ul upper (1-xi) confidence level +% ll lower (1-xi) confidence level +% +% PHB 7/6/2008 +% +% References: +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +if nargin<3 + xi = 0.05; +end + +if nargin<4 + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) > size(w,1) + w = w'; + end + if length(alpha)~=length(w) + error('Input dimensions do not match.') + end +end + +if nargin<5 + % per default do not apply correct for binned data + d = 0; +end + +% compute ingredients +mu = circ_mean(alpha,w); +t = circ_confmean(alpha,xi,w,d); +ul = mu + t; +ll = mu - t; + +% compute test via confidence limits (example 27.3) +h = abs(circ_dist2(dir,mu)) > t; diff --git a/functions/other/nancircstat/circ_otest.m b/functions/other/nancircstat/circ_otest.m new file mode 100644 index 0000000..f6ffc4b --- /dev/null +++ b/functions/other/nancircstat/circ_otest.m @@ -0,0 +1,79 @@ +function [pval m] = circ_otest(alpha, sz, w) +% +% [pval, m] = circ_otest(alpha,sz,w) +% Computes Omnibus or Hodges-Ajne test for non-uniformity of circular data. +% H0: the population is uniformly distributed around the circle +% HA: the population is not distributed uniformly around the circle +% +% Alternative to the Rayleigh and Rao's test. Works well for unimodal, +% bimodal or multimodal data. If requirements of the Rayleigh test are +% met, the latter is more powerful. +% +% Input: +% alpha sample of angles in radians +% [sz step size for evaluating distribution, default 1 degree +% [w number of incidences in case of binned angle data] + +% Output: +% pval p-value +% m minimum number of samples falling in one half of the circle +% +% PHB 3/16/2009 +% +% References: +% Biostatistical Analysis, J. H. Zar +% A bivariate sign test, J. L. Hodges et al., 1955 +% A simple test for uniformity of a circular distribution, B. Ajne, 1968 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +if nargin < 2 || isempty(sz) + sz = ang2rad(1); +end + +if nargin < 3 + w = ones(size(alpha)); +else + if length(alpha)~=length(w) + error('Input length does not match.') + end + w =w(:); +end + +alpha = mod(alpha,2*pi); +n = sum(w); +dg = 0:sz:pi; + +m = zeros(size(dg)); +for i=1:length(dg) + m(i) = sum((alpha > dg(i) & alpha < pi + dg(i)).*w); +end +m = min(m); + +if n > 50 + % approximation by Ajne (1968) + A = pi*sqrt(n) / 2 / (n-2*m); + pval = sqrt(2*pi) / A * exp(-pi^2/8/A^2); +else + % exact formula by Hodges (1955) + pval = 2^(1-n) * (n-2*m) * nchoosek(n,m); +end + + + + + + + + + + + + diff --git a/functions/other/nancircstat/circ_plot.m b/functions/other/nancircstat/circ_plot.m new file mode 100644 index 0000000..ea3192a --- /dev/null +++ b/functions/other/nancircstat/circ_plot.m @@ -0,0 +1,143 @@ +function a = circ_plot(alpha, format, formats, varargin) +% +% r = circ_plot(alpha, ...) +% Plotting routines for circular data. +% +% Input: +% alpha sample of angles in radians +% [format specifies style of plot +% pretty, histogram, density, [] +% [formats standard matlab string for plot format (like '.r')] +% +% The different plotting styles take optional arguments: +% pretty: fourth argument toggles between showing mean direction +% and not showing it +% hist: fourth argument determines number of bins/bin centers +% fifth argument determines whether normalized or count +% histogram is shown +% sixth argument toggles between showing mean direction +% and not showing it +% +% All of these arguments can be left empty, i.e. set to [], so that +% the default value will be used. If additional arguments are +% supplied in the name-value style ('linewidth', 2, ...), these are +% used to change the properties of the mean resultant vector plot. +% +% Output: +% a axis handle +% +% Examples: +% alpha = randn(60,1)*.4+pi/2; +% figure +% subplot(2,2,1) +% circ_plot(alpha,'pretty','ro',true,'linewidth',2,'color','r'), +% title('pretty plot style') +% subplot(2,2,2) +% circ_plot(alpha,'hist',[],20,true,true,'linewidth',2,'color','r') +% title('hist plot style') +% subplot(2,2,3) +% circ_plot(alpha,[],'s') +% title('non-fancy plot style') +% +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens & Marc J. Velasco, 2009 +% velasco@ccs.fau.edu, berens@tuebingen.mpg.de + +if nargin < 2 || isempty(format) + format = ''; +end + + +switch format + case 'pretty' + % plot in 'pretty style' + % draws unit circle and marks points around the circle + % adds optionally the mean resultant vector + + if nargin < 3|| isempty(formats) + formats = 'o'; + end + + % convert angles to unit vectors + z = exp(i*alpha); + + % create unit circle + zz = exp(i*linspace(0, 2*pi, 101)); + + plot(real(z), imag(z), formats, real(zz), imag(zz), 'k', [-2 2], [0 0], 'k:', [0 0], [-2 2], 'k:'); + set(gca, 'XLim', [-1.1 1.1], 'YLim', [-1.1 1.1]) + + % plot mean directions with an overlaid arrow if desired + if nargin > 2 && ~isempty(varargin{1}) + s = varargin{1}; + else + s = true; + end + + if s + r = circ_r(alpha); + phi = circ_mean(alpha); + hold on; + zm = r*exp(i*phi); + plot([0 real(zm)], [0, imag(zm)],varargin{2:end}) + hold off; + end + + axis square; + set(gca,'box','off') + set(gca,'xtick',[]) + set(gca,'ytick',[]) + text(1.2, 0, '0'); text(-.05, 1.2, '\pi/2'); text(-1.35, 0, '±\pi'); text(-.075, -1.2, '-\pi/2'); + + + case 'hist' + % plot in 'hist style' + % this is essentially a wrapper for the rose plot function of matlab + % adds optionally the mean resultant vector + + if nargin < 3|| isempty(formats) + formats = '-'; + end + + if nargin > 3 && ~isempty(varargin{1}) + x = varargin{1}; + else + x = 20; + end + + [t,r] = rose(alpha,x); + if varargin{2} + polar(t,r/sum(r),formats) + mr = max(r/sum(r)); + else + polar(t,r,formats) + mr = max(r); + end + + % plot mean directions with an overlaid arrow if desired + if nargin > 5 && ~isempty(varargin{3}) + s = varargin{1}; + else + s = true; + end + + if s + r = circ_r(alpha) * mr; + phi = circ_mean(alpha); + hold on; + zm = r*exp(i*phi); + plot([0 real(zm)], [0, imag(zm)],varargin{4:end}) + hold off; + end + + + otherwise + if nargin < 3 + formats = 'o'; + end + polar(alpha, ones(size(alpha)), formats); +end + +a = gca; diff --git a/functions/other/nancircstat/circ_raotest.m b/functions/other/nancircstat/circ_raotest.m new file mode 100644 index 0000000..4628ad9 --- /dev/null +++ b/functions/other/nancircstat/circ_raotest.m @@ -0,0 +1,130 @@ +function [p U UC] = circ_raotest(alpha) + +% [p U UC] = circ_raotest(alpha) +% Calculates Rao's spacing test by comparing distances between points on +% a circle to those expected from a uniform distribution. +% +% H0: Data is distributed uniformly around the circle. +% H1: Data is not uniformly distributed around the circle. +% +% Alternative to the Rayleigh test and the Omnibus test. Less powerful +% than the Rayleigh test when the distribution is unimodal on a global +% scale but uniform locally. +% +% Due to the complexity of the distributioin of the test statistic, we +% resort to the tables published by +% Russell, Gerald S. and Levitin, Daniel J.(1995) +% 'An expanded table of probability values for rao's spacing test' +% Communications in Statistics - Simulation and Computation +% Therefore the reported p-value is the smallest alpha level at which the +% test would still be significant. If the test is not significant at the +% alpha=0.1 level, we return the critical value for alpha = 0.05 and p = +% 0.5. +% +% Input: +% alpha sample of angles +% +% Output: +% p smallest p-value at which test would be significant +% U computed value of the test-statistic u +% UC critical value of the test statistic at sig-level +% +% +% References: +% Batschelet, 1981, Sec 4.6 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de + +alpha = alpha(:); + +% for the purpose of the test, convert to angles +alpha = rad2ang(alpha); +n = length(alpha); +alpha = sort(alpha); + +% compute test statistic +U = 0; +lambda = 360/n; +for j = 1:n-1 + ti = alpha(j+1) - alpha(j); + U = U + abs(ti - lambda); +end + +tn = (360 - alpha(n) + alpha(1)); +U = U + abs(tn-lambda); + +U = (1/2)*U; + +% get critical value from table +[p UC] = getVal(n,U); + + + +function [p UC] = getVal(N, U) + +% Table II from Russel and Levitin, 1995 + +alpha = [0.001, .01, .05, .10]; +table = [ 4 247.32, 221.14, 186.45, 168.02; + 5 245.19, 211.93, 183.44, 168.66; + 6 236.81, 206.79, 180.65, 166.30; + 7 229.46, 202.55, 177.83, 165.05; + 8 224.41, 198.46, 175.68, 163.56; + 9 219.52, 195.27, 173.68, 162.36; + 10 215.44, 192.37, 171.98, 161.23; + 11 211.87, 189.88, 170.45, 160.24; + 12 208.69, 187.66, 169.09, 159.33; + 13 205.87, 185.68, 167.87, 158.50; + 14 203.33, 183.90, 166.76, 157.75; + 15 201.04, 182.28, 165.75, 157.06; + 16 198.96, 180.81, 164.83, 156.43; + 17 197.05, 179.46, 163.98, 155.84; + 18 195.29, 178.22, 163.20, 155.29; + 19 193.67, 177.08, 162.47, 154.78; + 20 192.17, 176.01, 161.79, 154.31; + 21 190.78, 175.02, 161.16, 153.86; + 22 189.47, 174.10, 160.56, 153.44; + 23 188.25, 173.23, 160.01, 153.05; + 24 187.11, 172.41, 159.48, 152.68; + 25 186.03, 171.64, 158.99, 152.32; + 26 185.01, 170.92, 158.52, 151.99; + 27 184.05, 170.23, 158.07, 151.67; + 28 183.14, 169.58, 157.65, 151.37; + 29 182.28, 168.96, 157.25, 151.08; + 30 181.45, 168.38, 156.87, 150.80; + 35 177.88, 165.81, 155.19, 149.59; + 40 174.99, 163.73, 153.82, 148.60; + 45 172.58, 162.00, 152.68, 147.76; + 50 170.54, 160.53, 151.70, 147.05; + 75 163.60, 155.49, 148.34, 144.56; + 100 159.45, 152.46, 146.29, 143.03; + 150 154.51, 148.84, 143.83, 141.18; + 200 151.56, 146.67, 142.35, 140.06; + 300 148.06, 144.09, 140.57, 138.71; + 400 145.96, 142.54, 139.50, 137.89; + 500 144.54, 141.48, 138.77, 137.33; + 600 143.48, 140.70, 138.23, 136.91; + 700 142.66, 140.09, 137.80, 136.59; + 800 142.00, 139.60, 137.46, 136.33; + 900 141.45, 139.19, 137.18, 136.11; + 1000 140.99, 138.84, 136.94, 135.92 ]; + +ridx = find(table(:,1)>=N,1); +cidx = find(table(ridx,2:end) size(alpha,1) + alpha = alpha'; +end + +if nargin < 2 + r = circ_r(alpha); + n = length(alpha); +else + if length(alpha)~=length(w) + error('Input dimensions do not match.') + end + if nargin < 3 + d = 0; + end + r = circ_r(alpha,w(:),d); + n = sum(w); +end + +% compute Rayleigh's R (equ. 27.1) +R = n*r; + +% compute Rayleigh's z (equ. 27.2) +z = R^2 / n; + +% compute p value using approxation in Zar, p. 617 +pval = exp(sqrt(1+4*n+4*(n^2-R^2))-(1+2*n)); + +% outdated version: +% compute the p value using an approximation from Fisher, p. 70 +% pval = exp(-z); +% if n < 50 +% pval = pval * (1 + (2*z - z^2) / (4*n) - ... +% (24*z - 132*z^2 + 76*z^3 - 9*z^4) / (288*n^2)); +% end + + + + + + + + + diff --git a/functions/other/nancircstat/circ_stats.m b/functions/other/nancircstat/circ_stats.m new file mode 100644 index 0000000..33321e3 --- /dev/null +++ b/functions/other/nancircstat/circ_stats.m @@ -0,0 +1,60 @@ +function stats = circ_stats(alpha, w, d) +% +% stats = circ_stats(alpha, w) +% Computes descriptive statistics for circular data. +% +% Input: +% alpha sample of angles in radians +% [w weightings in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r] +% +% Output: +% stats structure containing descriptive statistics +% +% References: +% Statistical analysis of circular data, N. I. Fisher +% Topics in circular statistics, S. R. Jammalamadaka et al. +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de + +alpha = alpha(:); +if nargin<2 + w = ones(size(alpha)); +end + +if nargin < 3 + d = 0; +end + +% mean +stats.mean = circ_mean(alpha,w); + +% median +if sum(w)==length(alpha) + stats.median = circ_median(alpha); +else + stats.median = NaN; +end + +% variance +stats.var = circ_var(alpha,w,d); + +% standard deviation +stats.std = circ_std(alpha,w,d); +stats.std_mardia = circ_std(alpha,w,d,'mardia'); + +% skewness +[stats.skewness stats.skewness_mardia] = circ_skewness(alpha,w); + +% kurtosis +[stats.kurtosis stats.kurtosi_mardia] = circ_kurtosis(alpha,w); + + + + diff --git a/functions/other/nancircstat/circ_symtest.m b/functions/other/nancircstat/circ_symtest.m new file mode 100644 index 0000000..3e8075c --- /dev/null +++ b/functions/other/nancircstat/circ_symtest.m @@ -0,0 +1,40 @@ +function pval = circ_symtest(alpha) +% +% [pval, z] = circ_symtest(alpha,w) +% Tests for symmetry about the median. +% H0: the population is symmetrical around the median +% HA: the population is not symmetrical around the median + +% +% Input: +% alpha sample of angles in radians +% +% Output: +% pval p-value +% +% PHB 3/19/2009 +% +% References: +% Biostatistical Analysis, J. H. Zar, 27.4 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +% compute median +md = circ_median(alpha); + +% compute deviations from median +d = circ_dist(alpha,md); + +% compute wilcoxon sign rank test +pval = signrank(d); + + + + diff --git a/functions/other/nancircstat/circ_var.m b/functions/other/nancircstat/circ_var.m new file mode 100644 index 0000000..ff3dd84 --- /dev/null +++ b/functions/other/nancircstat/circ_var.m @@ -0,0 +1,48 @@ +function s = circ_var(alpha, w, d) +% s = circ_var(alpha, w, d) +% Computes circular variance for circular data +% (equ. 26.17, Zar). +% +% Input: +% alpha sample of angles in radians +% [w number of incidences in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r] +% +% Output: +% s circular variance +% +% PHB 6/7/2008 +% +% References: +% Statistical analysis of circular data, N.I. Fisher +% Topics in circular statistics, S.R. Jammalamadaka et al. +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +% check vector size +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +if nargin<2 + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +end + +if nargin<3 + % per default do not apply correct for binned data + d = 0; +end + +% compute mean resultant vector length +r = nancirc_r(alpha,w,d); + +% apply transformation to var +s = 1 - r; \ No newline at end of file diff --git a/functions/other/nancircstat/circ_vmpar.m b/functions/other/nancircstat/circ_vmpar.m new file mode 100644 index 0000000..d5448c5 --- /dev/null +++ b/functions/other/nancircstat/circ_vmpar.m @@ -0,0 +1,38 @@ +function [thetahat kappa] = circ_vmpar(alpha,w,d) + +% r = circ_vmpar(alpha, w, d) +% Estimate the parameters of a von Mises distribution. +% +% Input: +% alpha sample of angles in radians +% [w number of incidences in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r, in radians (!)] +% +% Output: +% thetahat preferred direction +% kappa concentration parameter +% +% PHB 3/23/2009 +% +% References: +% Statistical analysis of circular data, N.I. Fisher +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de + +alpha = alpha(:); +if nargin < 2 + w = ones(size(alpha)); +end +if nargin < 3 + d = 0; +end + +r = circ_r(alpha,w,d); +kappa = circ_kappa(r); + +thetahat = circ_mean(alpha,w); diff --git a/functions/other/nancircstat/circ_vmpdf.m b/functions/other/nancircstat/circ_vmpdf.m new file mode 100644 index 0000000..ace9a0e --- /dev/null +++ b/functions/other/nancircstat/circ_vmpdf.m @@ -0,0 +1,46 @@ +function [p alpha] = circ_vmpdf(alpha, thetahat, kappa) + +% [p alpha] = circ_vmpdf(alpha, w, p) +% Computes the circular von Mises pdf with preferred direction thetahat +% and concentration kappa at each of the angles in alpha +% +% The vmpdf is given by f(phi) = +% (1/(2pi*I0(kappa))*exp(kappa*cos(phi-thetahat) +% +% Input: +% alpha angles to evaluate pdf at, if empty alphas are chosen to +% 100 uniformly spaced points around the circle +% [thetahat preferred direction, default is 0] +% [kappa concentration parameter, default is 1] +% +% Output: +% p von Mises pdf evaluated at alpha +% alpha angles at which pdf was evaluated +% +% +% References: +% Statistical analysis of circular data, Fisher +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens and Marc J. Velasco, 2009 +% velasco@ccs.fau.edu + +% if no angles are supplied, 100 evenly spaced points around the circle are +% chosen +if nargin < 1 || isempty(alpha) + alpha = linspace(0, 2*pi, 101)'; + alpha = alpha(1:end-1); +end +if nargin < 3 + kappa = 1; +end +if nargin < 2 + thetahat = 0; +end + +alpha = alpha(:); + +% evaluate pdf +C = 1/(2*pi*bessi0(kappa)); +p = C * exp(kappa*cos(alpha-thetahat)); diff --git a/functions/other/nancircstat/circ_vmrnd.m b/functions/other/nancircstat/circ_vmrnd.m new file mode 100644 index 0000000..aac5897 --- /dev/null +++ b/functions/other/nancircstat/circ_vmrnd.m @@ -0,0 +1,71 @@ +function alpha = circ_vmrnd(theta, kappa, n) + +% alpha = circ_vmrnd(theta, kappa, n) +% Simulates n random angles from a von Mises distribution, with preferred +% direction thetahat and concentration parameter kappa. +% +% Input: +% [theta preferred direction, default is 0] +% [kappa width, default is 1] +% [n number of samples, defailt is 10] +% +% Output: +% alpha samples from von Mises distribution +% +% +% References: +% Statistical analysis of circular data, Fisher, sec. 3.3.6, p. 49 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens and Marc J. Velasco, 2009 +% velasco@ccs.fau.edu + + +% default parameter +if nargin < 3 + n = 10; +end +if nargin < 2 + kappa = 1; +end +if nargin < 1 + theta = 0; +end + +% if kappa is small, treat as uniform distribution +if kappa < 1e-6 + alpha = 2*pi*rand(n,1); + return +end + +% other cases +a = 1 + sqrt((1+4*kappa.^2)); +b = (a - sqrt(2*a))/(2*kappa); +r = (1 + b^2)/(2*b); + +alpha = zeros(n,1); +for j = 1:n + while true + u = rand(3,1); + + z = cos(pi*u(1)); + f = (1+r*z)/(r+z); + c = kappa*(r-f); + + if u(2) < c * (2-c) || ~(log(c)-log(u(2)) + 1 -c < 0) + break + end + + + end + + alpha(j) = theta + sign(u(3) - 0.5) * acos(f); + alpha(j) = angle(exp(i*alpha(j))); +end + + + + + + diff --git a/functions/other/nancircstat/circ_vtest.m b/functions/other/nancircstat/circ_vtest.m new file mode 100644 index 0000000..3542bcc --- /dev/null +++ b/functions/other/nancircstat/circ_vtest.m @@ -0,0 +1,77 @@ +function [pval z] = circ_vtest(alpha, dir, w, d) +% +% [pval, z] = circ_vtest(alpha, dir, w, d) +% Computes V test for non-uniformity of circular data with a specified +% mean direction dir. +% H0: the population is uniformly distributed around the circle +% HA: the population is not distributed uniformly around the circle but +% has a mean of dir. +% +% Note: Not rejecting H0 may mean that the population is uniformly +% distributed around the circle OR that it has a mode but that this mode +% is not centered at dir. +% +% The V test has more power than the Rayleigh test and is preferred if +% there is reason to believe in a specific mean direction. +% +% Input: +% alpha sample of angles in radians +% dir suspected mean direction +% [w number of incidences in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r, in radians (!)] +% +% Output: +% pval p-value of V test +% v value of the V statistic +% +% PHB 7/6/2008 +% +% References: +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + + +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +if nargin<3 + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +else + if size(w,2) > size(w,1) + w = w'; + end + if length(alpha)~=length(w) + error('Input dimensions do not match.') + end +end + +if nargin<4 + % per default do not apply correct for binned data + d = 0; +end + +% compute some ingredients +r = circ_r(alpha,w,d); +mu = circ_mean(alpha,w); +n = sum(w); + +% compute Rayleigh's R (equ. 27.1) +R = n * r; + +% compute the V statistic (equ. 27.5) +v = R * cos(mu-dir); + +% compute u (equ. 27.6) +u = v * sqrt(2/n); + +% compute p-value from one tailed normal approximation +pval = 1 - normcdf(u); diff --git a/functions/other/nancircstat/circ_wwtest.m b/functions/other/nancircstat/circ_wwtest.m new file mode 100644 index 0000000..5726171 --- /dev/null +++ b/functions/other/nancircstat/circ_wwtest.m @@ -0,0 +1,157 @@ +function [pval table] = circ_wwtest(varargin) +% [pval, table] = circ_wwtest(alpha, idx, [w]) +% [pval, table] = circ_wwtest(alpha1, alpha2, [w1, w2]) +% Parametric Watson-Williams multi-sample test for equal means. Can be +% used as a one-way ANOVA test for circular data. +% +% H0: the s populations have equal means +% HA: the s populations have unequal means +% +% Note: +% Use with binned data is only advisable if binning is finer than 10 deg. +% In this case, alpha is assumed to correspond +% to bin centers. +% +% The Watson-Williams two-sample test assumes underlying von-Mises +% distributrions. All groups are assumed to have a common concentration +% parameter k. +% +% Input: +% alpha angles in radians +% idx indicates which population the respective angle in alpha +% comes from, 1:s +% [w number of incidences in case of binned angle data] +% +% Output: +% pval p-value of the Watson-Williams multi-sample test. Discard H0 if +% pval is small. +% table cell array containg the ANOVA table +% +% PHB 3/19/2009 +% +% References: +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +[alpha, idx, w] = processInput(varargin{:}); + +% number of groups +u = unique(idx); +s = length(u); + +% number of samples +n = sum(w); + +% compute relevant quantitites +pn = zeros(s,1); pr = pn; +for t=1:s + pidx = idx == u(t); + pn(t) = sum(pidx.*w); + pr(t) = circ_r(alpha(pidx),w(pidx)); +end + +r = circ_r(alpha,w); +rw = sum(pn.*pr)/n; + +% make sure assumptions are satisfied +checkAssumption(rw,mean(pn)) + +% test statistic +kk = circ_kappa(rw); +beta = 1+3/(8*kk); % correction factor +A = sum(pr.*pn) - r*n; +B = n - sum(pr.*pn); + +F = beta * (n-s) * A / (s-1) / B; +pval = 1 - fcdf(F,s-1,n-s); + +na = nargout; +if na < 2 + printTable; +end +prepareOutput; + + + function printTable + + fprintf('\nANALYSIS OF VARIANCE TABLE (WATSON-WILLIAMS TEST)\n\n'); + fprintf('%s\t\t\t\t%s\t%s\t\t%s\t\t%s\t\t\t%s\n', ' ' ,'d.f.', 'SS', 'MS', 'F', 'P-Value'); + fprintf('--------------------------------------------------------------------\n'); + fprintf('%s\t\t\t%u\t\t%.2f\t%.2f\t%.2f\t\t%.4f\n', 'Columns', s-1 , A, A/(s-1), F, pval); + fprintf('%s\t\t%u\t\t%.2f\t%.2f\n', 'Residual ', n-s, B, B/(n-s)); + fprintf('--------------------------------------------------------------------\n'); + fprintf('%s\t\t%u\t\t%.2f', 'Total ',n-1,A+B); + fprintf('\n\n') + + end + + function prepareOutput + + if na > 1 + table = {'Source','d.f.','SS','MS','F','P-Value'; ... + 'Columns', s-1 , A, A/(s-1), F, pval; ... + 'Residual ', n-s, B, B/(n-s), [], []; ... + 'Total',n-1,A+B,[],[],[]}; + end + end +end + + + +function checkAssumption(rw,n) + + if n > 10 && rw<.45 + warning('Test not applicable. Average resultant vector length < 0.45.') %#ok + elseif n > 6 && rw<.5 + warning('Test not applicable. Average number of samples per population < 11 and average resultant vector length < 0.5.') %#ok + elseif n >=5 && rw<.55 + warning('Test not applicable. Average number of samples per population < 7 and average resultant vector length < 0.55.') %#ok + elseif n < 5 + warning('Test not applicable. Average number of samples per population < 5.') %#ok + end + +end + + +function [alpha, idx, w] = processInput(varargin) + + if nargin == 4 + alpha1 = varargin{1}(:); + alpha2 = varargin{2}(:); + w1 = varargin{3}(:); + w2 = varargin{4}(:); + alpha = [alpha1; alpha2]; + idx = [ones(size(alpha1)); ones(size(alpha2))]; + w = [w1; w2]; + elseif nargin==2 && sum(abs(round(varargin{2})-varargin{2}))>1e-5 + alpha1 = varargin{1}(:); + alpha2 = varargin{2}(:); + alpha = [alpha1; alpha2]; + idx = [ones(size(alpha1)); 2*ones(size(alpha2))]; + w = ones(size(alpha)); + elseif nargin==2 + alpha = varargin{1}(:); + idx = varargin{2}(:); + if ~(size(idx,1)==size(alpha,1)) + error('Input dimensions do not match.') + end + w = ones(size(alpha)); + elseif nargin==3 + alpha = varargin{1}(:); + idx = varargin{2}(:); + w = varargin{3}(:); + if ~(size(idx,1)==size(alpha,1)) + error('Input dimensions do not match.') + end + if ~(size(w,1)==size(alpha,1)) + error('Input dimensions do not match.') + end + else + error('Invalid use of circ_wwtest. Type help circ_wwtest.') + end +end + diff --git a/functions/other/nancircstat/data.mat b/functions/other/nancircstat/data.mat new file mode 100644 index 0000000..9bef4b0 Binary files /dev/null and b/functions/other/nancircstat/data.mat differ diff --git a/functions/other/nancircstat/example1.m b/functions/other/nancircstat/example1.m new file mode 100644 index 0000000..5bf783b --- /dev/null +++ b/functions/other/nancircstat/example1.m @@ -0,0 +1,195 @@ +% Philipp Berens +% CircStat: A Matlab Toolbox for Circular Statistics +% Submitted to Journal of Statistical Software +% +% Example 1 +% +% Demonstrate functionality of all functions of the CircStat toolbox using +% artifical data. + +%% part1: generate data + +alpha_deg = [13 15 21 26 28 30 35 36 41 60 92 103 165 199 210 ... + 250 301 320 343 359]'; + +alpha_rad = circ_ang2rad(alpha_deg); % convert to radians + +beta_deg = [1 13 41 NaN 67 71 81 85 99 110 119 131 145 177 199 220 ... + 291 320 340 355]'; +beta_rad = circ_ang2rad(beta_deg); % convert to radians + +fprintf('\nTHE CIRCSTAT TOOLBOX EXAMPLE\n\nDescriptive Statistics\n') + +%% part2: plot data (generate figure 1) + +figure(1) +subplot(2,2,1) +circ_plot(alpha_rad,'pretty','bo',true,'linewidth',2,'color','r'), + +subplot(2,2,3) +circ_plot(alpha_rad,'hist',[],20,true,true,'linewidth',2,'color','r') + +subplot(2,2,2) +circ_plot(beta_rad,'pretty','bo',true,'linewidth',2,'color','r'), + +subplot(2,2,4) +circ_plot(beta_rad,'hist',[],20,true,true,'linewidth',2,'color','r') + +%% part 3: descriptive statistics + +fprintf('\t\t\t\t\t\tALPHA\tBETA\n') + +alpha_bar = nancirc_mean(alpha_rad); +beta_bar = nancirc_mean(beta_rad); + +fprintf('Mean resultant vector:\t%.2f \t%.2f\n', circ_rad2ang([alpha_bar beta_bar])) + +alpha_hat = nancirc_median(alpha_rad); +beta_hat = nancirc_median(beta_rad); + +fprintf('Median:\t\t\t\t\t%.2f \t%.2f\n', circ_rad2ang([alpha_hat beta_hat])) + +R_alpha = nancirc_r(alpha_rad); +R_beta = nancirc_r(beta_rad); + +fprintf('R Length:\t\t\t\t\t%.2f \t%.2f\n',[R_alpha R_beta]) + +S_alpha = nancirc_var(alpha_rad); +S_beta = nancirc_var(beta_rad); + +fprintf('Variance:\t\t\t\t%.2f \t%.2f\n',[S_alpha S_beta]) + +[s_alpha s0_alpha] = nancirc_std(alpha_rad); +[s_beta s0_beta] = nancirc_std(beta_rad); + +fprintf('Standard deviation:\t\t%.2f \t%.2f\n',[s_alpha s_beta]) +fprintf('Standard deviation 0:\t%.2f \t%.2f\n',[s0_alpha s0_beta]) + +b_alpha = nancirc_skewness(alpha_rad); +b_beta = nancirc_skewness(beta_rad); + +fprintf('Skewness:\t\t\t\t%.2f \t%.2f\n',[b_alpha b_beta]) + +k_alpha = nancirc_kurtosis(alpha_rad); +k_beta = nancirc_kurtosis(beta_rad); + +fprintf('Kurtosis:\t\t\t\t%.2f \t%.2f\n',[k_alpha k_beta]) + +fprintf('\n\n') + +%% part 4: inferential statistics + +fprintf('Inferential Statistics\n\nTests for Uniformity\n') + +% Rayleigh test +p_alpha = circ_rtest(alpha_rad); +p_beta = circ_rtest(beta_rad); +fprintf('Rayleigh Test, \t\t P = %.2f \t%.2f\n',[p_alpha p_beta]) + +% Omnibus test +p_alpha = circ_otest(alpha_rad); +p_beta = circ_otest(beta_rad); +fprintf('Omnibus Test, \t\t P = %.2f \t%.2f\n',[p_alpha p_beta]) + +% Rao's spacing test +p_alpha = circ_raotest(alpha_rad); +p_beta = circ_raotest(beta_rad); +fprintf('Rao Spacing Test, \t P = %.2f \t%.2f\n',[p_alpha p_beta]) + +% V test +p_alpha = circ_vtest(alpha_rad,circ_ang2rad(0)); +p_beta = circ_vtest(beta_rad,circ_ang2rad(0)); +fprintf('V Test (r = 0), \t P = %.2f \t%.2f\n',[p_alpha p_beta]) + + +fprintf('\nTests concerning Mean and Median angle\n') + +% 95 percent confidence intervals for mean direction +t_alpha = circ_confmean(alpha_rad,0.05); +t_beta = circ_confmean(beta_rad,0.05); + +fprintf('Mean, up 95 perc. CI:\t\t\t%.2f \t%.2f\n', circ_rad2ang([alpha_bar+t_alpha beta_bar+t_beta])) +fprintf('Mean, low 95 perc. CI:\t\t\t%.2f \t%.2f\n', circ_rad2ang([2*pi+alpha_bar-t_alpha beta_bar-t_beta])) + +h1 = circ_mtest(alpha_rad,0); +h2 = circ_mtest(alpha_rad,circ_ang2rad(90)); + +fprintf('Mean Test (alpha), mean = 0 deg:\t\t%d\n',h1) +fprintf('Mean Test (alpha), mean = 90 deg:\t\t%d\n',h2) + + +h1 = circ_medtest(alpha_rad,circ_ang2rad(25)); +h2 = circ_medtest(alpha_rad,circ_ang2rad(105)); + +fprintf('Median Test (alpha), median = 25 deg:\t%.2f\n',h1) +fprintf('Median Test (alpha), median = 105 deg:\t%.2f\n',h2) + +h1 = circ_symtest(alpha_rad); +h2 = circ_symtest(beta_rad); + +fprintf('Symmetry around median (alpha/beta):\t\t\t%.2f\t %.2f\n',h1,h2) + + +%% part 4: association +fprintf('Measures of Association\n\nCircular-Circular Association\n') + +figure +subplot(121) +plot(alpha_rad,beta_rad,'ok') +formatSubplot(gca,'xl','\alpha_i','yl','\beta_i', 'ax','square','box','off', 'lim',[0 2*pi 0 2*pi ]) + +subplot(122) +plot(1:20,alpha_rad,'or',1:20,beta_rad,'ok') +formatSubplot(gca,'xl','x','yl','\alpha_i (red) / \beta_i (black)', 'ax','square','box','off', 'lim',[0 21 0 2*pi ]) + + +% compute circular - circular correlation of alpha and beta +[c p] = circ_corrcc(alpha_rad,beta_rad); +fprintf('Circ-circ corr coeff/pval:\t%.2f\t %.3f\n',c,p) + + +% cmpute circular - linear correlation of alpha/beta with 1:20 +[ca pa] = circ_corrcl(alpha_rad,1:20); +[cb pb] = circ_corrcl(beta_rad,1:20); + +fprintf('Circ-lin corr coeff:\t\t%.2f\t %.2f\n',ca,cb) +fprintf('Circ-lin corr pval:\t\t\t%.3f\t %.3f\n',pa,pb) + + +%% part 5: multi-sample tests +% the dataset we use here consists of three samples from von mises +% distributions with common parameter kappa = 10 and means equal to pi, +% pi+.25 and pi+.5. + +load data + +fprintf('\nMulti-Sample tests\n') + +fprintf('\nTEST 1: ONE FACTOR ANOVA, theta1 vs theta2\n') +p = circ_wwtest(theta1,theta2); + +fprintf('\nTEST 2: ONE FACTOR ANOVA, theta1 vs theta2 vs theta3\n') +p = circ_wwtest(theta,idx); + + +p = circ_cmtest(theta1,theta2); +fprintf('TEST 3: NON PARAMETRIC ONE FACTOR ANOVA, theta1 vs. theta2\nP = %.4f\n\n',p) + +fprintf('\nTEST 4: TWO FACTOR ANOVA, theta1 vs theta2\n') + +idp = idx(1:60); % factor 1: two original groups +idq = idp(randperm(length(idp))); % factor 2: random assignment to groups + +p = circ_hktest([theta1; theta2], idp,idq,true); + + + + + + + + + + + + diff --git a/functions/other/nancircstat/example2.m b/functions/other/nancircstat/example2.m new file mode 100644 index 0000000..ec2ca08 --- /dev/null +++ b/functions/other/nancircstat/example2.m @@ -0,0 +1,156 @@ +% Philipp Berens +% CircStat: A Matlab Toolbox for Circular Statistics +% Submitted to Journal of Statistical Software +% +% Example 2 +% An Application to Neuroscience +% +% +% In this example, we assess the orientation tuning properties of three +% neurons recorded from the primary visual cortex of awake macaques. the +% number of action potentials such neurons fire is modulated by the +% orientation of a visual stimulus such as an oriented grating. +% +% We thus consider two variables: The stimulus orientations ori spaced 22.5 +% deg apart and the number of spikes w fired in response to each +% orientation of the stimulus. + + +%% part 1: load and plot data +clear +load neurodata + +% orientation of bins -> convert two directions +ori = circ_axial(circ_ang2rad(ori),2); + +% spacing of bins +dori = diff(ori(1:2)); + +% summed spikes per orientation +w; + +% plot the activity of the three neurons +figure +for j = 1:3 + subplot(1,3,j) + + % compute and plot mean resultant vector length and direction + mw = max(w(j,:)); + r = circ_r(ori,w(j,:),dori) * mw; + phi = circ_mean(ori,w(j,:)); + hold on; + zm = r*exp(i*phi); + plot([0 real(zm)], [0, imag(zm)],'r','linewidth',1.5) + + % plot the tuning function of the three neurons + polar([ori ori(1)], [w(j,:) w(j,1)],'k') + + % draw a unit circle + zz = exp(i*linspace(0, 2*pi, 101)) * mw; + plot(real(zz),imag(zz),'k:') + plot([-mw mw], [0 0], 'k:', [0 0], [-mw mw], 'k:') + + formatSubplot(gca,'ax','square','box','off','lim',[-mw mw -mw mw]) + set(gca,'xtick',[]) + set(gca,'ytick',[]) + +end + +%% part 2: descriptive statistics + +stats = zeros(3,10); +for i=1:3 + + spk = w(i,:); + + % circular mean angle + stats(i,1) = circ_mean(ori,spk); + + % circular variance + stats(i,2) = circ_var(ori,spk,dori); + + % circular standard deviation + [stats(i,3) stats(i,4)] = circ_std(ori,spk,dori); + + % circular skewness + [stats(i,5) stats(i,6)] = circ_skewness(ori,spk); + + % circular skewness + [stats(i,7) stats(i,8)] = circ_kurtosis(ori,spk); + + % confidence limits on mean angle + t = circ_confmean(ori,[],spk,dori); + stats(i,9) = stats(i,1) + t; + stats(i,10) = stats(i,1) - t; +end + +% stats contains all data reported in table 1 + +%% part 3: inferential statistics + +% A: tests for uniformity of distribution around the circle +% rejecting the null hypothesis allows us to assert that the neurons are +% indeed tuned to the orientation of the stimulus and fire preferentially +% at a particular orientation + +uniform = zeros(3,2); +for i=1:3 + + spk = w(i,:); + + % rayleigh test + uniform(i,1) = circ_rtest(ori,spk,dori); + + % omnibus test + uniform(i,2) = circ_otest(ori,[],spk); + + % rao's spacing test is not possible with binned data +end + +% B: test for differences in preferred orientation between neurons + +% differences between all groups +alpha = [ori ori ori]; +idx = [ones(1,length(ori)) 2* ones(1,length(ori)) 3* ones(1,length(ori))]; +spk = reshape(w',1,numel(w)); + +fprintf('TESTING FOR DIFFERENCES BETWEEN ANY CELLS\n') +circ_wwtest(alpha,idx,spk); + +% all pairwise differences +for i=1:3 + for j=(i+1):3 + % differences between cells i and cell j + alpha = [ori ori]; + idx = [i* ones(1,length(ori)) j* ones(1,length(ori))]; + spk = reshape(w([i j],:)',1,numel(w([i j],:))); + + fprintf('TESTING FOR DIFFERENCES BETWEEN CELLS %d AND %d\n',i,j) + watson(i,j) = circ_wwtest(alpha,idx,spk); %#ok + end +end + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/functions/other/nancircstat/formatSubplot.m b/functions/other/nancircstat/formatSubplot.m new file mode 100644 index 0000000..84b71c5 --- /dev/null +++ b/functions/other/nancircstat/formatSubplot.m @@ -0,0 +1,38 @@ +function formatSubplot(handle,varargin) + +args.fs = 7; +args.xl = []; +args.yl = []; +args.box = []; +args.ax = []; +args.lim = []; +args.tt = []; +args.xt = []; +args.yt =[]; +args = parseVarArgs(args,varargin{:}); + +set(handle,'fontsize',args.fs) +if ~isempty(args.xl) + xlabel(handle,args.xl) +end +if ~isempty(args.yl) + ylabel(handle,args.yl) +end +if ~isempty(args.tt) + title(handle,args.tt) +end +if ~isempty(args.box) + set(handle,'box',args.box) +end +if ~isempty(args.ax) + axis(handle,args.ax) +end +if ~isempty(args.lim) + axis(handle,args.lim) +end +if ~isempty(args.yt) + set(handle,'ytick',args.yt) +end +if ~isempty(args.xt) + set(handle,'xtick',args.xt) +end \ No newline at end of file diff --git a/functions/other/nancircstat/matlab.mat b/functions/other/nancircstat/matlab.mat new file mode 100644 index 0000000..cb682af Binary files /dev/null and b/functions/other/nancircstat/matlab.mat differ diff --git a/functions/other/nancircstat/nancirc_kurtosis.m b/functions/other/nancircstat/nancirc_kurtosis.m new file mode 100644 index 0000000..edc7415 --- /dev/null +++ b/functions/other/nancircstat/nancirc_kurtosis.m @@ -0,0 +1,41 @@ +function [k k0] = circ_kurtosis(alpha, w) + +% [k k0] = circ_kurtosis(alpha,w) +% Calculates a measure of angular kurtosis. +% +% Input: +% alpha sample of angles +% [w weightings in case of binned angle data] +% +% Output: +% k kurtosis (from Pewsey) +% +% References: +% Pewsey, Metrika, 2004 +% Fisher, Circular Statistics, p. 34 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de + +alpha = alpha(:); + +if nargin < 2 + w = ones(size(alpha)); +else + w = w(:); +end + +% compute mean direction +R = circ_var(alpha,w); +theta = nancirc_mean(alpha,w); +[foo rho2] = circ_moment(alpha,w,2,true); +[foo foo2 mu2] = circ_moment(alpha,w,2,false); + +% compute skewness +% k = w'*(cos(2*(circ_dist(alpha,theta))))/sum(w); +k = (nancov(w',(cos(2*(circ_dist(alpha,theta)))))*size(w,1))/sum(w); + +k0 = (rho2*cos(circ_dist(mu2,2*theta))-R^4)/(1-R)^2; % (formula 2.29) + diff --git a/functions/other/nancircstat/nancirc_median.m b/functions/other/nancircstat/nancirc_median.m new file mode 100644 index 0000000..cf6dbd0 --- /dev/null +++ b/functions/other/nancircstat/nancirc_median.m @@ -0,0 +1,57 @@ +function md = circ_median(alpha,dim) +% +% mu = circ_median(alpha, w) +% Computes the median direction for circular data. +% +% Input: +% alpha sample of angles in radians +% +% Output: +% mu mean direction +% +% PHB 3/19/2009 +% +% References: +% Biostatistical Analysis, J. H. Zar (26.6) +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +% if size(alpha,2) > size(alpha,1) +% alpha = alpha'; +% end +alpha = mod(alpha,2*pi); +n = length(alpha); + +m1 = (sum(circ_dist2(alpha,alpha)>0,dim)); +m2 = (sum(circ_dist2(alpha,alpha)<0,dim)); + +dm = abs(m1-m2); +dm = abs(m1-m2); +% if mod(n,2)==1 + [m idx] = min(dm,[],dim); +% else +% m = min(dm); +% idx = find(dm==m,2); +% end +% if dim==1 +% [m idx] = min(dm,[],1); +% elseif dim==2 +% m = min(dm); +% idx = find(dm==m); +% end + +if m > 1 + warning('Ties detected.') %#ok +end + +% md = nancirc_mean(alpha(idx),dim); +md = nancirc_mean(alpha(idx),dim); + +if abs(circ_dist(nancirc_mean(alpha,dim),md)) > abs(circ_dist(nancirc_mean(alpha,dim),md+pi)) + md = mod(md+pi,2*pi); +end + + \ No newline at end of file diff --git a/functions/other/nancircstat/nancirc_skewness.m b/functions/other/nancircstat/nancirc_skewness.m new file mode 100644 index 0000000..d78c011 --- /dev/null +++ b/functions/other/nancircstat/nancirc_skewness.m @@ -0,0 +1,41 @@ +function [b b0] = circ_skewness(alpha,dim, w) + +% [b b0] = circ_skew(alpha,w) +% Calculates a measure of angular skewness. +% +% Input: +% alpha sample of angles +% [w weightings in case of binned angle data] +% +% Output: +% b skewness (from Pewsey) +% b0 alternative skewness measure (from Fisher) +% +% References: +% Pewsey, Metrika, 2004 +% Statistical analysis of circular data, Fisher, p. 34 +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de + +alpha = alpha(:); + +if nargin < 3 + w = ones(size(alpha)); +else + w = w(:); +end + +% compute neccessary values +R = circ_var(alpha,w); +theta = nancirc_mean(alpha,dim,w); +[foo rho2 mu2] = circ_moment(alpha,w,2,true); + +% compute skewness +% b = w'*(sin(2*(circ_dist(alpha,theta))))/sum(w); +b = (nancov(w',(sin(2*(circ_dist(alpha,theta)))))*size(w,1))/sum(w); +b0 = rho2*sin(circ_dist(mu2,2*theta))/(1-R)^(2/3); % (formula 2.29) + + diff --git a/functions/other/nancircstat/nancirc_var.m b/functions/other/nancircstat/nancirc_var.m new file mode 100644 index 0000000..ff3dd84 --- /dev/null +++ b/functions/other/nancircstat/nancirc_var.m @@ -0,0 +1,48 @@ +function s = circ_var(alpha, w, d) +% s = circ_var(alpha, w, d) +% Computes circular variance for circular data +% (equ. 26.17, Zar). +% +% Input: +% alpha sample of angles in radians +% [w number of incidences in case of binned angle data] +% [d spacing of bin centers for binned data, if supplied +% correction factor is used to correct for bias in +% estimation of r] +% +% Output: +% s circular variance +% +% PHB 6/7/2008 +% +% References: +% Statistical analysis of circular data, N.I. Fisher +% Topics in circular statistics, S.R. Jammalamadaka et al. +% Biostatistical Analysis, J. H. Zar +% +% Circular Statistics Toolbox for Matlab + +% By Philipp Berens, 2009 +% berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html + +% check vector size +if size(alpha,2) > size(alpha,1) + alpha = alpha'; +end + +if nargin<2 + % if no specific weighting has been specified + % assume no binning has taken place + w = ones(size(alpha)); +end + +if nargin<3 + % per default do not apply correct for binned data + d = 0; +end + +% compute mean resultant vector length +r = nancirc_r(alpha,w,d); + +% apply transformation to var +s = 1 - r; \ No newline at end of file diff --git a/functions/other/nancircstat/neurodata.mat b/functions/other/nancircstat/neurodata.mat new file mode 100644 index 0000000..3c2f53d Binary files /dev/null and b/functions/other/nancircstat/neurodata.mat differ diff --git a/functions/other/nancov_circ.m b/functions/other/nancov_circ.m new file mode 100644 index 0000000..52472d1 --- /dev/null +++ b/functions/other/nancov_circ.m @@ -0,0 +1,74 @@ +% NANCOV.M +% Program to compute a covariance matrix ignoring NaNs +% +% Usage: C = nancov(A,B) +% +% NANCOV calculates the matrix product A*B ignoring NaNs by replacing them +% with zeros, and then normalizing each element C(i,j) by the number of +% non-NaN values in the vector product A(i,:)*B(:,j). +% +% A - left hand matrix to be multiplied +% B - right hand matrix to be multiplied +% C - resultant covariance matrix +% Example: A = [1 NaN 1] , B = [1 +% 1 +% 1] +% then nancov(A,B) is 2/2 = 1 +% +% +%Based on code by: +%http://pordlabs.ucsd.edu/matlab/nan.htm ; +% +%Modified by M. Van Wyk de Vries for GIV toolbox. +% + +function [save_stats]=nancov_circ(A,B,dim) + +if dim == 2 + save_stats = NaN(size(A,1),1); + axis = size(A,1); +elseif dim == 1 + save_stats = NaN(1,size(A,2)); + axis = size(A,2); +else + disp('Maximum 2 dimensions allowed.') +end + +for loop = 1:axis + + %Crop out one column + if dim == 2 + A1 = A(loop,:); + B1 = B(loop,:); + elseif dim == 1 + A1 = A(:,loop); + B1 = B(:,loop); + end + + %Check if all NaN, do not do calculations if so to save time + if any(~isnan(A1))&&any(~isnan(B1)) + NmatA=~isnan(A1); % Counter matrix + NmatB=~isnan(B1); + + A1(isnan(A1))=0; % Replace NaNs in A,B, and counter matrices + B1(isnan(B1))=0; % with zeros + + if dim == 2 + Npts=NmatA*NmatB'; + C=(A1*B1')./Npts; + elseif dim == 1 + Npts=NmatA'*NmatB; + C=(A1'*B1)./Npts; + end + + else + C = NaN; + end + + if dim == 2 + save_stats(loop,1) = C; + elseif dim == 1 + save_stats(1,loop) = C; + end + +end diff --git a/functions/other/nanfill_time.m b/functions/other/nanfill_time.m new file mode 100644 index 0000000..61e18e7 --- /dev/null +++ b/functions/other/nanfill_time.m @@ -0,0 +1,81 @@ +function out = nanfill_time(in, ~, nantolerance, smoothsize) +%This function fills in the NaN values in a given matrix where they are not +%adjacent to a large number of other NaN values. It then smooths the +%resulting matrix on a predefined size smoothing matrix. +% nantolerance range = 0 to 10 +% smoothsize range >2, thanks to The Cryosphere reviewer and function +% 'make_mask.m' + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +%% Find the right NaNs + +% Make NaN values a very large negative number + +nanvalue = -1e10; + +if smoothsize == 2 +numelts = 4; +elseif smoothsize == 3 +numelts = 8; +elseif smoothsize == 4 +numelts = 12; +elseif smoothsize == 5 +numelts = 24; +end + +% Find the threshold value at which the average has too many nans +thresholdvalue = (nanvalue * nantolerance + (numelts-nantolerance) * 0)/numelts; +in_working = in; +in_working(isnan(in)) = nanvalue; + +% Make sure size of mask is correct +[mask] = make_mask(smoothsize); + +% Identify where too many NaNs are present +in_working = conv2(in_working, mask, 'same')/numelts; +in_working(in_working<=thresholdvalue) = -999; +in_working(in_working~=-999) = 0; +in_working(in_working==-999) = 1; +in_nan = in; +in_nan(~isnan(in))=10; + +%in with matrix 10 where not NaN and 1 where NaN +in_nan(isnan(in)) = 1; +in_nansbad = in_working.*in_nan; + +%now this is a matrix with a 1 where NaNs are present AND are too close to +%too many other NaNs +in_nansbad(in_nansbad~=1)=0; + +%% Replace the NaNs +nanX = isnan(in); + +%start off by making NaNs zero so that the convolution is possible +in(nanX) = 0; +means = conv2(in, mask, 'same') ./ ... + conv2(~nanX, mask, 'same'); +in(nanX) = means(nanX); +in(in_nansbad==1)=NaN; +out = in; diff --git a/functions/other/nanfill_timeandspace.m b/functions/other/nanfill_timeandspace.m new file mode 100644 index 0000000..e7e1cb4 --- /dev/null +++ b/functions/other/nanfill_timeandspace.m @@ -0,0 +1,78 @@ +function out = nanfill_timeandspace(in, ~, nantolerance, smoothsize) +%This function fills in the NaN values in a given matrix where they are not +%adjacent to a large number of other NaN values. It then smooths the +%resulting matrix on a predefined size smoothing matrix. +% nantolerance range = 0 to 10 +% smoothsize range >2, thanks to The Cryosphere reviewer and function +% 'make_mask.m' + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +%% Find the right NaNs + +% Make NaN values a very large negative number + +nanvalue = -1e10; +if smoothsize == 2 + numelts = 4; +elseif smoothsize == 3 + numelts = 8; +elseif smoothsize == 4 + numelts = 12; +elseif smoothsize == 5 + numelts = 24; +end + +% Find the threshold value at which the average has too many nans +thresholdvalue = (nanvalue * nantolerance + (numelts-nantolerance) * 0)/numelts; +in_working = in; +in_working(isnan(in)) = nanvalue; + +% Make sure size of mask is correct +[mask] = make_mask(smoothsize); + +% Identify where too many NaNs are present +in_working = conv2(in_working, mask, 'same')/numelts; +in_working(in_working<=thresholdvalue) = -999; +in_working(in_working~=-999) = 0; +in_working(in_working==-999) = 1; +in_nan = in; +in_nan(~isnan(in))=10; + +%in with matrix 10 where not NaN and 1 where NaN +in_nan(isnan(in)) = 1; +in_nansbad = in_working.*in_nan; + +%now this is a matrix with a 1 where NaNs are present AND are too close to +%too many other NaNs +in_nansbad(in_nansbad~=1)=0; + +%% Replace the NaNs +nanX = isnan(in); +%start off by making NaNs zero so that the convolution is possible +in(nanX) = 0; +means = conv2(in, mask, 'same') ./ ... + conv2(~nanX, mask, 'same'); +in(nanX) = means(nanX); +in(in_nansbad==1)=NaN; +out = in; diff --git a/functions/other/nanfillsm.m b/functions/other/nanfillsm.m new file mode 100644 index 0000000..54cea6c --- /dev/null +++ b/functions/other/nanfillsm.m @@ -0,0 +1,102 @@ +function out = nanfillsm(in, inputs, nantolerance, smoothsize); +%This function fills in the NaN values in a given matrix where they are not +%adjacent to a large number of other NaN values. It then smooths the +%resulting matrix on a predefined size smoothing matrix. +% nantolerance range = 0 to 10 +% smoothsize range >2, thanks to The Cryosphere reviewer and function +% 'make_mask.m' + + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota + + %Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +%MORE DISCLAIMERS, LINK TO CODE, LINK TO PAPER? +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Latest update Spring 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +%% Find the right NaNs + +% Make NaN values a very large negative number + +nanvalue = -1e10; +if smoothsize == 2 + numelts = 4; +elseif smoothsize == 3 + numelts = 8; +elseif smoothsize == 4 + numelts = 12; +elseif smoothsize == 5 + numelts = 24; +end + +% Find the threshold value at which the average has too many nans +thresholdvalue = (nanvalue * nantolerance + (numelts-nantolerance) * 0)/numelts; +in_working = in; +in_working(isnan(in)) = nanvalue; + +% Make sure size of mask is correct +[mask] = make_mask(smoothsize); + +% Identify where too many NaNs are present +in_working = conv2(in_working, mask, 'same')/numelts; +in_working(in_working<=thresholdvalue) = -999; +in_working(in_working~=-999) = 0; +in_working(in_working==-999) = 1; +in_nan = in; +in_nan(~isnan(in))=10; + +%in with matrix 10 where not NaN and 1 where NaN +in_nan(isnan(in)) = 1; +in_nansbad = in_working.*in_nan; + +%now this is a matrix with a 1 where NaNs are present AND are too close to +%too many other NaNs +in_nansbad(in_nansbad~=1)=0; + +%Now lets find which ones are NOT too close +in_nan = zeros(size(in)); +in_nan(isnan(in)) = 1; + +%now this is a matrix with a 1 where NaNs are present AND are NOT close to +%too many other NaNs +in_goodnan = in_nan - in_nansbad; + + +%% Replace the NaNs +nanX = isnan(in); + +%start off by making NaNs zero so that the convolution is possible +in(nanX) = 0; +means = conv2(in, mask, 'same') ./ ... + conv2(~nanX, mask, 'same'); +in(nanX) = means(nanX); +in(in_nansbad==1)=NaN; + +%% Smooth the whole matrix +in_working = in; +in_working(isnan(in)) = -999; +in_working(in_goodnan==1) = 0; +nanX = isnan(in); +in(nanX) = 0; +out = conv2(in, mask, 'same') ./ ... + conv2(~nanX, mask, 'same'); +out(in_working==-999)=NaN; +out(in_nansbad==1)=NaN; + + + + + diff --git a/functions/other/save_images.m b/functions/other/save_images.m new file mode 100644 index 0000000..9cb808f --- /dev/null +++ b/functions/other/save_images.m @@ -0,0 +1,336 @@ +function [images] = save_images (images, inputs, images_stack, monthly_averages) +% +%This function saves the outputs into one file, named "Results" according +%to user determined parameters. +% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +%Skip if nothing is to be saved. +if strcmpi(inputs.savearrays, 'Yes') | strcmpi(inputs.savekeyvel, 'Yes') | strcmpi(inputs.savegeotiff, 'Yes') + + %Check if Results folder exists yet + filename = strcat(inputs.folder,'/Results') + if ~exist(filename) + mkdir(filename) + end + + %Create main folder + mkdir(strcat(filename,'/',inputs.name)) + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %SAVE MATLAB ARRAYS + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + if strcmpi(inputs.savearrays, 'Yes') + %Create subfolder for matlab arrays + mkdir(strcat(filename,'/',inputs.name,'/Matlab data files')) + %Save images, Inputs, Images_stack and Monthly_averages in this folder + save(strcat(filename,'/',inputs.name,'/Matlab data files/','Run Input Parameters'),'inputs'); + save(strcat(filename,'/',inputs.name,'/Matlab data files/',... + 'Raw Images array'),'images','-v7.3'); %v7.3 allows large files to be saved when they otherwise would fail. + save(strcat(filename,'/',inputs.name,'/Matlab data files/',... + 'Stacked and averaged data array'),'images_stack','-v7.3');%v7.3 allows large files to be saved when they otherwise would fail. + save(strcat(filename,'/',inputs.name,'/Matlab data files/','Monthly averages data array'),'monthly_averages'); + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %SAVE PNG IMAGES OF DATA% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + if strcmpi(inputs.savekeyvel, 'Yes') + mkdir(strcat(filename,'/',inputs.name,'/Data Figures (Images)')) + %First save flow direction and velocity statistics + mkdir(strcat(filename,'/',inputs.name,'/Data Figures (Images)','/Mean, Standard Deviation and other statistics')) + %Load background image for all datasets + if ~exist(strcat(inputs.folder,'/save_image.png')) && ~exist(strcat(inputs.folder,'/save_image.jpg')) + disp('You need to save one of your images (ideally the best one) in the same folder as the others, under the name "save_image".') + disp('Please do this and run this function again. Do not worry, your data has not been lost :)') + end + + if exist(fullfile(fullfile(inputs.folder,'/save_image.png'))) > 0 + save_image = flipud(imread(fullfile(inputs.folder,'/save_image.png'))); + elseif exist(fullfile(fullfile(inputs.folder,'/save_image.jpg'))) >0 + save_image = flipud(imread(fullfile(inputs.folder,'/save_image.jpg'))); + end + + %First velocities (different labels) + for images_stack_loop = 3:2:size(images_stack,1)-2 + %Saving hidden figure + h = figure;set(h, 'Visible', 'off'); + + if strcmpi(inputs.isgeotiff,'No') + m_proj('lambert','lon',[inputs.minlon inputs.maxlon],'lat',[inputs.minlat inputs.maxlat]); + m_image([inputs.minlon inputs.maxlon],[inputs.minlat inputs.maxlat],save_image); + brighten(.5); + alpha(0.7) + hold on + m_image([inputs.minlon inputs.maxlon],[inputs.minlat inputs.maxlat],images_stack{images_stack_loop,2}); + else + m_proj('lambert','lon',[min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + 'lat',[min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)]); + m_image([min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + [min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)],save_image); + brighten(.5); + alpha(0.7) + hold on + m_image([min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + [min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)],images_stack{images_stack_loop,2}); + end + m_grid('xtick',10,'ytick',10,'box','fancy','tickdir','in') + title(images_stack{images_stack_loop,1},'FontSize',25,'FontName', 'Times New Roman'); + colormap([ flipud(cbrewer('seq', 'Blues', 33));cbrewer('seq', 'Reds', 66);]); + hold off + col = colorbar; + ylabel(col, 'Ice Velocity (m/year)','FontSize',15,'FontName', 'Times New Roman') + set(gcf, 'Units', 'Inches', 'Position', [0, 0, 17, 20], 'PaperUnits', 'Inches', 'PaperSize', [17, 20]) + saveas(h,strcat(filename,'/',inputs.name,'/Data Figures (Images)',... + '/Mean, Standard Deviation and other statistics/',images_stack{images_stack_loop,1},'.',inputs.imageformat)); + end + + %Percentage error + for images_stack_loop = 13 + %Saving hidden figure + h = figure;set(h, 'Visible', 'off'); + if strcmpi(inputs.isgeotiff,'No') + m_proj('lambert','lon',[inputs.minlon inputs.maxlon],'lat',[inputs.minlat inputs.maxlat]); + m_image([inputs.minlon inputs.maxlon],[inputs.minlat inputs.maxlat],save_image); + brighten(.5); + alpha(0.7) + hold on + m_image([inputs.minlon inputs.maxlon],[inputs.minlat inputs.maxlat],images_stack{images_stack_loop,2}); + else + m_proj('lambert','lon',[min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + 'lat',[min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)]); + m_image([min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + [min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)],save_image); + brighten(.5); + alpha(0.7) + hold on + m_image([min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + [min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)],images_stack{images_stack_loop,2}); + end + m_grid('xtick',10,'ytick',10,'box','fancy','tickdir','in') + title(images_stack{images_stack_loop,1},'FontSize',25,'FontName', 'Times New Roman'); + colormap([ flipud(cbrewer('seq', 'Blues', 33));cbrewer('seq', 'Reds', 66);]); + hold off + col = colorbar; + ylabel(col, 'Percentage variation in velocity','FontSize',15,'FontName', 'Times New Roman') + set(gcf, 'Units', 'Inches', 'Position', [0, 0, 17, 20], 'PaperUnits', 'Inches', 'PaperSize', [17, 20]) + saveas(h,strcat(filename,'/',inputs.name,'/Data Figures (Images)',... + '/Mean, Standard Deviation and other statistics/',images_stack{images_stack_loop,1},'.',inputs.imageformat)); + end + + %Then flow directions(different labels) + for images_stack_loop = 4:2:size(images_stack,1)-1 + %Saving hidden figure + h = figure;set(h, 'Visible', 'off'); + if strcmpi(inputs.isgeotiff,'No') + m_proj('lambert','lon',[inputs.minlon inputs.maxlon],'lat',[inputs.minlat inputs.maxlat]); + m_image([inputs.minlon inputs.maxlon],[inputs.minlat inputs.maxlat],save_image); + brighten(.5); + alpha(0.7) + hold on + m_image([inputs.minlon inputs.maxlon],[inputs.minlat inputs.maxlat],images_stack{images_stack_loop,2}); + else + m_proj('lambert','lon',[min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + 'lat',[min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)]); + m_image([min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + [min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)],save_image); + brighten(.5); + alpha(0.7) + hold on + m_image([min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + [min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)],images_stack{images_stack_loop,2}); + end + m_grid('xtick',10,'ytick',10,'box','fancy','tickdir','in') + title(images_stack{images_stack_loop,1},'FontSize',25,'FontName', 'Times New Roman'); + colormap([ flipud(cbrewer('seq', 'Greens', 50));cbrewer('seq', 'Blues', 50);flipud(cbrewer('seq', 'Purples', 50));cbrewer('seq', 'Reds', 50)]); + hold off + col = colorbar; + ylabel(col, 'Flow direction (degrees)','FontSize',15,'FontName', 'Times New Roman') + set(gcf, 'Units', 'Inches', 'Position', [0, 0, 17, 20], 'PaperUnits', 'Inches', 'PaperSize', [17, 20]) + saveas(h,strcat(filename,'/',inputs.name,'/Data Figures (Images)',... + '/Mean, Standard Deviation and other statistics/',images_stack{images_stack_loop,1},'.',inputs.imageformat)); +end + +%Next save average monthly values +mkdir(strcat(filename,'/',inputs.name,'/Data Figures (Images)','/Average monthly values')) + +% Velocity +for images_stack_loop = 1:size(monthly_averages,1) + %Saving hidden figure + h = figure;set(h, 'Visible', 'off'); + if strcmpi(inputs.isgeotiff,'No') + m_proj('lambert','lon',[inputs.minlon inputs.maxlon],'lat',[inputs.minlat inputs.maxlat]); + m_image([inputs.minlon inputs.maxlon],[inputs.minlat inputs.maxlat],save_image); + brighten(.5); + alpha(0.7) + hold on + m_image([inputs.minlon inputs.maxlon],[inputs.minlat inputs.maxlat],monthly_averages{images_stack_loop,3}); + else + m_proj('lambert','lon',[min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + 'lat',[min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)]); + m_image([min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + [min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)],save_image); + brighten(.5); + alpha(0.7) + hold on + m_image([min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + [min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)],monthly_averages{images_stack_loop,3}); + end + m_grid('xtick',10,'ytick',10,'box','fancy','tickdir','in') + labeltextv = ['Average velocity for' ' ' num2str(monthly_averages{images_stack_loop,2}),... + ' ',num2str(monthly_averages{images_stack_loop,1})]; + title(labeltextv,'FontSize',25,'FontName', 'Times New Roman'); + colormap([ flipud(cbrewer('seq', 'Blues', 33));cbrewer('seq', 'Reds', 66);]); + hold off + col = colorbar; + ylabel(col, 'Ice Velocity (m/year)','FontSize',15,'FontName', 'Times New Roman') + set(gcf, 'Units', 'Inches', 'Position', [0, 0, 17, 20], 'PaperUnits', 'Inches', 'PaperSize', [17, 20]) + saveas(h,strcat(filename,'/',inputs.name,'/Data Figures (Images)',... + '/Average monthly values/',labeltextv,'_(',monthly_averages{images_stack_loop,5},')','.',inputs.imageformat)); +end + + +% Flow directions + +for images_stack_loop = 1:size(monthly_averages,1) + %Saving hidden figure + h = figure;set(h, 'Visible', 'off'); + if strcmpi(inputs.isgeotiff,'No') + m_proj('lambert','lon',[inputs.minlon inputs.maxlon],'lat',[inputs.minlat inputs.maxlat]); + m_image([inputs.minlon inputs.maxlon],[inputs.minlat inputs.maxlat],save_image); + brighten(.5); + alpha(0.7) + hold on + m_image([inputs.minlon inputs.maxlon],[inputs.minlat inputs.maxlat],monthly_averages{images_stack_loop,4}); + else + m_proj('lambert','lon',[min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + 'lat',[min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)]); + m_image([min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + [min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)],save_image); + brighten(.5); + alpha(0.7) + hold on + m_image([min(inputs.geotifflocationdata.CornerCoords.Lon) max(inputs.geotifflocationdata.CornerCoords.Lon)],... + [min(inputs.geotifflocationdata.CornerCoords.Lat) max(inputs.geotifflocationdata.CornerCoords.Lat)],monthly_averages{images_stack_loop,4}); + end + m_grid('xtick',10,'ytick',10,'box','fancy','tickdir','in') + labeltextfd = ['Average flow direction for' ' ' num2str(monthly_averages{images_stack_loop,2}),... + ' ',num2str(monthly_averages{images_stack_loop,1})]; + title(labeltextfd,'FontSize',25,'FontName', 'Times New Roman'); + colormap([ flipud(cbrewer('seq', 'Blues', 33));cbrewer('seq', 'Reds', 66);]); + hold off + col = colorbar; + ylabel(col, 'Ice Velocity (m/year)','FontSize',15,'FontName', 'Times New Roman') + set(gcf, 'Units', 'Inches', 'Position', [0, 0, 17, 20], 'PaperUnits', 'Inches', 'PaperSize', [17, 20]) + saveas(h,strcat(filename,'/',inputs.name,'/Data Figures (Images)',... + '/Average monthly values/',labeltextfd,'_(',monthly_averages{images_stack_loop,5},')','.',inputs.imageformat)); +end + + +end + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%SAVE GEOREFERENCED VELOCITY DATA% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +if strcmpi(inputs.savegeotiff, 'Yes') + mkdir(strcat(filename,'/',inputs.name,'/Georeferenced Velocity Data')) + + %Create location data that will be used for georeferencing all arrays + if strcmpi(inputs.isgeotiff,'No') + location_data = georasterref('RasterSize',size(images_stack{3, 2}),'LatitudeLimits',... + [inputs.minlat ,inputs.maxlat ],'LongitudeLimits',[inputs.minlon ,inputs.maxlon ]); + + %First save flow direction and velocity statistics + mkdir(strcat(filename,'/',inputs.name,'/Georeferenced Velocity Data','/Mean, Standard Deviation and other statistics')) + + for images_stack_loop = 3:size(images_stack,1) + geotiffwrite(strcat(filename,'/',inputs.name,'/Georeferenced Velocity Data',... + '/Mean, Standard Deviation and other statistics/',images_stack{images_stack_loop,1},'.tif')... + ,images_stack{images_stack_loop,2},location_data) + end + + %Next save average monthly values + mkdir(strcat(filename,'/',inputs.name,'/Georeferenced Velocity Data','/Average monthly values')) + + for images_stack_loop = 1:size(monthly_averages,1) + labeltextv = ['Average velocity for' ' ' num2str(monthly_averages{images_stack_loop,2}),... + ' ',num2str(monthly_averages{images_stack_loop,1})]; + geotiffwrite(strcat(filename,'/',inputs.name,'/Georeferenced Velocity Data',... + '/Average monthly values/',labeltextv,'_(',monthly_averages{images_stack_loop,5},')','.tif'),... + monthly_averages{images_stack_loop,3},location_data) + end + + for images_stack_loop = 1:size(monthly_averages,1) + labeltextfd = ['Average flow direction for' ' ' num2str(monthly_averages{images_stack_loop,2}),... + ' ',num2str(monthly_averages{images_stack_loop,1})]; + geotiffwrite(strcat(filename,'/',inputs.name,'/Georeferenced Velocity Data',... + '/Average monthly values/',labeltextfd,'_(',monthly_averages{images_stack_loop,5},')','.tif'),... + monthly_averages{images_stack_loop,4},location_data) + end + else + %First save flow direction and velocity statistics + mkdir(strcat(filename,'/',inputs.name,'/Georeferenced Velocity Data','/Mean, Standard Deviation and other statistics')) + + % Edit the mappostings portion + inputs.geotiffreference = maprefpostings(inputs.geotiffreference.XWorldLimits,... + inputs.geotiffreference.YWorldLimits,... + [size(images_stack{3,2},1),size(images_stack{3,2},2)],... + 'ColumnsStartFrom',inputs.geotiffreference.ColumnsStartFrom,... + 'RowsStartFrom',inputs.geotiffreference.RowsStartFrom); + + for images_stack_loop = 3:size(images_stack,1) + geotiffwrite(strcat(filename,'/',inputs.name,'/Georeferenced Velocity Data',... + '/Mean, Standard Deviation and other statistics/',images_stack{images_stack_loop,1},'.tif')... + ,flipud(images_stack{images_stack_loop,2}),inputs.geotiffreference,'GeoKeyDirectoryTag',inputs.geotifflocationdata.GeoTIFFTags.GeoKeyDirectoryTag) + end + + %Next save average monthly values + mkdir(strcat(filename,'/',inputs.name,'/Georeferenced Velocity Data','/Average monthly values')) + + for images_stack_loop = 1:size(monthly_averages,1) + labeltextv = ['Average velocity for' ' ' num2str(monthly_averages{images_stack_loop,2}),... + ' ',num2str(monthly_averages{images_stack_loop,1})]; + geotiffwrite(strcat(filename,'/',inputs.name,'/Georeferenced Velocity Data',... + '/Average monthly values/',labeltextv,'_(',monthly_averages{images_stack_loop,5},')','.tif'),... + flipud(monthly_averages{images_stack_loop,3}),inputs.geotiffreference,'GeoKeyDirectoryTag',inputs.geotifflocationdata.GeoTIFFTags.GeoKeyDirectoryTag) + end + + for images_stack_loop = 1:size(monthly_averages,1) + labeltextfd = ['Average flow direction for' ' ' num2str(monthly_averages{images_stack_loop,2}),... + ' ',num2str(monthly_averages{images_stack_loop,1})]; + geotiffwrite(strcat(filename,'/',inputs.name,'/Georeferenced Velocity Data',... + '/Average monthly values/',labeltextfd,'_(',monthly_averages{images_stack_loop,5},')','.tif'),... + flipud(monthly_averages{images_stack_loop,4}),inputs.geotiffreference,'GeoKeyDirectoryTag',inputs.geotifflocationdata.GeoTIFFTags.GeoKeyDirectoryTag) + end + + end + +end + +else + disp('You chose not to save any files. You may edit the inputs file, rerun loadinpus.mat and then rerun save_images.mat if you have decided to save') +end diff --git a/functions/other/save_raw_array.m b/functions/other/save_raw_array.m new file mode 100644 index 0000000..465fcc7 --- /dev/null +++ b/functions/other/save_raw_array.m @@ -0,0 +1,48 @@ +function save_raw_array(images,inputs) +% +%This functions saves the raw images array prior to filtering. This +%preserves the raw data and serves as a backup in case an error occurs +%later. Run portions of the GIV_main if an error occurs in filtering and +%you do not wish to recalculate image pairs. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +%Check if Results folder exists yet +filename = strcat(inputs.folder,'/Results'); +if ~exist(filename) + mkdir(filename) +end + +%Create main folder +mkdir(strcat(filename,'/',inputs.name)) + +%SAVE +if strcmpi(inputs.savearrays, 'Yes') +%Create subfolder for matlab arrays +mkdir(strcat(filename,'/',inputs.name,'/Initial data backup')) + +%Save images, Inputs, Images_stack and Monthly_averages in this folder + +save(strcat(filename,'/',inputs.name,'/Initial data backup/','Raw Images array'),'images','-v7.3'); +end + diff --git a/functions/other/smooth_snr.m b/functions/other/smooth_snr.m new file mode 100644 index 0000000..80791e0 --- /dev/null +++ b/functions/other/smooth_snr.m @@ -0,0 +1,46 @@ +function out = smooth_snr(in, inputs); +%This function smooths the signal to noise ratio matrixes. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + + +%% Find the right NaNs + +% Make NaN values a very large negative number +smoothscale1 = round(0.1*size(in,1)); +smoothscale2 = round(0.1*size(in,2)); +mask = ones(smoothscale1,smoothscale2); + +%% Smooth the whole matrix +in_working = in; +in_working(isnan(in)) = -999; + nanX = isnan(in); + in(nanX) = 0; + out = conv2(in, mask, 'same') ./ ... + conv2(~nanX, mask, 'same'); +out(in_working==-999)=NaN; + + + + + + diff --git a/functions/other/velocitytimeplot.m b/functions/other/velocitytimeplot.m new file mode 100644 index 0000000..b76b3f6 --- /dev/null +++ b/functions/other/velocitytimeplot.m @@ -0,0 +1,340 @@ + function velocitytimeplot(vtplotinputs) +%This function loads the previously saved data, and according to the inputs +%of a user plots the monthly averages and/or the raw data at one point over +%time. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + +%% First load the previously saved data in + +my_path_velocitytimeplot = uigetdir('./Results','SELECT YOUR SAVE FILE'); +load(strcat(my_path_velocitytimeplot,'/Matlab data files/Run input parameters.mat')); +load(strcat(my_path_velocitytimeplot,'/Matlab data files/Raw Images array.mat')); +load(strcat(my_path_velocitytimeplot,'/Matlab data files/Stacked and averaged data array.mat')); +load(strcat(my_path_velocitytimeplot,'/Matlab data files/Monthly averages data array.mat')); + +%DATA IS NOW LOADED BACK IN. DOING IT THIS WAY MEAN THIS FUNCTION CAN BE +%RUN INDEPENDANTLY OF THE MAIN RUN AT ANY LATER TIME. +%% Calculate positions of lat long data provided on grid, cycle through different data provided +for latlongloop = 1:size(vtplotinputs{1,2}, 1) + if vtplotinputs{1,2}(latlongloop)~=0 + longpoint = vtplotinputs{1,2}(latlongloop,2); + latpoint = vtplotinputs{1,2}(latlongloop,1); + + % Find lat/long of point in image + x_position = round(inputs.sizevel(2)*(longpoint-inputs.minlon)/(inputs.maxlon-inputs.minlon)); + y_position = round(inputs.sizevel(1)*(latpoint-inputs.minlat)/(inputs.maxlat-inputs.minlat)); + + % Check point is not on the edge of the image + if x_position > inputs.sizevel(2) - vtplotinputs{2,2} + x_position = inputs.sizevel(2) - vtplotinputs{2,2} ; + end + + if x_position < 1 + vtplotinputs{2,2} + x_position = 1 + vtplotinputs{2,2}; + end + + if y_position > inputs.sizevel(1) - vtplotinputs{2,2} + y_position = inputs.sizevel(1) - vtplotinputs{2,2} ; + end + + if y_position < 1 + vtplotinputs{2,2} + y_position = 1 + vtplotinputs{2,2}; + end + + %% Calculate time series for raw data + if strcmpi(vtplotinputs{3,2}, 'Yes') + + %% Load the time data for raw velocities + meta_dum = 0; + array_pos = 0; + emptycount_inner = 0; + emptycount_outer = 0; + number_in_range = 0; + number_with_values = (size(images,2)-6)/2; + for i = 8:2:8+(number_with_values*2)-1 + for i2 = 2:size(images,1) + if ~isempty(images{i2,i}) + number_in_range = number_in_range+1; + end + end + end + + full_date = NaN(number_in_range,1); + + for time_loop = 1:number_with_values + dum1 = time_loop + 6 + array_pos; + for inner_loop = 2:inputs.numimages-time_loop + if ~isempty(images{inner_loop,dum1}) + %calculate time interval + time_gap = (images{inner_loop+time_loop,5}-images{inner_loop,5}); + % Here calculates a median date for the interval that we will use + date_current = round(images{inner_loop+time_loop,4}-(time_gap/2)); + full_date(inner_loop+meta_dum-1-emptycount_inner-emptycount_outer,1)= date_current; + full_date(inner_loop+meta_dum-1-emptycount_inner-emptycount_outer,2)= time_gap; + else + emptycount_inner = emptycount_inner + 1; + end + end + emptycount_outer = emptycount_outer + emptycount_inner; + emptycount_inner = 0; + meta_dum = meta_dum + inputs.numimages-time_loop-1; + array_pos = array_pos + 1; + end + %append this array to the full velocity array + full_velocity_array = NaN(size(images_stack{1,2},1),size(images_stack{1,2},2)+1); + full_velocity_array(:,1) = full_date(:,1); + full_velocity_array(:,2:end) = images_stack{1,2}; + %sort based on date + full_velocity_array = sortrows(full_velocity_array,1); + %Make an array of all the positions to calculate + all_positions = []; + position_place = 1; + for position_loop = x_position - vtplotinputs{2,2} : x_position + vtplotinputs{2,2} + y_moved = abs(vtplotinputs{2,2}-(position_loop-x_position)); + for position_loop_2 = y_position-y_moved : y_position+y_moved + all_positions(position_place,1) = position_loop*inputs.sizevel(1)-position_loop_2+1; + position_place = position_place+1; + end + end + % Calculate mean of all of these positions, for each date. Note the +1 + % because of the date column. + final_velocity_array = []; + for date_loop = 1:size(full_velocity_array,1) + inner_array = []; + for position_loop = 1:size(all_positions,1) + inner_array(position_loop,1) = full_velocity_array(date_loop,all_positions(position_loop)+1); + end + final_velocity_array(date_loop,2) = nanmean(inner_array,'all'); + end + final_velocity_array(:,1) = full_date(:,1); + %Create a new, similar array to save with 4 columns for year, month, day + %and velocity + save_velocity_array = []; + for time_loop = 1:size(final_velocity_array,1) + save_velocity_array(time_loop,1) = year(datetime(full_date(time_loop,1),'ConvertFrom','datenum')); + save_velocity_array(time_loop,2) = month(datetime(full_date(time_loop,1),'ConvertFrom','datenum')); + save_velocity_array(time_loop,3) = day(datetime(full_date(time_loop,1),'ConvertFrom','datenum')); + save_velocity_array(time_loop,4) = final_velocity_array(time_loop,2); + end + + % Now lets save a .csv file of results that can be opened in excel + if ~exist(strcat(my_path_velocitytimeplot,'/csv files of raw timeseries')) + mkdir(strcat(my_path_velocitytimeplot,'/csv files of raw timeseries')); + end + writematrix(save_velocity_array,strcat(my_path_velocitytimeplot,'/csv files of raw timeseries/','Velocities_lat=',num2str(latpoint),'_long=',num2str(longpoint),'.csv')) + + % Finally, let's save a png plot of the image + if ~exist(strcat(my_path_velocitytimeplot,'/png files of raw timeseries')) + mkdir(strcat(my_path_velocitytimeplot,'/png files of raw timeseries')); + end + + %Saving hidden figure + x_axis_date = []; + for i = 1:size(save_velocity_array,1) + x_axis_date(i,1) = save_velocity_array(i,1) + save_velocity_array(i,2)/12 + save_velocity_array(i,3)/365; + end + h = figure;set(h, 'Visible', 'off'); + h = errorbar(x_axis_date(:,1),save_velocity_array(:,4),0.0014*full_date(:,2),'horizontal','LineStyle','none'); + h.Color = [0.2,0.2,0.2,0.1]; + h.CapSize = 0; + saveas(h,strcat(my_path_velocitytimeplot,'/png files of raw timeseries/','Velocities_lat=',num2str(latpoint),'_long=',num2str(longpoint),'.png')) + + % NOW DO THE SAME FOR FLOW DIRECTION IF WANTED + if strcmpi(vtplotinputs{5,2}, 'Yes') + %append this array to the full flow direction array + full_fd_array = NaN(size(images_stack{1,2},1),size(images_stack{1,2},2)+1); + full_fd_array(:,1) = full_date(:,1); + full_fd_array(:,2:end) = images_stack{2,2}; + %sort based on date + full_fd_array = sortrows(full_fd_array,1); + %Make an array of all the positions to calculate + all_positions = []; + position_place = 1; + for position_loop = x_position - vtplotinputs{2,2} : x_position + vtplotinputs{2,2} + y_moved = abs(vtplotinputs{2,2}-(position_loop-x_position)); + for position_loop_2 = y_position-y_moved : y_position+y_moved + all_positions(position_place,1) = position_loop*inputs.sizevel(1)-position_loop_2+1; + position_place = position_place+1; + end + end + % Calculate mean of all of these positions, for each date. Note the +1 + % because of the date column. + final_fd_array = []; + for date_loop = 1:size(full_fd_array,1) + inner_array = []; + for position_loop = 1:size(all_positions,1) + inner_array(position_loop,1) = full_fd_array(date_loop,all_positions(position_loop)+1); + end + final_fd_array(date_loop,2) = nanmean(inner_array,'all'); + end + final_fd_array(:,1) = full_date(:,1); + + %Create a new, similar array to save with 4 columns for year, month, day + %and fd + save_fd_array = []; + for time_loop = 1:size(final_fd_array,1) + save_fd_array(time_loop,1) = year(datetime(full_date(time_loop,1),'ConvertFrom','datenum')); + save_fd_array(time_loop,2) = month(datetime(full_date(time_loop,1),'ConvertFrom','datenum')); + save_fd_array(time_loop,3) = day(datetime(full_date(time_loop,1),'ConvertFrom','datenum')); + save_fd_array(time_loop,4) = final_fd_array(time_loop,2); + end + + % Now lets save a .csv file of results that can be opened in excel + if ~exist(strcat(my_path_velocitytimeplot,'/csv files of raw timeseries')) + mkdir(strcat(my_path_velocitytimeplot,'/csv files of raw timeseries')); + end + writematrix(save_fd_array,strcat(my_path_velocitytimeplot,'/csv files of raw timeseries/','FD_lat=',num2str(latpoint),'_long=',num2str(longpoint),'.csv')) + + % Finally, let's save a png plot of the image + if ~exist(strcat(my_path_velocitytimeplot,'/png files of raw timeseries')) + mkdir(strcat(my_path_velocitytimeplot,'/png files of raw timeseries')); + end + + %Saving hidden figure + for i = 1:size(save_fd_array,1) + x_axis_date(i,1) = save_fd_array(i,1) + save_fd_array(i,2)/12 + save_fd_array(i,3)/365; + end + h = figure;set(h, 'Visible', 'off'); + h = errorbar(x_axis_date(:,1),save_fd_array(:,4),0.0014*full_date(:,2),'horizontal','LineStyle','none'); + h.Color = [0.2,0.2,0.2,0.1]; + h.CapSize = 0; + saveas(h,strcat(my_path_velocitytimeplot,'/png files of raw timeseries/','FD_lat=',num2str(latpoint),'_long=',num2str(longpoint),'.png')) + + end %end for fd loop +end %end for raw data loop + +%NOW CALCULATE MONTHLY DATA. THIS IS SLIGHTLY EASIER AS IT IS ALREADY +%SORTED IN ORDER. + +if strcmpi(vtplotinputs{4,2}, 'Yes') + %Make an array of all the positions to calculate. Here need pairs of + %coordinates rather than single value as velocities have not been + %linearized. + all_positions = {}; + position_place = 1; + for position_loop = x_position - vtplotinputs{2,2} : x_position + vtplotinputs{2,2} + y_moved = abs(vtplotinputs{2,2}-(position_loop-x_position)); + for position_loop_2 = y_position-y_moved : y_position+y_moved + all_positions{position_place,1} = [position_loop_2, position_loop]; + position_place = position_place+1; + end + end + % Calculate mean of all of these positions, for each date. + final_velocity_array = []; + for date_loop = 1:size(monthly_averages,1) + inner_array = []; + for position_loop = 1:size(all_positions,1) + inner_array(position_loop,1) = monthly_averages{date_loop,3}(all_positions{position_loop,1}(1),all_positions{position_loop,1}(2)); + end + final_velocity_array(date_loop,2) = nanmean(inner_array,'all'); + end + x_axis_date = []; + for loop = 1:size(monthly_averages,1) + x_axis_date(loop) = monthly_averages{loop,1} + monthly_averages{loop,2}/12; + end + final_velocity_array(:,1) = x_axis_date(1,:)'; + + %Create a new, similar array to save with 4 columns for year, month, day + %and velocity + save_velocity_array = []; + for time_loop = 1:size(final_velocity_array,1) + save_velocity_array(time_loop,1) = monthly_averages{time_loop,1}; + save_velocity_array(time_loop,2) = monthly_averages{time_loop,2}; + save_velocity_array(time_loop,3) = final_velocity_array(time_loop,2); + end + % Now lets save a .csv file of results that can be opened in excel + if ~exist(strcat(my_path_velocitytimeplot,'/csv files of monthly timeseries')) + mkdir(strcat(my_path_velocitytimeplot,'/csv files of monthly timeseries')); + end + writematrix(save_velocity_array,strcat(my_path_velocitytimeplot,'/csv files of monthly timeseries/','Velocities_lat=',num2str(latpoint),'_long=',num2str(longpoint),'.csv')) + % Finally, let's save a png plot of the image + if ~exist(strcat(my_path_velocitytimeplot,'/png files of monthly timeseries')) + mkdir(strcat(my_path_velocitytimeplot,'/png files of monthly timeseries')); + end + %Saving hidden figure + h = figure;set(h, 'Visible', 'off'); + h = plot(final_velocity_array(:,1),final_velocity_array(:,2),'k-o'); + saveas(h,strcat(my_path_velocitytimeplot,'/png files of monthly timeseries/','Velocities_lat=',num2str(latpoint),'_long=',num2str(longpoint),'.png')); + if strcmpi(vtplotinputs{5,2}, 'Yes') + %Make an array of all the positions to calculate. Here need pairs of + %coordinates rather than single value as velocities have not been + %linearized. + all_positions = {}; + position_place = 1; + for position_loop = x_position - vtplotinputs{2,2} : x_position + vtplotinputs{2,2} + y_moved = abs(vtplotinputs{2,2}-(position_loop-x_position)); + for position_loop_2 = y_position-y_moved : y_position+y_moved + all_positions{position_place,1} = [position_loop_2, position_loop]; + position_place = position_place+1; + end + end + % Calculate mean of all of these positions, for each date. + final_fd_array = []; + for date_loop = 1:size(monthly_averages,1) + inner_array = []; + for position_loop = 1:size(all_positions,1) + inner_array(position_loop,1) = monthly_averages{date_loop,4}(all_positions{position_loop,1}(1),all_positions{position_loop,1}(2)); + end + final_fd_array(date_loop,2) = nanmean(inner_array,'all'); + end + for loop = 1:size(monthly_averages,1) + x_axis_date(loop) = monthly_averages{loop,1} + monthly_averages{loop,2}/12; + end + final_fd_array(:,1) = x_axis_date; + + %Create a new, similar array to save with 3 columns for year, month, day + %and fd + save_fd_array = []; + for time_loop = 1:size(final_fd_array,1) + save_fd_array(time_loop,1) = monthly_averages{time_loop,1}; + save_fd_array(time_loop,2) = monthly_averages{time_loop,2}; + save_fd_array(time_loop,3) = final_fd_array(time_loop,2); + end + + % Now lets save a .csv file of results that can be opened in excel + if ~exist(strcat(my_path_velocitytimeplot,'/csv files of monthly timeseries')) + mkdir(strcat(my_path_velocitytimeplot,'/csv files of monthly timeseries')); + end + writematrix(save_fd_array,strcat(my_path_velocitytimeplot,'/csv files of monthly timeseries/','FD_lat=',num2str(latpoint),'_long=',num2str(longpoint),'.csv')) + + % Finally, let's save a png plot of the image + if ~exist(strcat(my_path_velocitytimeplot,'/png files of monthly timeseries')) + mkdir(strcat(my_path_velocitytimeplot,'/png files of monthly timeseries')); + end + + %Saving hidden figure + h = figure;set(h, 'Visible', 'off'); + h = plot(final_fd_array(:,1),final_fd_array(:,2),'k-o'); + saveas(h,strcat(my_path_velocitytimeplot,'/png files of monthly timeseries/','FD_lat=',num2str(latpoint),'_long=',num2str(longpoint),'.png')); + end %end for monthly averages (flow direction if loop) + +end %end for monthly averages loop + + end %end for ~empty condition + +end %end for main loop + +logo = imread('GIV_LOGO_SMALL.png'); + +msgbox({'ALL TIMESERIES POINTS HAVE BEEN EXTRACTED AND SAVED TO THE RESULTS FOLDER. SEE USER MANUAL FOR MORE DETAILS.'},... + 'TIMESERIES EXTRACTION COMPLETE.','custom',logo); \ No newline at end of file diff --git a/functions/other/xytoV.m b/functions/other/xytoV.m new file mode 100644 index 0000000..4be64bf --- /dev/null +++ b/functions/other/xytoV.m @@ -0,0 +1,53 @@ +function [V,fd] = xytoV(du, dv, mean_resolution, dt) +%input two direction files (x component of velocity, y component of +%velocity), output a flow direction and a velocity magnitude + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% GLACIER IMAGE VELOCIMETRY (GIV) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Code written by Max Van Wyk de Vries @ University of Minnesota +%Credit to Ben Popken and Andrew Wickert for portions of the toolbox. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Portions of this toolbox are based on a number of codes written by +%previous authors, including matPIV, IMGRAFT, PIVLAB, M_Map and more. +%Credit and thanks are due to the authors of these toolboxes, and for +%sharing their codes online. See the user manual for a full list of third +%party codes used here. Accordingly, you are free to share, edit and +%add to this GIV code. Please give us credit if you do, and share your code +%with the same conditions as this. + +% Read the associated paper here: +% https://doi.org/10.5194/tc-2020-204 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Version 0.7, Autumn 2020% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %Feel free to contact me at vanwy048@umn.edu% + +%% Calculate velocity +V= abs((du-dv*1i)*mean_resolution/dt); %Using imaginary values to indicate direction (for convenience). + +%% Calculate flow direction +dir_du = du; +dir_dv = dv; +ws = NaN*ones(size(dir_du)); +fd = NaN*ones(size(dir_du)); +e = find(~isnan(dir_du) & ~isnan(dir_dv)); +ws(e) = sqrt(dir_du(e).*dir_du(e) + dir_dv(e).*dir_dv(e)); +fd(e) = (180/pi)*atan2(dir_dv(e),dir_du(e)); +temp1=fd; +temp1(fd>0) = 0; +temp1 = abs(temp1); +temp1(temp1==0)=-90; +temp1=temp1+90; +temp2 = fd; +temp2(fd<0) = 0; +temp2=360-temp2; +temp2(temp2==360)=0; +temp2=temp2+90; +temp2(temp2==90)=0; +temp3=temp2; +temp3(temp3<360)=0; +temp3=temp3-360; +temp3(temp3==-360)=0; +temp2(temp2>360)=0; +fd = temp1+temp2+temp3; \ No newline at end of file diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/._cbrewer.m b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/._cbrewer.m new file mode 100644 index 0000000..2ccad76 Binary files /dev/null and b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/._cbrewer.m differ diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/._interpolate_cbrewer.m b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/._interpolate_cbrewer.m new file mode 100644 index 0000000..2ccad76 Binary files /dev/null and b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/._interpolate_cbrewer.m differ diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/._plot_brewer_cmap.m b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/._plot_brewer_cmap.m new file mode 100644 index 0000000..2ccad76 Binary files /dev/null and b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/._plot_brewer_cmap.m differ diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/cbrewer.m b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/cbrewer.m new file mode 100644 index 0000000..219ee57 --- /dev/null +++ b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/cbrewer.m @@ -0,0 +1,128 @@ +function [colormap]=cbrewer(ctype, cname, ncol, interp_method) +% +% CBREWER - This function produces a colorbrewer table (rgb data) for a +% given type, name and number of colors of the colorbrewer tables. +% For more information on 'colorbrewer', please visit +% http://colorbrewer2.org/ +% +% The tables were generated from an MS-Excel file provided on the website +% http://www.personal.psu.edu/cab38/ColorBrewer/ColorBrewer_updates.html +% +% +% [colormap]=cbrewer(ctype, cname, ncol, interp_method) +% +% INPUT: +% - ctype: type of color table 'seq' (sequential), 'div' (diverging), 'qual' (qualitative) +% - cname: name of colortable. It changes depending on ctype. +% - ncol: number of color in the table. It changes according to ctype and +% cname +% - interp_method: interpolation method (see interp1.m). Default is "cubic" ) +% +% A note on the number of colors: Based on the original data, there is +% only a certain number of colors available for each type and name of +% colortable. When 'ncol' is larger then the maximum number of colors +% originally given, an interpolation routine is called (interp1) to produce +% the "extended" colormaps. +% +% Example: To produce a colortable CT of ncol X 3 entries (RGB) of +% sequential type and named 'Blues' with 8 colors: +% CT=cbrewer('seq', 'Blues', 8); +% To use this colortable as colormap, simply call: +% colormap(CT) +% +% To see the various colormaps available according to their types and +% names, simply call: cbrewer() +% +% This product includes color specifications and designs developed by +% Cynthia Brewer (http://colorbrewer.org/). +% +% Author: Charles Robert +% email: tannoudji@hotmail.com +% Date: 06.12.2011 +% ------------------------------ +% 18.09.2015 Minor fixes, fixed a bug where the 'spectral' color table did not appear in the preview + + +% load colorbrewer data +load('colorbrewer.mat') +% initialise the colormap is there are any problems +colormap=[]; +if (~exist('interp_method', 'var')) + interp_method='pchip'; +end + +% If no arguments +if (~exist('ctype', 'var') | ~exist('cname', 'var') | ~exist('ncol', 'var')) + disp(' ') + disp('[colormap] = cbrewer(ctype, cname, ncol [, interp_method])') + disp(' ') + disp('INPUT:') + disp(' - ctype: type of color table *seq* (sequential), *div* (divergent), *qual* (qualitative)') + disp(' - cname: name of colortable. It changes depending on ctype.') + disp(' - ncol: number of color in the table. It changes according to ctype and cname') + disp(' - interp_method: interpolation method (see interp1.m). Default is "cubic" )') + + disp(' ') + disp('Sequential tables:') + z={'Blues','BuGn','BuPu','GnBu','Greens','Greys','Oranges','OrRd','PuBu','PuBuGn','PuRd',... + 'Purples','RdPu', 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd', 'Spectral'}; + disp(z') + + disp('Divergent tables:') + z={'BrBG', 'PiYG', 'PRGn', 'PuOr', 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn'}; + disp(z') + + disp(' ') + disp('Qualitative tables:') + %getfield(colorbrewer, 'qual') + z={'Accent', 'Dark2', 'Paired', 'Pastel1', 'Pastel2', 'Set1', 'Set2', 'Set3'}; + disp(z') + + plot_brewer_cmap + return +end + +% Verify that the input is appropriate +ctype_names={'div', 'seq', 'qual'}; +if (~ismember(ctype,ctype_names)) + disp('ctype must be either: *div*, *seq* or *qual*') + colormap=[]; + return +end + +if (~isfield(colorbrewer.(ctype),cname)) + disp(['The name of the colortable of type *' ctype '* must be one of the following:']) + getfield(colorbrewer, ctype) + colormap=[]; + return +end + +if (ncol>length(colorbrewer.(ctype).(cname))) +% disp(' ') +% disp('----------------------------------------------------------------------') +% disp(['The maximum number of colors for table *' cname '* is ' num2str(length(colorbrewer.(ctype).(cname)))]) +% disp(['The new colormap will be extrapolated from these ' num2str(length(colorbrewer.(ctype).(cname))) ' values']) +% disp('----------------------------------------------------------------------') +% disp(' ') + cbrew_init=colorbrewer.(ctype).(cname){length(colorbrewer.(ctype).(cname))}; + colormap=interpolate_cbrewer(cbrew_init, interp_method, ncol); + colormap=colormap./255; + return +end + +if (isempty(colorbrewer.(ctype).(cname){ncol})) + + while(isempty(colorbrewer.(ctype).(cname){ncol})) + ncol=ncol+1; + end + disp(' ') + disp('----------------------------------------------------------------------') + disp(['The minimum number of colors for table *' cname '* is ' num2str(ncol)]) + disp('This minimum value shall be defined as ncol instead') + disp('----------------------------------------------------------------------') + disp(' ') +end + +colormap=(colorbrewer.(ctype).(cname){ncol})./255; + +end \ No newline at end of file diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/cbrewer_preview.jpg b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/cbrewer_preview.jpg new file mode 100644 index 0000000..bd2830a Binary files /dev/null and b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/cbrewer_preview.jpg differ diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/change_jet.m b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/change_jet.m new file mode 100644 index 0000000..b8d4ecb --- /dev/null +++ b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/change_jet.m @@ -0,0 +1,64 @@ +% This script help produce a new 'jet'-like colormap based on other RGB reference colors + +% ------- I WAS ASKED --------------- +% "is there a chance that you could add a diverging map going from blue to green to red as in jet, +% but using the red and blue from your RdBu map and the third darkest green from your RdYlGn map?"" +% +% ANSWER: +% You should construct the new colormap based on the existing RGB values of 'jet' +% but projecting these RGB values on your new RGB basis. +% ----------------------------------- + +% load colormaps +jet=colormap('jet'); +RdBu=cbrewer('div', 'RdBu', 11); +RdYlGn=cbrewer('div', 'RdYlGn', 11); + +% Define the new R, G, B references (p stands for prime) +Rp=RdBu(1,:); +Bp=RdBu(end, :); +Gp=RdYlGn(end-2, :); +RGBp=[Rp;Gp;Bp]; + +% construct the new colormap based on the existing RGB values of jet +% Project the RGB values on your new basis +newjet = jet*RGBp; + +% store data in a strcuture, easier to handle +cmap.jet=jet; +cmap.newjet=newjet; +cnames={'jet', 'newjet'}; + +% plot the RGB values +fh=figure(); +colors={'r', 'g', 'b'}; +for iname=1:length(cnames) + subplot(length(cnames),1,iname) + dat=cmap.(cnames{end-iname+1}); + for icol=1:size(dat,2) + plot(dat(:,icol), 'color', colors{icol}, 'linewidth', 2);hold on; + end % icol + title([' "' cnames{end-iname+1} '" in RGB plot']) +end + +% plot the colormaps +fh=figure(); +for iname=1:length(cnames) + F=cmap.(cnames{iname}); + ncol=length(F); + fg=1./ncol; % geometrical factor + X=fg.*[0 0 1 1]; + Y=0.1.*[1 0 0 1]+(2*iname-1)*0.1; + + for icol=1:ncol + X2=X+fg.*(icol-1); + fill(X2,Y,F(icol, :), 'linestyle', 'none') + hold all + end % icol + text(-0.1, mean(Y), cnames{iname}, 'HorizontalAlignment', 'right', 'FontWeight', 'bold', 'FontSize', 10, 'FontName' , 'AvantGarde') + xlim([-0.4, 1]) + axis off + set(gcf, 'color', [1 1 1]) + ylim([0.1 1.05.*max(Y)]); + end % iname + diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/colorbrewer.mat b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/colorbrewer.mat new file mode 100644 index 0000000..ec59ef4 Binary files /dev/null and b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/colorbrewer.mat differ diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/interpolate_cbrewer.m b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/interpolate_cbrewer.m new file mode 100644 index 0000000..e8b5e21 --- /dev/null +++ b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/interpolate_cbrewer.m @@ -0,0 +1,36 @@ +function [interp_cmap]=interpolate_cbrewer(cbrew_init, interp_method, ncolors) +% +% INTERPOLATE_CBREWER - interpolate a colorbrewer map to ncolors levels +% +% INPUT: +% - cbrew_init: the initial colormap with format N*3 +% - interp_method: interpolation method, which can be the following: +% 'nearest' - nearest neighbor interpolation +% 'linear' - bilinear interpolation +% 'spline' - spline interpolation +% 'cubic' - bicubic interpolation as long as the data is +% uniformly spaced, otherwise the same as 'spline' +% - ncolors=desired number of colors +% +% Author: Charles Robert +% email: tannoudji@hotmail.com +% Date: 14.10.2011 + + +% just to make sure, in case someone puts in a decimal +ncolors=round(ncolors); + +% How many data points of the colormap available +nmax=size(cbrew_init,1); + +% create the associated X axis (using round to get rid of decimals) +a=(ncolors-1)./(nmax-1); +X=round([0 a:a:(ncolors-1)]); +X2=0:ncolors-1; + +z=interp1(X,cbrew_init(:,1),X2,interp_method); +z2=interp1(X,cbrew_init(:,2),X2,interp_method); +z3=interp1(X,cbrew_init(:,3),X2, interp_method); +interp_cmap=round([z' z2' z3']); + +end \ No newline at end of file diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/plot_brewer_cmap.m b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/plot_brewer_cmap.m new file mode 100644 index 0000000..a5cab9e --- /dev/null +++ b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/cbrewer/plot_brewer_cmap.m @@ -0,0 +1,50 @@ +% Plots and identifies the various colorbrewer tables available. +% Is called by cbrewer.m when no arguments are given. +% +% Author: Charles Robert +% email: tannoudji@hotmail.com +% Date: 14.10.2011 + + + +load('colorbrewer.mat') + +ctypes={'div', 'seq', 'qual'}; +ctypes_title={'Diverging', 'Sequential', 'Qualitative'}; +cnames{1,:}={'BrBG', 'PiYG', 'PRGn', 'PuOr', 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn', 'Spectral'}; +cnames{2,:}={'Blues','BuGn','BuPu','GnBu','Greens','Greys','Oranges','OrRd','PuBu','PuBuGn','PuRd',... + 'Purples','RdPu', 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd'}; +cnames{3,:}={'Accent', 'Dark2', 'Paired', 'Pastel1', 'Pastel2', 'Set1', 'Set2', 'Set3'}; + +figure('position', [314 327 807 420]) +for itype=1:3 + + %fh(itype)=figure(); + subplot(1,3,itype) + + for iname=1:length(cnames{itype,:}) + + ncol=length(colorbrewer.(ctypes{itype}).(cnames{itype}{iname})); + fg=1./ncol; % geometrical factor + + X=fg.*[0 0 1 1]; + Y=0.1.*[1 0 0 1]+(2*iname-1)*0.1; + F=cbrewer(ctypes{itype}, cnames{itype}{iname}, ncol); + + for icol=1:ncol + X2=X+fg.*(icol-1); + fill(X2,Y,F(icol, :), 'linestyle', 'none') + text(-0.1, mean(Y), cnames{itype}{iname}, 'HorizontalAlignment', 'right', 'FontWeight', 'bold', 'FontSize', 10, 'FontName' , 'AvantGarde') + xlim([-0.4, 1]) + hold all + end % icol + %set(gca, 'box', 'off') + title(ctypes_title{itype}, 'FontWeight', 'bold', 'FontSize', 16, 'FontName' , 'AvantGarde') + axis off + set(gcf, 'color', [1 1 1]) + end % iname + ylim([0.1 1.05.*max(Y)]); +end %itype + +set(gcf, 'MenuBar', 'none') +set(gcf, 'Name', 'ColorBrewer Color maps') \ No newline at end of file diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/license.txt b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/license.txt new file mode 100644 index 0000000..ded8179 --- /dev/null +++ b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/cbrewer/license.txt @@ -0,0 +1,24 @@ +Copyright (c) 2011, Charles Robert +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. diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/license.txt b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/license.txt new file mode 100644 index 0000000..c74316e --- /dev/null +++ b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/license.txt @@ -0,0 +1,24 @@ +Copyright (c) 2015, Charles Robert +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. diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/addons_core.xml b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/addons_core.xml new file mode 100644 index 0000000..204bada --- /dev/null +++ b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/addons_core.xml @@ -0,0 +1,9 @@ + + + + 1.1.0.0 + zip + e583a467-4a80-11e4-9553-005056977bd0 + + resources/screenshot.png + diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/cbrewer.zip b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/cbrewer.zip new file mode 100644 index 0000000..8e79672 Binary files /dev/null and b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/cbrewer.zip differ diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/matlab_path_entries.xml b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/matlab_path_entries.xml new file mode 100644 index 0000000..891f9e3 --- /dev/null +++ b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/matlab_path_entries.xml @@ -0,0 +1,6 @@ + + + . + cbrewer + cbrewer\cbrewer + diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/metadata.xml b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/metadata.xml new file mode 100644 index 0000000..baf5c06 --- /dev/null +++ b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/metadata.xml @@ -0,0 +1,19 @@ + + + e583a467-4a80-11e4-9553-005056977bd0 + Collection + + Collection + コレクション + 컬렉션 + é›†åˆ + + cbrewer : colorbrewer schemes for Matlab + Charles + 1.1.0.0 + https://www.mathworks.com/matlabcentral/mlc-downloads/downloads/submissions/34087/versions/2/download/zip?src=addons_ml_desktop_install&profile_id=15130015&license=40747540&release_family=R2019b + https://addons.mathworks.com/registry/v1/e583a467-4a80-11e4-9553-005056977bd0/1.1.0.0/-/license + https://www.mathworks.com/responsive_image/160/120/0/0/0/cache/matlabcentral/mlc-downloads/downloads/submissions/34087/versions/2/screenshot.jpg + https://www.mathworks.com/add-ons/e583a467-4a80-11e4-9553-005056977bd0/55310874-0078-73a5-5eee-ca921a35ed6b/releaseNotes + Collections + diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/previewImage.png b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/previewImage.png new file mode 100644 index 0000000..8d950ff Binary files /dev/null and b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/previewImage.png differ diff --git a/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/screenshot.png b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/screenshot.png new file mode 100644 index 0000000..37f42b4 Binary files /dev/null and b/functions/plotting/cbrewer _ colorbrewer schemes for Matlab/resources/screenshot.png differ diff --git a/functions/plotting/m_colmap.m b/functions/plotting/m_colmap.m new file mode 100644 index 0000000..1c24876 --- /dev/null +++ b/functions/plotting/m_colmap.m @@ -0,0 +1,1607 @@ +function cols=m_colmap(nme,m,ncol) +% M_COLMAP Useful colormaps +% M_COLMAP(NAME) returns an M-by-3 matrix containing the NAME colormap +% where NAME is one of: +% 'jet' : a perceptually uniform variation of the JET colormap. It +% contains the multiple colours which make JET useful, while +% avoiding the weird highlighting especially around yellow and +% cyan. The colors begin with dark blue, range through shades +% of blue, green, orange and red, and ends with dark red. +% 'blue' : a perceptually useful blue shading (good for bathymetry) +% 'green' : a perceptually useful green shading +% 'diverging' : a blue/red diverging colormap +% 'odv' : an isoluminant map +% 'land' : a topographic height (green-brown-white) shading +% 'water' : blue shading for water (goes with 'land'). +% 'gland' : a topographic height shading with more green +% 'bland' : a topographic height shading with browns only. +% +% and M is the same length as the current figure's colormap. If no +% figure exists, the length of the default colormap is used. The +% length can be explicitly specified with M_COLMAP(NAME,M). +% +% M_COLMAP('demo') demonstrates the colormaps. +% +% M_COLMAP(NAME,'step') returns a 256-color map in which colours are +% perceptually bunched into 16 separate colours. This is useful +% if you want to see "edges" in what would be an otherwise +% smooth gradation (i.e. approaching the look of contouring). +% +% M_COLMAP(NAME,'demo') Gives a demo of this behavior +% +% M_COLMAP(NAME,'step',M) bunches into M colours. +% +% The jet and odv colourmaps were designed using the CET Perceptually +% Uniform Colour Maps toolbox at peterkovesi.com/projects/colourmaps/ +% +% The blue, green, and diverging colormaps are from CBREWER, a matlab +% implementation of colours described at http://colorbrewer2.org. +% +% The land and gland colormaps are derived from the ETOPO1 water/land +% colormap at http://soliton.vm.bytemark.co.uk/pub/cpt-city/ngdc/index.html +% +% See also PARULA, HSV, HOT, PINK, FLAG, COLORMAP, RGBPLOT. + +% R Pawlowicz Nov/2017 + +% names +if nargin==0 + m_colmap('get'); + return; +end + +switch lower(nme(1:3)) + case 'jet' + nme='jet'; + case 'blu' + nme='blue'; + case 'gre' + nme='green'; + case 'div' + nme='diverging'; + case 'odv' + nme='odv'; + case 'lan' + nme='land'; + case 'wat' + nme='water'; + case 'gla' + nme='gland'; + case 'bla' + nme='bland'; + case 'get' + fprintf('Colormaps include:\n'); + fprintf(' ''jet'' {,M|,''step''{,M}}\n'); + fprintf(' ''blue'' {,M|,''step''{,M}}\n'); + fprintf(' ''green'' {,M|,''step''{,M}}\n'); + fprintf(' ''diverging'' {,M|,''step''{,M}}\n'); + fprintf(' ''land'' {,M|,''step''{,M}}\n'); + fprintf(' ''gland'' {,M|,''step''{,M}}\n'); + fprintf(' ''bland'' {,M|,''step''{,M}}\n'); + fprintf(' ''water'' {,M|,''step''{,M}}\n'); + case 'dem' + colmap_demo; + return + otherwise + error(['map: ' mfilename ':invalidMapname'],... + ' First argument must be an valid colormap name '); +end + + +if nargin < 2 + f = gcf; + m = size(get(f,'Colormap'),1); + ncol=m; +else + if isnumeric(m) + ncol=m; + else + switch m(1:3) + case 'dem' % demo + clf; + subplot(2,1,1); + imagesc(peaks(10*10)); + title('Peaks function displayed with IMAGESC'); + subplot(2,1,2); + imagesc(1:256); + cols=m_colmap(nme,'step'); + colormap(cols); + title(['The colormap used above: m\_colmap(''' nme ''',256,16)']); + if nargout==0 + clear cols + end + return; + + case 'ste' % step + m=256; + if nargin<3 + ncol=16; + end + otherwise + error(['map: ' mfilename ':invalidOption'],... + ' Second argument must be an valid option'); + end + end +end + +% Whatever length colormap we have + +if ncol0 + [r,basecols]=mycols(nme); + cols=interp1(r,basecols,yy); +end + + + +end + + + +function [r,Data]=mycols(nme) +% +% Returns raw colourmap - 0<=r<=255 and +% [0 0 0]<=Data(row,:)<=[1 1 1] +% + +r=[0:255]; % Default for most of these. +switch nme + case 'jet' + Data=[... + 0.0000000000000000e+00 0.0000000000000000e+00 8.2097987032366326e-01 + 0.0000000000000000e+00 0.0000000000000000e+00 8.2810185708388151e-01 + 0.0000000000000000e+00 1.6244801768825715e-02 8.3523804428475601e-01 + 0.0000000000000000e+00 3.3036471648334995e-02 8.4238547984011569e-01 + 0.0000000000000000e+00 4.9815313296183217e-02 8.4954008831091266e-01 + 0.0000000000000000e+00 6.4029974334975218e-02 8.5670244416752706e-01 + 0.0000000000000000e+00 7.6535959975665882e-02 8.6388438002720569e-01 + 0.0000000000000000e+00 8.8013865699010582e-02 8.7105469052628581e-01 + 0.0000000000000000e+00 9.8600980176800038e-02 8.7821143148088110e-01 + 0.0000000000000000e+00 1.0855337679557225e-01 8.8532422388838095e-01 + 0.0000000000000000e+00 1.1812539206874099e-01 8.9236038456129052e-01 + 0.0000000000000000e+00 1.2726308783402634e-01 8.9926170553603024e-01 + 0.0000000000000000e+00 1.3619917896297423e-01 9.0595230153199524e-01 + 0.0000000000000000e+00 1.4506118969622983e-01 9.1232172813169876e-01 + 0.0000000000000000e+00 1.5377890552725290e-01 9.1823409334055117e-01 + 0.0000000000000000e+00 1.6261365170233669e-01 9.2351427566801991e-01 + 0.0000000000000000e+00 1.7154074948381501e-01 9.2794646225220667e-01 + 0.0000000000000000e+00 1.8070256379609848e-01 9.3131899478139557e-01 + 0.0000000000000000e+00 1.9017887289112076e-01 9.3338241072484596e-01 + 0.0000000000000000e+00 1.9997783192436316e-01 9.3392154621153756e-01 + 0.0000000000000000e+00 2.1019119971968461e-01 9.3274045531274641e-01 + 0.0000000000000000e+00 2.2078830806041727e-01 9.2970178242713375e-01 + 0.0000000000000000e+00 2.3170788397910427e-01 9.2472675872455312e-01 + 0.0000000000000000e+00 2.4291058720581157e-01 9.1783217933659011e-01 + 0.0000000000000000e+00 2.5439689340691901e-01 9.0907966847559551e-01 + 0.0000000000000000e+00 2.6601511242910086e-01 8.9863138701299472e-01 + 0.0000000000000000e+00 2.7770789341482360e-01 8.8668327712843464e-01 + 0.0000000000000000e+00 2.8940651531291417e-01 8.7345282146153225e-01 + 0.0000000000000000e+00 3.0102041216268027e-01 8.5918692717013723e-01 + 0.0000000000000000e+00 3.1252327536427388e-01 8.4411199405573478e-01 + 0.0000000000000000e+00 3.2386802405602533e-01 8.2843647500968565e-01 + 0.0000000000000000e+00 3.3502534309709658e-01 8.1233252376445897e-01 + 0.0000000000000000e+00 3.4591820537992940e-01 7.9594701247201749e-01 + 0.0000000000000000e+00 3.5661427072219648e-01 7.7939361987056155e-01 + 0.0000000000000000e+00 3.6703710422430275e-01 7.6275539017719729e-01 + 0.0000000000000000e+00 3.7721017332291257e-01 7.4610487594974018e-01 + 0.0000000000000000e+00 3.8709592071744631e-01 7.2949277318103267e-01 + 0.0000000000000000e+00 3.9670474982054660e-01 7.1295673554612449e-01 + 0.0000000000000000e+00 4.0602438327051393e-01 6.9655675508496329e-01 + 0.0000000000000000e+00 4.1500561550145126e-01 6.8030864681305458e-01 + 0.0000000000000000e+00 4.2366289307317656e-01 6.6426240828904592e-01 + 0.0000000000000000e+00 4.3200712706984007e-01 6.4842386975272537e-01 + 3.0566524560783279e-03 4.3999127354957085e-01 6.3282182663250508e-01 + 2.1259594640010666e-02 4.4764881469817519e-01 6.1745638962714788e-01 + 4.3803836689370011e-02 4.5501957945750093e-01 6.0233557663170700e-01 + 6.5847269982244869e-02 4.6208402302425822e-01 5.8744496819586389e-01 + 8.5714142185715644e-02 4.6890583204144093e-01 5.7277998204506675e-01 + 1.0409596887009070e-01 4.7550636110461003e-01 5.5828074688552098e-01 + 1.2102697913139572e-01 4.8192127879442975e-01 5.4395369747328215e-01 + 1.3667902142111943e-01 4.8820071402585424e-01 5.2974025041805628e-01 + 1.5103696859797716e-01 4.9437177951608591e-01 5.1559526287877988e-01 + 1.6416735480159775e-01 5.0046436145743556e-01 5.0151677895326252e-01 + 1.7599785165409093e-01 5.0651659371728996e-01 4.8743987594925903e-01 + 1.8673494649110914e-01 5.1254773876555138e-01 4.7333098265162471e-01 + 1.9635984308719795e-01 5.1857739467224218e-01 4.5920475411903505e-01 + 2.0490590950992249e-01 5.2459707667461242e-01 4.4499829451551892e-01 + 2.1249481521562941e-01 5.3063533990020706e-01 4.3070141183233479e-01 + 2.1917765060054359e-01 5.3669591908749759e-01 4.1629180215797296e-01 + 2.2499535088875952e-01 5.4276707337012853e-01 4.0174506555606909e-01 + 2.3004736186449742e-01 5.4886421494692972e-01 3.8704858786501528e-01 + 2.3439364402268012e-01 5.5497461212998789e-01 3.7217181537750266e-01 + 2.3802214916377087e-01 5.6111021864810351e-01 3.5711075761778077e-01 + 2.4102958080802567e-01 5.6727120617849991e-01 3.4180313298247084e-01 + 2.4347078965167188e-01 5.7343697984137976e-01 3.2624718187968538e-01 + 2.4541755424164602e-01 5.7961519583221810e-01 3.1046646770536129e-01 + 2.4695087697744367e-01 5.8578978746082422e-01 2.9436976897198003e-01 + 2.4816602364067705e-01 5.9195396468447525e-01 2.7803594615233906e-01 + 2.4914804420757949e-01 5.9808477862815501e-01 2.6142686912908059e-01 + 2.5009122010144075e-01 6.0419223727339377e-01 2.4457986428005363e-01 + 2.5125107794115892e-01 6.1022050248824800e-01 2.2760242777985751e-01 + 2.5277963649326868e-01 6.1617179084321716e-01 2.1050609513494345e-01 + 2.5499887511783337e-01 6.2200150973129531e-01 1.9345024424320145e-01 + 2.5811871983643009e-01 6.2770454035851242e-01 1.7653075332522819e-01 + 2.6246816164275255e-01 6.3323695072608899e-01 1.5996210212986198e-01 + 2.6818346039674890e-01 6.3858125645704489e-01 1.4398097898551054e-01 + 2.7543338752629509e-01 6.4372114150893245e-01 1.2870986574286711e-01 + 2.8418213538041015e-01 6.4865628006181242e-01 1.1444933871183166e-01 + 2.9441479687067434e-01 6.5336988668170226e-01 1.0152426951505689e-01 + 3.0599728766863188e-01 6.5788824014397052e-01 9.0139191413144706e-02 + 3.1866282501793303e-01 6.6220359310488208e-01 8.0483895706916511e-02 + 3.3224320620395048e-01 6.6633263204236381e-01 7.2801598535599379e-02 + 3.4646179112792114e-01 6.7032401486586635e-01 6.7067497770581408e-02 + 3.6113631412522007e-01 6.7416768477092770e-01 6.3249077315340047e-02 + 3.7608731018537811e-01 6.7791233106441862e-01 6.0980464884529913e-02 + 3.9114649219215752e-01 6.8155555404442747e-01 6.0237646826049381e-02 + 4.0620969841971383e-01 6.8514312914868336e-01 6.0434850173806676e-02 + 4.2119208206707631e-01 6.8867051135431134e-01 6.1317869943769421e-02 + 4.3607730241284837e-01 6.9215167952165702e-01 6.2899876768280863e-02 + 4.5080272445331049e-01 6.9559278562020677e-01 6.4630034822273294e-02 + 4.6536143503241884e-01 6.9900108657586113e-01 6.6611409445883923e-02 + 4.7977927019121297e-01 7.0239032638575571e-01 6.8765586458024650e-02 + 4.9402278124389287e-01 7.0575587274235263e-01 7.0874113597661562e-02 + 5.0812209701947120e-01 7.0910213329145999e-01 7.3065156643943877e-02 + 5.2205818272473403e-01 7.1241552273829678e-01 7.5181298203090122e-02 + 5.3588169773612182e-01 7.1572588892233568e-01 7.7316510344089567e-02 + 5.4958796386661235e-01 7.1900198771359247e-01 7.9498911575721087e-02 + 5.6318325188735974e-01 7.2225882977126032e-01 8.1739922275486848e-02 + 5.7667734958705708e-01 7.2550816943346963e-01 8.3886170589407089e-02 + 5.9006715802606269e-01 7.2872236431771908e-01 8.5969093205613856e-02 + 6.0339198534874716e-01 7.3192594564488933e-01 8.8191004728472841e-02 + 6.1663360653820753e-01 7.3510592591557200e-01 9.0348464852867502e-02 + 6.2979877564545061e-01 7.3826041744638315e-01 9.2484236233912193e-02 + 6.4290502541913341e-01 7.4139762708091694e-01 9.4695676765631190e-02 + 6.5595456455707568e-01 7.4451903129559338e-01 9.6766064389575565e-02 + 6.6894100563615921e-01 7.4762140253119092e-01 9.8966110102230720e-02 + 6.8187256965709520e-01 7.5069894456381092e-01 1.0111568171360964e-01 + 6.9476451769134873e-01 7.5375241811299143e-01 1.0331287444459691e-01 + 7.0761384378249492e-01 7.5678894789262396e-01 1.0543392059916874e-01 + 7.2042165068418740e-01 7.5980213993578027e-01 1.0760350744563843e-01 + 7.3319470176764145e-01 7.6279840902831653e-01 1.0981215158679503e-01 + 7.4592828571528091e-01 7.6577879845079466e-01 1.1194689692155048e-01 + 7.5863468570665482e-01 7.6872670099528584e-01 1.1407090775631480e-01 + 7.7131848568430994e-01 7.7166810405759800e-01 1.1627716014608953e-01 + 7.8398678935532840e-01 7.7456683356005351e-01 1.1844264905380968e-01 + 7.9662697582417896e-01 7.7744081794020037e-01 1.2054078396447886e-01 + 8.0926185607475876e-01 7.8025300319044533e-01 1.2266783407386730e-01 + 8.2187414124312763e-01 7.8300130137588675e-01 1.2480676238195154e-01 + 8.3446602223939059e-01 7.8565722796567439e-01 1.2687749576058471e-01 + 8.4702437066066527e-01 7.8816898161099214e-01 1.2890567635476541e-01 + 8.5954289047780741e-01 7.9049204962457431e-01 1.3088474793982860e-01 + 8.7197831670600356e-01 7.9255502154840052e-01 1.3269172868341109e-01 + 8.8427738654617694e-01 7.9427245270485536e-01 1.3436638425443168e-01 + 8.9637053729861804e-01 7.9553909023023628e-01 1.3576481705392310e-01 + 9.0816444779814065e-01 7.9626169503294353e-01 1.3697659943588600e-01 + 9.1953673575996886e-01 7.9633432352513089e-01 1.3786713706219822e-01 + 9.3037259899096236e-01 7.9566413293269556e-01 1.3835047336237846e-01 + 9.4053209111364600e-01 7.9418180027718388e-01 1.3842916138252423e-01 + 9.4989207994255664e-01 7.9182887326844242e-01 1.3808153617074001e-01 + 9.5836294828986246e-01 7.8861031080564803e-01 1.3725685332614224e-01 + 9.6586462349906821e-01 7.8454305319884909e-01 1.3594823160952096e-01 + 9.7239039139483674e-01 7.7967621023720923e-01 1.3431101877433596e-01 + 9.7794177385612990e-01 7.7410205347271077e-01 1.3221480879967804e-01 + 9.8259333615419153e-01 7.6791778909022512e-01 1.2980073335970169e-01 + 9.8642494090379840e-01 7.6122992421425550e-01 1.2702534915073754e-01 + 9.8955166954763185e-01 7.5413730388263700e-01 1.2406071795849168e-01 + 9.9208992758455905e-01 7.4672824419867512e-01 1.2089567778081263e-01 + 9.9415891855407701e-01 7.3909488972694637e-01 1.1760517777184400e-01 + 9.9586234078238622e-01 7.3127941939636465e-01 1.1416775566548833e-01 + 9.9729483003018982e-01 7.2335091637232807e-01 1.1070869560896780e-01 + 9.9852727658269325e-01 7.1534184353124297e-01 1.0714334894572426e-01 + 9.9960957379964188e-01 7.0726043228880653e-01 1.0352445558761095e-01 + 1.0000000000000000e+00 6.9912890339600753e-01 9.9829372782125531e-02 + 1.0000000000000000e+00 6.9095883736804042e-01 9.6116559516242178e-02 + 1.0000000000000000e+00 6.8275705650119767e-01 9.2417489373060394e-02 + 1.0000000000000000e+00 6.7452426257956222e-01 8.8677593797862289e-02 + 1.0000000000000000e+00 6.6625666540404749e-01 8.4887313721726754e-02 + 1.0000000000000000e+00 6.5796365276303015e-01 8.1068177807262484e-02 + 1.0000000000000000e+00 6.4962701740088724e-01 7.7151213817244532e-02 + 1.0000000000000000e+00 6.4124528876170073e-01 7.3351998210193614e-02 + 1.0000000000000000e+00 6.3283767086881249e-01 6.9416379806024719e-02 + 1.0000000000000000e+00 6.2438475544545868e-01 6.5331601005328144e-02 + 1.0000000000000000e+00 6.1588280808086227e-01 6.1211652569017221e-02 + 1.0000000000000000e+00 6.0734668246046875e-01 5.7123569446539284e-02 + 1.0000000000000000e+00 5.9874800807184747e-01 5.2865554268786509e-02 + 1.0000000000000000e+00 5.9010246493802909e-01 4.8647547440398876e-02 + 1.0000000000000000e+00 5.8140951034192445e-01 4.4198570670319334e-02 + 1.0000000000000000e+00 5.7266585316082430e-01 3.9705280914958743e-02 + 1.0000000000000000e+00 5.6385731706157016e-01 3.5191257367171103e-02 + 1.0000000000000000e+00 5.5497816055012050e-01 3.0647747322206934e-02 + 1.0000000000000000e+00 5.4604761486237297e-01 2.6461611736228074e-02 + 1.0000000000000000e+00 5.3704122502628560e-01 2.2436402898803214e-02 + 1.0000000000000000e+00 5.2795094033373646e-01 1.8569728931739027e-02 + 1.0000000000000000e+00 5.1880030560715795e-01 1.4859141284721791e-02 + 1.0000000000000000e+00 5.0955197815230335e-01 1.1196012834395055e-02 + 1.0000000000000000e+00 5.0021693769032671e-01 7.7056436600708390e-03 + 1.0000000000000000e+00 4.9080757314831269e-01 4.4527213011970471e-03 + 1.0000000000000000e+00 4.8127050430505153e-01 1.3486232596699801e-03 + 1.0000000000000000e+00 4.7165053711191246e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 4.6190083189547609e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 4.5204021136716938e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 4.4204343506591337e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 4.3190627002582327e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 4.2159591143411812e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 4.1114619470166724e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 4.0051916733978549e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 3.8967477462351169e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 3.7863908422433407e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 3.6737229102939645e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 3.5588805687874975e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 3.4412420334830296e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 3.3213896185541525e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 3.1988349723243259e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 3.0737131121967348e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 2.9466234283445780e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 2.8180431610272688e-01 0.0000000000000000e+00 + 1.0000000000000000e+00 2.6885346259089427e-01 0.0000000000000000e+00 + 9.9971380921896635e-01 2.5588279168968908e-01 0.0000000000000000e+00 + 9.9745107484299911e-01 2.4306303891550010e-01 0.0000000000000000e+00 + 9.9471175718486304e-01 2.3053240966922203e-01 0.0000000000000000e+00 + 9.9144050807482531e-01 2.1845350104652131e-01 0.0000000000000000e+00 + 9.8759742405304762e-01 2.0697738741569063e-01 0.0000000000000000e+00 + 9.8316166027396978e-01 1.9624582890323888e-01 0.0000000000000000e+00 + 9.7814117536301937e-01 1.8638373147524231e-01 0.0000000000000000e+00 + 9.7256691186559741e-01 1.7750982585337141e-01 0.0000000000000000e+00 + 9.6646763333593055e-01 1.6960615229744733e-01 0.0000000000000000e+00 + 9.5991667718773344e-01 1.6265283853733181e-01 0.0000000000000000e+00 + 9.5297568794473220e-01 1.5659747318781603e-01 0.0000000000000000e+00 + 9.4571233760129314e-01 1.5128687901353635e-01 0.0000000000000000e+00 + 9.3820118122169338e-01 1.4664168011978534e-01 0.0000000000000000e+00 + 9.3050268815754777e-01 1.4253427062145158e-01 0.0000000000000000e+00 + 9.2266803031005806e-01 1.3878427919273950e-01 0.0000000000000000e+00 + 9.1474108307638347e-01 1.3532555938839283e-01 0.0000000000000000e+00 + 9.0675852417667746e-01 1.3206323417870042e-01 0.0000000000000000e+00 + 8.9873962287707232e-01 1.2889180676634279e-01 0.0000000000000000e+00 + 8.9070644004606214e-01 1.2586340008396713e-01 0.0000000000000000e+00 + 8.8266708081748724e-01 1.2278481340036466e-01 0.0000000000000000e+00 + 8.7463547859087032e-01 1.1980508899179866e-01 0.0000000000000000e+00 + 8.6661131238848954e-01 1.1682153274204797e-01 0.0000000000000000e+00 + 8.5859901159723606e-01 1.1382680416595528e-01 0.0000000000000000e+00 + 8.5060093722026298e-01 1.1083435058870025e-01 0.0000000000000000e+00 + 8.4262210493452183e-01 1.0777800601488426e-01 0.0000000000000000e+00 + 8.3465143106553319e-01 1.0471633325123153e-01 0.0000000000000000e+00 + 8.2669639277606366e-01 1.0170369534475480e-01 0.0000000000000000e+00 + 8.1874989394241815e-01 9.8659152046269100e-02 0.0000000000000000e+00 + 8.1082521361314908e-01 9.5589480024985407e-02 0.0000000000000000e+00 + 8.0291243524621259e-01 9.2477562506154257e-02 0.0000000000000000e+00 + 7.9501601582959724e-01 8.9390544379782902e-02 0.0000000000000000e+00 + 7.8713591423470530e-01 8.6218414092508924e-02 0.0000000000000000e+00 + 7.7926327536719753e-01 8.3082652674223073e-02 0.0000000000000000e+00 + 7.7141345413247508e-01 7.9904163323746544e-02 0.0000000000000000e+00 + 7.6356901068481819e-01 7.6683348793519776e-02 0.0000000000000000e+00 + 7.5574754344824191e-01 7.3559378952035598e-02 0.0000000000000000e+00 + 7.4794071009249607e-01 7.0232910613491642e-02 0.0000000000000000e+00 + 7.4014602737794621e-01 6.6954364586541498e-02 0.0000000000000000e+00 + 7.3236760838059556e-01 6.3633307967642341e-02 0.0000000000000000e+00 + 7.2460119293990866e-01 6.0280688573269070e-02 0.0000000000000000e+00 + 7.1685625358364513e-01 5.6849608855938531e-02 0.0000000000000000e+00 + 7.0912481497916180e-01 5.3299226112309528e-02 0.0000000000000000e+00 + 7.0140312192465981e-01 4.9829293199622995e-02 0.0000000000000000e+00 + 6.9370510178801092e-01 4.6158764888123434e-02 0.0000000000000000e+00 + 6.8602792806999691e-01 4.2524088717921474e-02 0.0000000000000000e+00 + 6.7836388922453772e-01 3.8797586133169637e-02 0.0000000000000000e+00 + 6.7072178335076416e-01 3.5066982469895418e-02 0.0000000000000000e+00 + 6.6309318632075742e-01 3.1291508120498114e-02 0.0000000000000000e+00 + 6.5547739533880844e-01 2.7799830769093408e-02 0.0000000000000000e+00 + 6.4788052533085139e-01 2.4415535891618653e-02 0.0000000000000000e+00 + 6.4031120522707030e-01 2.1137242643728692e-02 0.0000000000000000e+00 + 6.3275181226008126e-01 1.7963580322279168e-02 0.0000000000000000e+00 + 6.2521102502886350e-01 1.4892646934414970e-02 0.0000000000000000e+00 + 6.1768851440583761e-01 1.1947271916774600e-02 0.0000000000000000e+00 + 6.1018680816921134e-01 8.8617158086171516e-03 0.0000000000000000e+00 + 6.0270479360661422e-01 6.0916955702822869e-03 0.0000000000000000e+00 + 5.9523986538913543e-01 3.4203333573827339e-03 0.0000000000000000e+00 + 5.8779123408662970e-01 8.4517490685311037e-04 0.0000000000000000e+00 + 5.8037263574738407e-01 0.0000000000000000e+00 0.0000000000000000e+00 + 5.7296951136703345e-01 0.0000000000000000e+00 0.0000000000000000e+00 + 5.6557284013198694e-01 0.0000000000000000e+00 0.0000000000000000e+00 + 5.5820630194758614e-01 0.0000000000000000e+00 0.0000000000000000e+00 + 5.5086745375910373e-01 0.0000000000000000e+00 0.0000000000000000e+00 + 5.4354221465215014e-01 0.0000000000000000e+00 0.0000000000000000e+00 + 5.3623817219036729e-01 0.0000000000000000e+00 0.0000000000000000e+00 + 5.2896046694295906e-01 0.0000000000000000e+00 0.0000000000000000e+00 + 5.2168511872923218e-01 0.0000000000000000e+00 0.0000000000000000e+00 + 5.1445545856746699e-01 0.0000000000000000e+00 0.0000000000000000e+00 + 5.0723090697621742e-01 0.0000000000000000e+00 0.0000000000000000e+00 + 5.0002769723112239e-01 0.0000000000000000e+00 0.0000000000000000e+00]; + case 'blue' + Data=[... + 3.1372549019607843e-02 1.8823529411764706e-01 4.1960784313725491e-01 + 3.1372549019607843e-02 1.9215686274509805e-01 4.2745098039215684e-01 + 3.1372549019607843e-02 1.9607843137254902e-01 4.3529411764705883e-01 + 3.1372549019607843e-02 2.0000000000000001e-01 4.4313725490196076e-01 + 3.1372549019607843e-02 2.0392156862745098e-01 4.4705882352941179e-01 + 3.1372549019607843e-02 2.0784313725490197e-01 4.5490196078431372e-01 + 3.1372549019607843e-02 2.1176470588235294e-01 4.6274509803921571e-01 + 3.1372549019607843e-02 2.1568627450980393e-01 4.7058823529411764e-01 + 3.1372549019607843e-02 2.1960784313725490e-01 4.7843137254901963e-01 + 3.1372549019607843e-02 2.2352941176470589e-01 4.8235294117647060e-01 + 3.1372549019607843e-02 2.2745098039215686e-01 4.9019607843137253e-01 + 3.1372549019607843e-02 2.3137254901960785e-01 4.9803921568627452e-01 + 3.1372549019607843e-02 2.3529411764705882e-01 5.0588235294117645e-01 + 3.1372549019607843e-02 2.4313725490196078e-01 5.0980392156862742e-01 + 3.1372549019607843e-02 2.4705882352941178e-01 5.1764705882352946e-01 + 3.1372549019607843e-02 2.5098039215686274e-01 5.2156862745098043e-01 + 3.1372549019607843e-02 2.5490196078431371e-01 5.2941176470588236e-01 + 3.1372549019607843e-02 2.5882352941176473e-01 5.3725490196078429e-01 + 3.1372549019607843e-02 2.6274509803921570e-01 5.4117647058823526e-01 + 3.1372549019607843e-02 2.6666666666666666e-01 5.4901960784313730e-01 + 3.1372549019607843e-02 2.7058823529411763e-01 5.5294117647058827e-01 + 3.1372549019607843e-02 2.7450980392156865e-01 5.5686274509803924e-01 + 3.1372549019607843e-02 2.7843137254901962e-01 5.6470588235294117e-01 + 3.1372549019607843e-02 2.8235294117647058e-01 5.6862745098039214e-01 + 3.1372549019607843e-02 2.8627450980392155e-01 5.7647058823529407e-01 + 3.1372549019607843e-02 2.9019607843137257e-01 5.8039215686274515e-01 + 3.1372549019607843e-02 2.9411764705882354e-01 5.8431372549019611e-01 + 3.1372549019607843e-02 2.9803921568627451e-01 5.8823529411764708e-01 + 3.1372549019607843e-02 3.0196078431372547e-01 5.9607843137254901e-01 + 3.1372549019607843e-02 3.0588235294117649e-01 5.9999999999999998e-01 + 3.1372549019607843e-02 3.0980392156862746e-01 6.0392156862745094e-01 + 3.1372549019607843e-02 3.1372549019607843e-01 6.0784313725490191e-01 + 3.1372549019607843e-02 3.1764705882352939e-01 6.1176470588235299e-01 + 3.1372549019607843e-02 3.2156862745098042e-01 6.1568627450980395e-01 + 3.1372549019607843e-02 3.2549019607843138e-01 6.1960784313725492e-01 + 3.1372549019607843e-02 3.2941176470588235e-01 6.2352941176470589e-01 + 3.5294117647058823e-02 3.3333333333333331e-01 6.2745098039215685e-01 + 3.5294117647058823e-02 3.3725490196078434e-01 6.3137254901960782e-01 + 3.5294117647058823e-02 3.4117647058823530e-01 6.3529411764705879e-01 + 3.9215686274509803e-02 3.4509803921568627e-01 6.3921568627450975e-01 + 4.3137254901960784e-02 3.4901960784313724e-01 6.4313725490196083e-01 + 4.3137254901960784e-02 3.5294117647058826e-01 6.4313725490196083e-01 + 4.7058823529411764e-02 3.5686274509803922e-01 6.4705882352941180e-01 + 5.0980392156862744e-02 3.6078431372549019e-01 6.5098039215686276e-01 + 5.0980392156862744e-02 3.6470588235294116e-01 6.5490196078431373e-01 + 5.4901960784313725e-02 3.6862745098039218e-01 6.5882352941176470e-01 + 5.8823529411764705e-02 3.7254901960784315e-01 6.6274509803921566e-01 + 6.2745098039215685e-02 3.7647058823529411e-01 6.6274509803921566e-01 + 6.6666666666666666e-02 3.8039215686274508e-01 6.6666666666666663e-01 + 7.0588235294117646e-02 3.8431372549019610e-01 6.7058823529411760e-01 + 7.4509803921568626e-02 3.8823529411764707e-01 6.7450980392156867e-01 + 7.8431372549019607e-02 3.9215686274509803e-01 6.7450980392156867e-01 + 8.2352941176470587e-02 3.9607843137254900e-01 6.7843137254901964e-01 + 8.6274509803921567e-02 4.0000000000000002e-01 6.8235294117647061e-01 + 9.0196078431372548e-02 4.0392156862745099e-01 6.8235294117647061e-01 + 9.4117647058823528e-02 4.0784313725490196e-01 6.8627450980392157e-01 + 9.8039215686274508e-02 4.1176470588235292e-01 6.9019607843137254e-01 + 1.0196078431372549e-01 4.1568627450980394e-01 6.9019607843137254e-01 + 1.0588235294117647e-01 4.1960784313725491e-01 6.9411764705882351e-01 + 1.0980392156862745e-01 4.2352941176470588e-01 6.9803921568627447e-01 + 1.1372549019607843e-01 4.2745098039215684e-01 6.9803921568627447e-01 + 1.1764705882352941e-01 4.3137254901960786e-01 7.0196078431372544e-01 + 1.2156862745098039e-01 4.3529411764705883e-01 7.0588235294117652e-01 + 1.2549019607843137e-01 4.3921568627450980e-01 7.0588235294117652e-01 + 1.2941176470588237e-01 4.4313725490196076e-01 7.0980392156862748e-01 + 1.3333333333333333e-01 4.4705882352941179e-01 7.1372549019607845e-01 + 1.3725490196078433e-01 4.5098039215686275e-01 7.1372549019607845e-01 + 1.4117647058823529e-01 4.5490196078431372e-01 7.1764705882352942e-01 + 1.4509803921568629e-01 4.5882352941176469e-01 7.1764705882352942e-01 + 1.4901960784313725e-01 4.6274509803921571e-01 7.2156862745098038e-01 + 1.5294117647058825e-01 4.6666666666666667e-01 7.2549019607843135e-01 + 1.5294117647058825e-01 4.7058823529411764e-01 7.2549019607843135e-01 + 1.5686274509803921e-01 4.7450980392156861e-01 7.2941176470588232e-01 + 1.6078431372549021e-01 4.7843137254901963e-01 7.2941176470588232e-01 + 1.6470588235294117e-01 4.8235294117647060e-01 7.3333333333333328e-01 + 1.6862745098039217e-01 4.8627450980392156e-01 7.3333333333333328e-01 + 1.7254901960784313e-01 4.9019607843137253e-01 7.3725490196078436e-01 + 1.7647058823529413e-01 4.9803921568627452e-01 7.3725490196078436e-01 + 1.8039215686274510e-01 5.0196078431372548e-01 7.4117647058823533e-01 + 1.8431372549019609e-01 5.0588235294117645e-01 7.4117647058823533e-01 + 1.8823529411764706e-01 5.0980392156862742e-01 7.4509803921568629e-01 + 1.9215686274509805e-01 5.1372549019607838e-01 7.4509803921568629e-01 + 2.0000000000000001e-01 5.1764705882352946e-01 7.4901960784313726e-01 + 2.0392156862745098e-01 5.2156862745098043e-01 7.4901960784313726e-01 + 2.0784313725490197e-01 5.2549019607843139e-01 7.5294117647058822e-01 + 2.1176470588235294e-01 5.2941176470588236e-01 7.5294117647058822e-01 + 2.1568627450980393e-01 5.3333333333333333e-01 7.5686274509803919e-01 + 2.1960784313725490e-01 5.3725490196078429e-01 7.5686274509803919e-01 + 2.2352941176470589e-01 5.4117647058823526e-01 7.6078431372549016e-01 + 2.2745098039215686e-01 5.4509803921568623e-01 7.6078431372549016e-01 + 2.3137254901960785e-01 5.4901960784313730e-01 7.6470588235294112e-01 + 2.3529411764705882e-01 5.5294117647058827e-01 7.6470588235294112e-01 + 2.3921568627450981e-01 5.5686274509803924e-01 7.6862745098039220e-01 + 2.4705882352941178e-01 5.6078431372549020e-01 7.6862745098039220e-01 + 2.5098039215686274e-01 5.6470588235294117e-01 7.7254901960784317e-01 + 2.5490196078431371e-01 5.6862745098039214e-01 7.7254901960784317e-01 + 2.5882352941176473e-01 5.7254901960784310e-01 7.7647058823529413e-01 + 2.6274509803921570e-01 5.7647058823529407e-01 7.8039215686274510e-01 + 2.6666666666666666e-01 5.8039215686274515e-01 7.8039215686274510e-01 + 2.7450980392156865e-01 5.8431372549019611e-01 7.8431372549019607e-01 + 2.7843137254901962e-01 5.8823529411764708e-01 7.8431372549019607e-01 + 2.8235294117647058e-01 5.9215686274509804e-01 7.8823529411764703e-01 + 2.8627450980392155e-01 5.9607843137254901e-01 7.8823529411764703e-01 + 2.9019607843137257e-01 5.9999999999999998e-01 7.9215686274509800e-01 + 2.9803921568627451e-01 6.0392156862745094e-01 7.9215686274509800e-01 + 3.0196078431372547e-01 6.0392156862745094e-01 7.9607843137254897e-01 + 3.0588235294117649e-01 6.0784313725490191e-01 7.9607843137254897e-01 + 3.0980392156862746e-01 6.1176470588235299e-01 8.0000000000000004e-01 + 3.1764705882352939e-01 6.1568627450980395e-01 8.0392156862745101e-01 + 3.2156862745098042e-01 6.1960784313725492e-01 8.0392156862745101e-01 + 3.2549019607843138e-01 6.2352941176470589e-01 8.0784313725490198e-01 + 3.3333333333333331e-01 6.2745098039215685e-01 8.0784313725490198e-01 + 3.3725490196078434e-01 6.3137254901960782e-01 8.1176470588235294e-01 + 3.4117647058823530e-01 6.3529411764705879e-01 8.1176470588235294e-01 + 3.4901960784313724e-01 6.3921568627450975e-01 8.1568627450980391e-01 + 3.5294117647058826e-01 6.3921568627450975e-01 8.1568627450980391e-01 + 3.5686274509803922e-01 6.4313725490196083e-01 8.1960784313725488e-01 + 3.6470588235294116e-01 6.4705882352941180e-01 8.1960784313725488e-01 + 3.6862745098039218e-01 6.5098039215686276e-01 8.2352941176470584e-01 + 3.7647058823529411e-01 6.5490196078431373e-01 8.2352941176470584e-01 + 3.8039215686274508e-01 6.5882352941176470e-01 8.2745098039215681e-01 + 3.8431372549019610e-01 6.6274509803921566e-01 8.2745098039215681e-01 + 3.9215686274509803e-01 6.6666666666666663e-01 8.3137254901960789e-01 + 3.9607843137254900e-01 6.6666666666666663e-01 8.3137254901960789e-01 + 4.0392156862745099e-01 6.7058823529411760e-01 8.3529411764705885e-01 + 4.0784313725490196e-01 6.7450980392156867e-01 8.3529411764705885e-01 + 4.1568627450980394e-01 6.7843137254901964e-01 8.3921568627450982e-01 + 4.1960784313725491e-01 6.8235294117647061e-01 8.3921568627450982e-01 + 4.2352941176470588e-01 6.8627450980392157e-01 8.3921568627450982e-01 + 4.3137254901960786e-01 6.9019607843137254e-01 8.4313725490196079e-01 + 4.3529411764705883e-01 6.9411764705882351e-01 8.4313725490196079e-01 + 4.4313725490196076e-01 6.9803921568627447e-01 8.4705882352941175e-01 + 4.5098039215686275e-01 7.0196078431372544e-01 8.4705882352941175e-01 + 4.5490196078431372e-01 7.0588235294117652e-01 8.4705882352941175e-01 + 4.6274509803921571e-01 7.0588235294117652e-01 8.5098039215686272e-01 + 4.6666666666666667e-01 7.0980392156862748e-01 8.5098039215686272e-01 + 4.7450980392156861e-01 7.1372549019607845e-01 8.5098039215686272e-01 + 4.8235294117647060e-01 7.1764705882352942e-01 8.5490196078431369e-01 + 4.8627450980392156e-01 7.2156862745098038e-01 8.5490196078431369e-01 + 4.9411764705882355e-01 7.2549019607843135e-01 8.5490196078431369e-01 + 5.0196078431372548e-01 7.2941176470588232e-01 8.5882352941176465e-01 + 5.0588235294117645e-01 7.3333333333333328e-01 8.5882352941176465e-01 + 5.1372549019607838e-01 7.3725490196078436e-01 8.5882352941176465e-01 + 5.2156862745098043e-01 7.4117647058823533e-01 8.6274509803921573e-01 + 5.2549019607843139e-01 7.4509803921568629e-01 8.6274509803921573e-01 + 5.3333333333333333e-01 7.4901960784313726e-01 8.6274509803921573e-01 + 5.4117647058823526e-01 7.5294117647058822e-01 8.6666666666666670e-01 + 5.4509803921568623e-01 7.5686274509803919e-01 8.6666666666666670e-01 + 5.5294117647058827e-01 7.5686274509803919e-01 8.6666666666666670e-01 + 5.6078431372549020e-01 7.6078431372549016e-01 8.7058823529411766e-01 + 5.6470588235294117e-01 7.6470588235294112e-01 8.7058823529411766e-01 + 5.7254901960784310e-01 7.6862745098039220e-01 8.7058823529411766e-01 + 5.7647058823529407e-01 7.7254901960784317e-01 8.7450980392156863e-01 + 5.8431372549019611e-01 7.7647058823529413e-01 8.7450980392156863e-01 + 5.9215686274509804e-01 7.7647058823529413e-01 8.7450980392156863e-01 + 5.9607843137254901e-01 7.8039215686274510e-01 8.7843137254901960e-01 + 6.0392156862745094e-01 7.8431372549019607e-01 8.7843137254901960e-01 + 6.0784313725490191e-01 7.8823529411764703e-01 8.7843137254901960e-01 + 6.1568627450980395e-01 7.8823529411764703e-01 8.8235294117647056e-01 + 6.1960784313725492e-01 7.9215686274509800e-01 8.8235294117647056e-01 + 6.2352941176470589e-01 7.9607843137254897e-01 8.8235294117647056e-01 + 6.3137254901960782e-01 7.9607843137254897e-01 8.8627450980392153e-01 + 6.3529411764705879e-01 8.0000000000000004e-01 8.8627450980392153e-01 + 6.4313725490196083e-01 8.0392156862745101e-01 8.9019607843137250e-01 + 6.4705882352941180e-01 8.0392156862745101e-01 8.9019607843137250e-01 + 6.5098039215686276e-01 8.0784313725490198e-01 8.9411764705882357e-01 + 6.5882352941176470e-01 8.0784313725490198e-01 8.9411764705882357e-01 + 6.6274509803921566e-01 8.1176470588235294e-01 8.9411764705882357e-01 + 6.7058823529411760e-01 8.1176470588235294e-01 8.9803921568627454e-01 + 6.7450980392156867e-01 8.1568627450980391e-01 8.9803921568627454e-01 + 6.7843137254901964e-01 8.1568627450980391e-01 9.0196078431372551e-01 + 6.8627450980392157e-01 8.1960784313725488e-01 9.0196078431372551e-01 + 6.9019607843137254e-01 8.2352941176470584e-01 9.0588235294117647e-01 + 6.9411764705882351e-01 8.2352941176470584e-01 9.0588235294117647e-01 + 7.0196078431372544e-01 8.2745098039215681e-01 9.0980392156862744e-01 + 7.0588235294117652e-01 8.2745098039215681e-01 9.0980392156862744e-01 + 7.0980392156862748e-01 8.3137254901960789e-01 9.1372549019607840e-01 + 7.1372549019607845e-01 8.3137254901960789e-01 9.1372549019607840e-01 + 7.2156862745098038e-01 8.3529411764705885e-01 9.1764705882352937e-01 + 7.2549019607843135e-01 8.3529411764705885e-01 9.1764705882352937e-01 + 7.2941176470588232e-01 8.3921568627450982e-01 9.2156862745098034e-01 + 7.3333333333333328e-01 8.3921568627450982e-01 9.2156862745098034e-01 + 7.3725490196078436e-01 8.4313725490196079e-01 9.2549019607843142e-01 + 7.4509803921568629e-01 8.4313725490196079e-01 9.2549019607843142e-01 + 7.4901960784313726e-01 8.4705882352941175e-01 9.2549019607843142e-01 + 7.5294117647058822e-01 8.4705882352941175e-01 9.2941176470588238e-01 + 7.5686274509803919e-01 8.4705882352941175e-01 9.2941176470588238e-01 + 7.6078431372549016e-01 8.5098039215686272e-01 9.3333333333333335e-01 + 7.6470588235294112e-01 8.5098039215686272e-01 9.3333333333333335e-01 + 7.6862745098039220e-01 8.5490196078431369e-01 9.3333333333333335e-01 + 7.7254901960784317e-01 8.5490196078431369e-01 9.3725490196078431e-01 + 7.7647058823529413e-01 8.5882352941176465e-01 9.3725490196078431e-01 + 7.8039215686274510e-01 8.6274509803921573e-01 9.3725490196078431e-01 + 7.8431372549019607e-01 8.6274509803921573e-01 9.4117647058823528e-01 + 7.8823529411764703e-01 8.6666666666666670e-01 9.4117647058823528e-01 + 7.9215686274509800e-01 8.6666666666666670e-01 9.4117647058823528e-01 + 7.9215686274509800e-01 8.7058823529411766e-01 9.4117647058823528e-01 + 7.9607843137254897e-01 8.7058823529411766e-01 9.4509803921568625e-01 + 8.0000000000000004e-01 8.7450980392156863e-01 9.4509803921568625e-01 + 8.0392156862745101e-01 8.7450980392156863e-01 9.4509803921568625e-01 + 8.0784313725490198e-01 8.7843137254901960e-01 9.4901960784313721e-01 + 8.0784313725490198e-01 8.7843137254901960e-01 9.4901960784313721e-01 + 8.1176470588235294e-01 8.8235294117647056e-01 9.4901960784313721e-01 + 8.1568627450980391e-01 8.8235294117647056e-01 9.4901960784313721e-01 + 8.1960784313725488e-01 8.8627450980392153e-01 9.5294117647058818e-01 + 8.1960784313725488e-01 8.8627450980392153e-01 9.5294117647058818e-01 + 8.2352941176470584e-01 8.9019607843137250e-01 9.5294117647058818e-01 + 8.2745098039215681e-01 8.9019607843137250e-01 9.5294117647058818e-01 + 8.2745098039215681e-01 8.9411764705882357e-01 9.5686274509803926e-01 + 8.3137254901960789e-01 8.9411764705882357e-01 9.5686274509803926e-01 + 8.3529411764705885e-01 8.9803921568627454e-01 9.5686274509803926e-01 + 8.3529411764705885e-01 8.9803921568627454e-01 9.5686274509803926e-01 + 8.3921568627450982e-01 9.0196078431372551e-01 9.5686274509803926e-01 + 8.4313725490196079e-01 9.0196078431372551e-01 9.6078431372549022e-01 + 8.4705882352941175e-01 9.0588235294117647e-01 9.6078431372549022e-01 + 8.4705882352941175e-01 9.0588235294117647e-01 9.6078431372549022e-01 + 8.5098039215686272e-01 9.0980392156862744e-01 9.6078431372549022e-01 + 8.5490196078431369e-01 9.0980392156862744e-01 9.6470588235294119e-01 + 8.5490196078431369e-01 9.1372549019607840e-01 9.6470588235294119e-01 + 8.5882352941176465e-01 9.1372549019607840e-01 9.6470588235294119e-01 + 8.6274509803921573e-01 9.1764705882352937e-01 9.6470588235294119e-01 + 8.6274509803921573e-01 9.1764705882352937e-01 9.6862745098039216e-01 + 8.6666666666666670e-01 9.2156862745098034e-01 9.6862745098039216e-01 + 8.7058823529411766e-01 9.2156862745098034e-01 9.6862745098039216e-01 + 8.7450980392156863e-01 9.2549019607843142e-01 9.6862745098039216e-01 + 8.7843137254901960e-01 9.2549019607843142e-01 9.7254901960784312e-01 + 8.7843137254901960e-01 9.2941176470588238e-01 9.7254901960784312e-01 + 8.8235294117647056e-01 9.2941176470588238e-01 9.7254901960784312e-01 + 8.8627450980392153e-01 9.3333333333333335e-01 9.7254901960784312e-01 + 8.9019607843137250e-01 9.3333333333333335e-01 9.7647058823529409e-01 + 8.9019607843137250e-01 9.3725490196078431e-01 9.7647058823529409e-01 + 8.9411764705882357e-01 9.3725490196078431e-01 9.7647058823529409e-01 + 8.9803921568627454e-01 9.4117647058823528e-01 9.7647058823529409e-01 + 9.0196078431372551e-01 9.4117647058823528e-01 9.8039215686274506e-01 + 9.0196078431372551e-01 9.4509803921568625e-01 9.8039215686274506e-01 + 9.0588235294117647e-01 9.4509803921568625e-01 9.8039215686274506e-01 + 9.0980392156862744e-01 9.4901960784313721e-01 9.8039215686274506e-01 + 9.1372549019607840e-01 9.4901960784313721e-01 9.8431372549019602e-01 + 9.1764705882352937e-01 9.5294117647058818e-01 9.8431372549019602e-01 + 9.1764705882352937e-01 9.5294117647058818e-01 9.8431372549019602e-01 + 9.2156862745098034e-01 9.5686274509803926e-01 9.8431372549019602e-01 + 9.2549019607843142e-01 9.5686274509803926e-01 9.8823529411764710e-01 + 9.2941176470588238e-01 9.6078431372549022e-01 9.8823529411764710e-01 + 9.3333333333333335e-01 9.6078431372549022e-01 9.8823529411764710e-01 + 9.3333333333333335e-01 9.6470588235294119e-01 9.8823529411764710e-01 + 9.3725490196078431e-01 9.6470588235294119e-01 9.9215686274509807e-01 + 9.4117647058823528e-01 9.6862745098039216e-01 9.9215686274509807e-01 + 9.4509803921568625e-01 9.6862745098039216e-01 9.9215686274509807e-01 + 9.4509803921568625e-01 9.7254901960784312e-01 9.9215686274509807e-01 + 9.4901960784313721e-01 9.7254901960784312e-01 9.9607843137254903e-01 + 9.5294117647058818e-01 9.7647058823529409e-01 9.9607843137254903e-01 + 9.5686274509803926e-01 9.7647058823529409e-01 9.9607843137254903e-01 + 9.6078431372549022e-01 9.8039215686274506e-01 9.9607843137254903e-01 + 9.6078431372549022e-01 9.8039215686274506e-01 1.0000000000000000e+00 + 9.6470588235294119e-01 9.8431372549019602e-01 1.0000000000000000e+00 + 9.6862745098039216e-01 9.8431372549019602e-01 1.0000000000000000e+00]; + case 'green' + Data=[... + 0.0000000000000000e+00 2.6666666666666666e-01 1.0588235294117647e-01 + 0.0000000000000000e+00 2.7058823529411763e-01 1.0588235294117647e-01 + 0.0000000000000000e+00 2.7843137254901962e-01 1.0980392156862745e-01 + 0.0000000000000000e+00 2.8235294117647058e-01 1.0980392156862745e-01 + 0.0000000000000000e+00 2.9019607843137257e-01 1.1372549019607843e-01 + 0.0000000000000000e+00 2.9411764705882354e-01 1.1372549019607843e-01 + 0.0000000000000000e+00 3.0196078431372547e-01 1.1764705882352941e-01 + 0.0000000000000000e+00 3.0588235294117649e-01 1.1764705882352941e-01 + 0.0000000000000000e+00 3.0980392156862746e-01 1.2156862745098039e-01 + 0.0000000000000000e+00 3.1764705882352939e-01 1.2156862745098039e-01 + 0.0000000000000000e+00 3.2156862745098042e-01 1.2549019607843137e-01 + 0.0000000000000000e+00 3.2549019607843138e-01 1.2549019607843137e-01 + 0.0000000000000000e+00 3.3333333333333331e-01 1.2941176470588237e-01 + 0.0000000000000000e+00 3.3725490196078434e-01 1.2941176470588237e-01 + 0.0000000000000000e+00 3.4117647058823530e-01 1.3333333333333333e-01 + 0.0000000000000000e+00 3.4901960784313724e-01 1.3333333333333333e-01 + 0.0000000000000000e+00 3.5294117647058826e-01 1.3725490196078433e-01 + 0.0000000000000000e+00 3.5686274509803922e-01 1.3725490196078433e-01 + 0.0000000000000000e+00 3.6470588235294116e-01 1.4117647058823529e-01 + 0.0000000000000000e+00 3.6862745098039218e-01 1.4117647058823529e-01 + 0.0000000000000000e+00 3.7254901960784315e-01 1.4509803921568629e-01 + 0.0000000000000000e+00 3.7647058823529411e-01 1.4509803921568629e-01 + 0.0000000000000000e+00 3.8039215686274508e-01 1.4901960784313725e-01 + 0.0000000000000000e+00 3.8823529411764707e-01 1.5294117647058825e-01 + 0.0000000000000000e+00 3.9215686274509803e-01 1.5294117647058825e-01 + 0.0000000000000000e+00 3.9607843137254900e-01 1.5686274509803921e-01 + 0.0000000000000000e+00 4.0000000000000002e-01 1.5686274509803921e-01 + 0.0000000000000000e+00 4.0392156862745099e-01 1.6078431372549021e-01 + 0.0000000000000000e+00 4.1176470588235292e-01 1.6470588235294117e-01 + 0.0000000000000000e+00 4.1568627450980394e-01 1.6470588235294117e-01 + 0.0000000000000000e+00 4.1960784313725491e-01 1.6862745098039217e-01 + 0.0000000000000000e+00 4.2352941176470588e-01 1.6862745098039217e-01 + 0.0000000000000000e+00 4.2745098039215684e-01 1.7254901960784313e-01 + 0.0000000000000000e+00 4.3137254901960786e-01 1.7647058823529413e-01 + 0.0000000000000000e+00 4.3529411764705883e-01 1.7647058823529413e-01 + 3.9215686274509803e-03 4.3921568627450980e-01 1.8039215686274510e-01 + 3.9215686274509803e-03 4.4313725490196076e-01 1.8431372549019609e-01 + 7.8431372549019607e-03 4.4705882352941179e-01 1.8431372549019609e-01 + 7.8431372549019607e-03 4.5098039215686275e-01 1.8823529411764706e-01 + 1.1764705882352941e-02 4.5490196078431372e-01 1.9215686274509805e-01 + 1.5686274509803921e-02 4.5882352941176469e-01 1.9607843137254902e-01 + 1.9607843137254902e-02 4.6274509803921571e-01 1.9607843137254902e-01 + 2.3529411764705882e-02 4.6666666666666667e-01 2.0000000000000001e-01 + 2.7450980392156862e-02 4.7058823529411764e-01 2.0392156862745098e-01 + 3.1372549019607843e-02 4.7450980392156861e-01 2.0784313725490197e-01 + 3.5294117647058823e-02 4.7843137254901963e-01 2.1176470588235294e-01 + 4.3137254901960784e-02 4.8235294117647060e-01 2.1176470588235294e-01 + 4.7058823529411764e-02 4.8627450980392156e-01 2.1568627450980393e-01 + 5.0980392156862744e-02 4.8627450980392156e-01 2.1960784313725490e-01 + 5.8823529411764705e-02 4.9019607843137253e-01 2.2352941176470589e-01 + 6.2745098039215685e-02 4.9411764705882355e-01 2.2745098039215686e-01 + 7.0588235294117646e-02 4.9803921568627452e-01 2.2745098039215686e-01 + 7.4509803921568626e-02 5.0196078431372548e-01 2.3137254901960785e-01 + 8.2352941176470587e-02 5.0588235294117645e-01 2.3529411764705882e-01 + 8.6274509803921567e-02 5.0980392156862742e-01 2.3921568627450981e-01 + 9.4117647058823528e-02 5.1372549019607838e-01 2.4313725490196078e-01 + 9.8039215686274508e-02 5.1764705882352946e-01 2.4705882352941178e-01 + 1.0196078431372549e-01 5.1764705882352946e-01 2.4705882352941178e-01 + 1.0980392156862745e-01 5.2156862745098043e-01 2.5098039215686274e-01 + 1.1372549019607843e-01 5.2549019607843139e-01 2.5490196078431371e-01 + 1.1764705882352941e-01 5.2941176470588236e-01 2.5882352941176473e-01 + 1.2549019607843137e-01 5.3333333333333333e-01 2.6274509803921570e-01 + 1.2941176470588237e-01 5.3725490196078429e-01 2.6274509803921570e-01 + 1.3333333333333333e-01 5.4117647058823526e-01 2.6666666666666666e-01 + 1.3725490196078433e-01 5.4509803921568623e-01 2.7058823529411763e-01 + 1.4117647058823529e-01 5.4901960784313730e-01 2.7450980392156865e-01 + 1.4509803921568629e-01 5.5294117647058827e-01 2.7843137254901962e-01 + 1.4901960784313725e-01 5.5686274509803924e-01 2.7843137254901962e-01 + 1.5294117647058825e-01 5.6078431372549020e-01 2.8235294117647058e-01 + 1.5686274509803921e-01 5.6470588235294117e-01 2.8627450980392155e-01 + 1.6078431372549021e-01 5.6862745098039214e-01 2.9019607843137257e-01 + 1.6470588235294117e-01 5.7254901960784310e-01 2.9019607843137257e-01 + 1.6470588235294117e-01 5.7647058823529407e-01 2.9411764705882354e-01 + 1.6862745098039217e-01 5.8039215686274515e-01 2.9803921568627451e-01 + 1.7254901960784313e-01 5.8431372549019611e-01 3.0196078431372547e-01 + 1.7647058823529413e-01 5.8823529411764708e-01 3.0196078431372547e-01 + 1.8039215686274510e-01 5.9215686274509804e-01 3.0588235294117649e-01 + 1.8431372549019609e-01 5.9607843137254901e-01 3.0980392156862746e-01 + 1.8823529411764706e-01 5.9999999999999998e-01 3.0980392156862746e-01 + 1.8823529411764706e-01 6.0392156862745094e-01 3.1372549019607843e-01 + 1.9215686274509805e-01 6.0784313725490191e-01 3.1764705882352939e-01 + 1.9607843137254902e-01 6.1176470588235299e-01 3.2156862745098042e-01 + 2.0000000000000001e-01 6.1568627450980395e-01 3.2156862745098042e-01 + 2.0392156862745098e-01 6.1960784313725492e-01 3.2549019607843138e-01 + 2.0784313725490197e-01 6.2352941176470589e-01 3.2941176470588235e-01 + 2.1176470588235294e-01 6.2745098039215685e-01 3.3333333333333331e-01 + 2.1568627450980393e-01 6.3137254901960782e-01 3.3333333333333331e-01 + 2.1568627450980393e-01 6.3529411764705879e-01 3.3725490196078434e-01 + 2.1960784313725490e-01 6.3921568627450975e-01 3.4117647058823530e-01 + 2.2352941176470589e-01 6.4313725490196083e-01 3.4509803921568627e-01 + 2.2745098039215686e-01 6.4705882352941180e-01 3.4509803921568627e-01 + 2.3137254901960785e-01 6.5098039215686276e-01 3.4901960784313724e-01 + 2.3529411764705882e-01 6.5490196078431373e-01 3.5294117647058826e-01 + 2.4313725490196078e-01 6.5882352941176470e-01 3.5686274509803922e-01 + 2.4705882352941178e-01 6.6274509803921566e-01 3.5686274509803922e-01 + 2.5098039215686274e-01 6.6666666666666663e-01 3.6078431372549019e-01 + 2.5490196078431371e-01 6.7058823529411760e-01 3.6470588235294116e-01 + 2.5882352941176473e-01 6.7450980392156867e-01 3.6862745098039218e-01 + 2.6666666666666666e-01 6.7843137254901964e-01 3.7254901960784315e-01 + 2.7058823529411763e-01 6.8235294117647061e-01 3.7254901960784315e-01 + 2.7450980392156865e-01 6.8627450980392157e-01 3.7647058823529411e-01 + 2.8235294117647058e-01 6.8627450980392157e-01 3.8039215686274508e-01 + 2.8627450980392155e-01 6.9019607843137254e-01 3.8431372549019610e-01 + 2.9411764705882354e-01 6.9411764705882351e-01 3.8431372549019610e-01 + 2.9803921568627451e-01 6.9803921568627447e-01 3.8823529411764707e-01 + 3.0588235294117649e-01 7.0196078431372544e-01 3.9215686274509803e-01 + 3.1372549019607843e-01 7.0588235294117652e-01 3.9607843137254900e-01 + 3.1764705882352939e-01 7.0588235294117652e-01 3.9607843137254900e-01 + 3.2549019607843138e-01 7.0980392156862748e-01 4.0000000000000002e-01 + 3.3333333333333331e-01 7.1372549019607845e-01 4.0392156862745099e-01 + 3.4117647058823530e-01 7.1764705882352942e-01 4.0784313725490196e-01 + 3.4509803921568627e-01 7.2156862745098038e-01 4.0784313725490196e-01 + 3.5294117647058826e-01 7.2549019607843135e-01 4.1176470588235292e-01 + 3.6078431372549019e-01 7.2549019607843135e-01 4.1568627450980394e-01 + 3.6862745098039218e-01 7.2941176470588232e-01 4.1960784313725491e-01 + 3.7647058823529411e-01 7.3333333333333328e-01 4.2352941176470588e-01 + 3.8039215686274508e-01 7.3725490196078436e-01 4.2352941176470588e-01 + 3.8823529411764707e-01 7.4117647058823533e-01 4.2745098039215684e-01 + 3.9607843137254900e-01 7.4117647058823533e-01 4.3137254901960786e-01 + 4.0392156862745099e-01 7.4509803921568629e-01 4.3529411764705883e-01 + 4.0784313725490196e-01 7.4901960784313726e-01 4.3921568627450980e-01 + 4.1568627450980394e-01 7.5294117647058822e-01 4.4313725490196076e-01 + 4.2352941176470588e-01 7.5294117647058822e-01 4.4313725490196076e-01 + 4.3137254901960786e-01 7.5686274509803919e-01 4.4705882352941179e-01 + 4.3529411764705883e-01 7.6078431372549016e-01 4.5098039215686275e-01 + 4.4313725490196076e-01 7.6470588235294112e-01 4.5490196078431372e-01 + 4.4705882352941179e-01 7.6470588235294112e-01 4.5882352941176469e-01 + 4.5490196078431372e-01 7.6862745098039220e-01 4.6274509803921571e-01 + 4.6274509803921571e-01 7.7254901960784317e-01 4.6666666666666667e-01 + 4.6666666666666667e-01 7.7254901960784317e-01 4.7058823529411764e-01 + 4.7450980392156861e-01 7.7647058823529413e-01 4.7450980392156861e-01 + 4.7843137254901963e-01 7.8039215686274510e-01 4.7843137254901963e-01 + 4.8627450980392156e-01 7.8431372549019607e-01 4.8235294117647060e-01 + 4.9019607843137253e-01 7.8431372549019607e-01 4.8627450980392156e-01 + 4.9411764705882355e-01 7.8823529411764703e-01 4.9019607843137253e-01 + 5.0196078431372548e-01 7.9215686274509800e-01 4.9411764705882355e-01 + 5.0588235294117645e-01 7.9215686274509800e-01 4.9803921568627452e-01 + 5.1372549019607838e-01 7.9607843137254897e-01 5.0588235294117645e-01 + 5.1764705882352946e-01 8.0000000000000004e-01 5.0980392156862742e-01 + 5.2549019607843139e-01 8.0000000000000004e-01 5.1372549019607838e-01 + 5.2941176470588236e-01 8.0392156862745101e-01 5.1764705882352946e-01 + 5.3725490196078429e-01 8.0784313725490198e-01 5.2156862745098043e-01 + 5.4117647058823526e-01 8.0784313725490198e-01 5.2549019607843139e-01 + 5.4509803921568623e-01 8.1176470588235294e-01 5.3333333333333333e-01 + 5.5294117647058827e-01 8.1568627450980391e-01 5.3725490196078429e-01 + 5.5686274509803924e-01 8.1568627450980391e-01 5.4117647058823526e-01 + 5.6470588235294117e-01 8.1960784313725488e-01 5.4509803921568623e-01 + 5.6862745098039214e-01 8.2352941176470584e-01 5.5294117647058827e-01 + 5.7254901960784310e-01 8.2352941176470584e-01 5.5686274509803924e-01 + 5.8039215686274515e-01 8.2745098039215681e-01 5.6078431372549020e-01 + 5.8431372549019611e-01 8.3137254901960789e-01 5.6470588235294117e-01 + 5.8823529411764708e-01 8.3137254901960789e-01 5.6862745098039214e-01 + 5.9607843137254901e-01 8.3529411764705885e-01 5.7647058823529407e-01 + 5.9999999999999998e-01 8.3529411764705885e-01 5.8039215686274515e-01 + 6.0392156862745094e-01 8.3921568627450982e-01 5.8431372549019611e-01 + 6.1176470588235299e-01 8.4313725490196079e-01 5.8823529411764708e-01 + 6.1568627450980395e-01 8.4313725490196079e-01 5.9215686274509804e-01 + 6.1960784313725492e-01 8.4705882352941175e-01 5.9999999999999998e-01 + 6.2745098039215685e-01 8.4705882352941175e-01 6.0392156862745094e-01 + 6.3137254901960782e-01 8.5098039215686272e-01 6.0784313725490191e-01 + 6.3529411764705879e-01 8.5490196078431369e-01 6.1176470588235299e-01 + 6.4313725490196083e-01 8.5490196078431369e-01 6.1568627450980395e-01 + 6.4705882352941180e-01 8.5882352941176465e-01 6.1960784313725492e-01 + 6.5098039215686276e-01 8.5882352941176465e-01 6.2745098039215685e-01 + 6.5490196078431373e-01 8.6274509803921573e-01 6.3137254901960782e-01 + 6.6274509803921566e-01 8.6274509803921573e-01 6.3529411764705879e-01 + 6.6666666666666663e-01 8.6666666666666670e-01 6.3921568627450975e-01 + 6.7058823529411760e-01 8.6666666666666670e-01 6.4313725490196083e-01 + 6.7450980392156867e-01 8.7058823529411766e-01 6.5098039215686276e-01 + 6.8235294117647061e-01 8.7058823529411766e-01 6.5490196078431373e-01 + 6.8627450980392157e-01 8.7450980392156863e-01 6.5882352941176470e-01 + 6.9019607843137254e-01 8.7843137254901960e-01 6.6274509803921566e-01 + 6.9411764705882351e-01 8.7843137254901960e-01 6.6666666666666663e-01 + 7.0196078431372544e-01 8.8235294117647056e-01 6.7058823529411760e-01 + 7.0588235294117652e-01 8.8235294117647056e-01 6.7843137254901964e-01 + 7.0980392156862748e-01 8.8627450980392153e-01 6.8235294117647061e-01 + 7.1372549019607845e-01 8.8627450980392153e-01 6.8627450980392157e-01 + 7.1764705882352942e-01 8.9019607843137250e-01 6.9019607843137254e-01 + 7.2549019607843135e-01 8.9019607843137250e-01 6.9411764705882351e-01 + 7.2941176470588232e-01 8.9411764705882357e-01 7.0196078431372544e-01 + 7.3333333333333328e-01 8.9411764705882357e-01 7.0588235294117652e-01 + 7.3725490196078436e-01 8.9411764705882357e-01 7.0980392156862748e-01 + 7.4117647058823533e-01 8.9803921568627454e-01 7.1372549019607845e-01 + 7.4509803921568629e-01 8.9803921568627454e-01 7.1764705882352942e-01 + 7.4901960784313726e-01 9.0196078431372551e-01 7.2156862745098038e-01 + 7.5686274509803919e-01 9.0196078431372551e-01 7.2549019607843135e-01 + 7.6078431372549016e-01 9.0588235294117647e-01 7.3333333333333328e-01 + 7.6470588235294112e-01 9.0588235294117647e-01 7.3725490196078436e-01 + 7.6862745098039220e-01 9.0980392156862744e-01 7.4117647058823533e-01 + 7.7254901960784317e-01 9.0980392156862744e-01 7.4509803921568629e-01 + 7.7647058823529413e-01 9.1372549019607840e-01 7.4901960784313726e-01 + 7.8039215686274510e-01 9.1372549019607840e-01 7.5294117647058822e-01 + 7.8431372549019607e-01 9.1372549019607840e-01 7.5686274509803919e-01 + 7.8823529411764703e-01 9.1764705882352937e-01 7.6078431372549016e-01 + 7.9215686274509800e-01 9.1764705882352937e-01 7.6470588235294112e-01 + 7.9607843137254897e-01 9.2156862745098034e-01 7.6862745098039220e-01 + 8.0000000000000004e-01 9.2156862745098034e-01 7.7254901960784317e-01 + 8.0392156862745101e-01 9.2549019607843142e-01 7.7647058823529413e-01 + 8.0784313725490198e-01 9.2549019607843142e-01 7.8431372549019607e-01 + 8.1176470588235294e-01 9.2549019607843142e-01 7.8823529411764703e-01 + 8.1568627450980391e-01 9.2941176470588238e-01 7.9215686274509800e-01 + 8.1960784313725488e-01 9.2941176470588238e-01 7.9607843137254897e-01 + 8.2352941176470584e-01 9.3333333333333335e-01 8.0000000000000004e-01 + 8.2745098039215681e-01 9.3333333333333335e-01 8.0392156862745101e-01 + 8.3137254901960789e-01 9.3333333333333335e-01 8.0784313725490198e-01 + 8.3529411764705885e-01 9.3725490196078431e-01 8.1176470588235294e-01 + 8.3921568627450982e-01 9.3725490196078431e-01 8.1568627450980391e-01 + 8.4313725490196079e-01 9.4117647058823528e-01 8.1960784313725488e-01 + 8.4705882352941175e-01 9.4117647058823528e-01 8.2352941176470584e-01 + 8.5098039215686272e-01 9.4117647058823528e-01 8.2745098039215681e-01 + 8.5490196078431369e-01 9.4509803921568625e-01 8.3137254901960789e-01 + 8.5882352941176465e-01 9.4509803921568625e-01 8.3529411764705885e-01 + 8.6274509803921573e-01 9.4509803921568625e-01 8.3921568627450982e-01 + 8.6666666666666670e-01 9.4901960784313721e-01 8.4313725490196079e-01 + 8.7058823529411766e-01 9.4901960784313721e-01 8.4705882352941175e-01 + 8.7450980392156863e-01 9.5294117647058818e-01 8.5098039215686272e-01 + 8.7843137254901960e-01 9.5294117647058818e-01 8.5490196078431369e-01 + 8.7843137254901960e-01 9.5294117647058818e-01 8.5882352941176465e-01 + 8.8235294117647056e-01 9.5686274509803926e-01 8.6274509803921573e-01 + 8.8627450980392153e-01 9.5686274509803926e-01 8.6666666666666670e-01 + 8.9019607843137250e-01 9.5686274509803926e-01 8.7058823529411766e-01 + 8.9411764705882357e-01 9.5686274509803926e-01 8.7058823529411766e-01 + 8.9411764705882357e-01 9.6078431372549022e-01 8.7450980392156863e-01 + 8.9803921568627454e-01 9.6078431372549022e-01 8.7843137254901960e-01 + 9.0196078431372551e-01 9.6078431372549022e-01 8.8235294117647056e-01 + 9.0196078431372551e-01 9.6470588235294119e-01 8.8627450980392153e-01 + 9.0588235294117647e-01 9.6470588235294119e-01 8.8627450980392153e-01 + 9.0980392156862744e-01 9.6470588235294119e-01 8.9019607843137250e-01 + 9.0980392156862744e-01 9.6470588235294119e-01 8.9411764705882357e-01 + 9.1372549019607840e-01 9.6862745098039216e-01 8.9803921568627454e-01 + 9.1764705882352937e-01 9.6862745098039216e-01 8.9803921568627454e-01 + 9.1764705882352937e-01 9.6862745098039216e-01 9.0196078431372551e-01 + 9.2156862745098034e-01 9.6862745098039216e-01 9.0588235294117647e-01 + 9.2549019607843142e-01 9.7254901960784312e-01 9.0980392156862744e-01 + 9.2549019607843142e-01 9.7254901960784312e-01 9.0980392156862744e-01 + 9.2941176470588238e-01 9.7254901960784312e-01 9.1372549019607840e-01 + 9.3333333333333335e-01 9.7254901960784312e-01 9.1764705882352937e-01 + 9.3333333333333335e-01 9.7647058823529409e-01 9.1764705882352937e-01 + 9.3725490196078431e-01 9.7647058823529409e-01 9.2156862745098034e-01 + 9.3725490196078431e-01 9.7647058823529409e-01 9.2549019607843142e-01 + 9.4117647058823528e-01 9.7647058823529409e-01 9.2549019607843142e-01 + 9.4117647058823528e-01 9.7647058823529409e-01 9.2941176470588238e-01 + 9.4509803921568625e-01 9.8039215686274506e-01 9.3333333333333335e-01 + 9.4901960784313721e-01 9.8039215686274506e-01 9.3333333333333335e-01 + 9.4901960784313721e-01 9.8039215686274506e-01 9.3725490196078431e-01 + 9.5294117647058818e-01 9.8039215686274506e-01 9.4117647058823528e-01 + 9.5294117647058818e-01 9.8039215686274506e-01 9.4117647058823528e-01 + 9.5686274509803926e-01 9.8431372549019602e-01 9.4509803921568625e-01 + 9.5686274509803926e-01 9.8431372549019602e-01 9.4509803921568625e-01 + 9.5686274509803926e-01 9.8431372549019602e-01 9.4901960784313721e-01 + 9.6078431372549022e-01 9.8431372549019602e-01 9.4901960784313721e-01 + 9.6078431372549022e-01 9.8431372549019602e-01 9.5294117647058818e-01 + 9.6470588235294119e-01 9.8823529411764710e-01 9.5294117647058818e-01 + 9.6470588235294119e-01 9.8823529411764710e-01 9.5686274509803926e-01 + 9.6862745098039216e-01 9.8823529411764710e-01 9.6078431372549022e-01 + 9.6862745098039216e-01 9.8823529411764710e-01 9.6078431372549022e-01 ]; + case 'diverging' + Data=flipud([... + 4.0392156862745099e-01 0.0000000000000000e+00 1.2156862745098039e-01 + 4.1960784313725491e-01 0.0000000000000000e+00 1.2156862745098039e-01 + 4.3137254901960786e-01 0.0000000000000000e+00 1.2156862745098039e-01 + 4.4705882352941179e-01 0.0000000000000000e+00 1.2156862745098039e-01 + 4.5882352941176469e-01 3.9215686274509803e-03 1.2156862745098039e-01 + 4.7450980392156861e-01 3.9215686274509803e-03 1.2549019607843137e-01 + 4.8627450980392156e-01 7.8431372549019607e-03 1.2549019607843137e-01 + 4.9803921568627452e-01 7.8431372549019607e-03 1.2549019607843137e-01 + 5.1372549019607838e-01 1.1764705882352941e-02 1.2941176470588237e-01 + 5.2549019607843139e-01 1.5686274509803921e-02 1.2941176470588237e-01 + 5.3725490196078429e-01 1.9607843137254902e-02 1.2941176470588237e-01 + 5.4901960784313730e-01 1.9607843137254902e-02 1.3333333333333333e-01 + 5.6078431372549020e-01 2.3529411764705882e-02 1.3333333333333333e-01 + 5.7254901960784310e-01 2.7450980392156862e-02 1.3725490196078433e-01 + 5.8431372549019611e-01 3.5294117647058823e-02 1.3725490196078433e-01 + 5.9607843137254901e-01 3.9215686274509803e-02 1.4117647058823529e-01 + 6.0784313725490191e-01 4.3137254901960784e-02 1.4117647058823529e-01 + 6.1568627450980395e-01 4.7058823529411764e-02 1.4509803921568629e-01 + 6.2745098039215685e-01 5.0980392156862744e-02 1.4901960784313725e-01 + 6.3529411764705879e-01 5.4901960784313725e-02 1.4901960784313725e-01 + 6.4705882352941180e-01 6.2745098039215685e-02 1.5294117647058825e-01 + 6.5490196078431373e-01 6.6666666666666666e-02 1.5686274509803921e-01 + 6.6666666666666663e-01 7.0588235294117646e-02 1.5686274509803921e-01 + 6.7450980392156867e-01 7.8431372549019607e-02 1.6078431372549021e-01 + 6.8235294117647061e-01 8.2352941176470587e-02 1.6470588235294117e-01 + 6.9019607843137254e-01 9.0196078431372548e-02 1.6470588235294117e-01 + 6.9803921568627447e-01 9.4117647058823528e-02 1.6862745098039217e-01 + 7.0588235294117652e-01 1.0196078431372549e-01 1.7254901960784313e-01 + 7.1372549019607845e-01 1.0588235294117647e-01 1.7647058823529413e-01 + 7.1764705882352942e-01 1.1372549019607843e-01 1.7647058823529413e-01 + 7.2549019607843135e-01 1.2156862745098039e-01 1.8039215686274510e-01 + 7.3333333333333328e-01 1.3333333333333333e-01 1.8431372549019609e-01 + 7.3725490196078436e-01 1.4117647058823529e-01 1.9215686274509805e-01 + 7.4509803921568629e-01 1.5294117647058825e-01 1.9607843137254902e-01 + 7.5294117647058822e-01 1.6470588235294117e-01 2.0000000000000001e-01 + 7.5686274509803919e-01 1.7647058823529413e-01 2.0392156862745098e-01 + 7.6078431372549016e-01 1.8823529411764706e-01 2.1176470588235294e-01 + 7.6862745098039220e-01 2.0000000000000001e-01 2.1568627450980393e-01 + 7.7254901960784317e-01 2.1176470588235294e-01 2.1960784313725490e-01 + 7.8039215686274510e-01 2.2352941176470589e-01 2.2745098039215686e-01 + 7.8431372549019607e-01 2.3921568627450981e-01 2.3137254901960785e-01 + 7.8823529411764703e-01 2.5098039215686274e-01 2.3921568627450981e-01 + 7.9607843137254897e-01 2.6274509803921570e-01 2.4313725490196078e-01 + 8.0000000000000004e-01 2.7843137254901962e-01 2.5098039215686274e-01 + 8.0392156862745101e-01 2.9019607843137257e-01 2.5882352941176473e-01 + 8.0784313725490198e-01 3.0588235294117649e-01 2.6274509803921570e-01 + 8.1568627450980391e-01 3.1764705882352939e-01 2.7058823529411763e-01 + 8.1960784313725488e-01 3.2941176470588235e-01 2.7450980392156865e-01 + 8.2352941176470584e-01 3.4117647058823530e-01 2.8235294117647058e-01 + 8.2745098039215681e-01 3.5294117647058826e-01 2.9019607843137257e-01 + 8.3529411764705885e-01 3.6470588235294116e-01 2.9411764705882354e-01 + 8.3921568627450982e-01 3.7647058823529411e-01 3.0196078431372547e-01 + 8.4313725490196079e-01 3.8823529411764707e-01 3.0980392156862746e-01 + 8.5098039215686272e-01 4.0000000000000002e-01 3.1372549019607843e-01 + 8.5490196078431369e-01 4.0784313725490196e-01 3.2156862745098042e-01 + 8.5882352941176465e-01 4.1960784313725491e-01 3.2941176470588235e-01 + 8.6666666666666670e-01 4.3137254901960786e-01 3.3725490196078434e-01 + 8.7058823529411766e-01 4.4313725490196076e-01 3.4117647058823530e-01 + 8.7450980392156863e-01 4.5098039215686275e-01 3.4901960784313724e-01 + 8.8235294117647056e-01 4.6274509803921571e-01 3.5686274509803922e-01 + 8.8627450980392153e-01 4.7450980392156861e-01 3.6470588235294116e-01 + 8.9019607843137250e-01 4.8627450980392156e-01 3.7254901960784315e-01 + 8.9803921568627454e-01 4.9411764705882355e-01 3.8039215686274508e-01 + 9.0196078431372551e-01 5.0588235294117645e-01 3.8823529411764707e-01 + 9.0588235294117647e-01 5.1764705882352946e-01 3.9607843137254900e-01 + 9.1372549019607840e-01 5.2549019607843139e-01 4.0392156862745099e-01 + 9.1764705882352937e-01 5.3725490196078429e-01 4.1176470588235292e-01 + 9.2156862745098034e-01 5.4901960784313730e-01 4.1960784313725491e-01 + 9.2549019607843142e-01 5.5686274509803924e-01 4.3137254901960786e-01 + 9.2941176470588238e-01 5.6862745098039214e-01 4.3921568627450980e-01 + 9.3333333333333335e-01 5.8039215686274515e-01 4.4705882352941179e-01 + 9.3725490196078431e-01 5.8823529411764708e-01 4.5490196078431372e-01 + 9.4117647058823528e-01 5.9999999999999998e-01 4.6274509803921571e-01 + 9.4509803921568625e-01 6.0784313725490191e-01 4.7450980392156861e-01 + 9.4901960784313721e-01 6.1960784313725492e-01 4.8235294117647060e-01 + 9.5294117647058818e-01 6.2745098039215685e-01 4.9019607843137253e-01 + 9.5294117647058818e-01 6.3921568627450975e-01 5.0196078431372548e-01 + 9.5686274509803926e-01 6.4705882352941180e-01 5.0980392156862742e-01 + 9.6078431372549022e-01 6.5490196078431373e-01 5.1764705882352946e-01 + 9.6078431372549022e-01 6.6666666666666663e-01 5.2941176470588236e-01 + 9.6470588235294119e-01 6.7450980392156867e-01 5.3725490196078429e-01 + 9.6470588235294119e-01 6.8627450980392157e-01 5.4901960784313730e-01 + 9.6862745098039216e-01 6.9411764705882351e-01 5.6078431372549020e-01 + 9.6862745098039216e-01 7.0588235294117652e-01 5.7254901960784310e-01 + 9.7254901960784312e-01 7.1372549019607845e-01 5.8431372549019611e-01 + 9.7254901960784312e-01 7.2156862745098038e-01 5.9607843137254901e-01 + 9.7647058823529409e-01 7.3333333333333328e-01 6.0392156862745094e-01 + 9.7647058823529409e-01 7.4117647058823533e-01 6.1568627450980395e-01 + 9.8039215686274506e-01 7.4901960784313726e-01 6.2745098039215685e-01 + 9.8039215686274506e-01 7.6078431372549016e-01 6.3921568627450975e-01 + 9.8039215686274506e-01 7.6862745098039220e-01 6.5098039215686276e-01 + 9.8431372549019602e-01 7.7647058823529413e-01 6.6274509803921566e-01 + 9.8431372549019602e-01 7.8823529411764703e-01 6.7450980392156867e-01 + 9.8431372549019602e-01 7.9607843137254897e-01 6.8627450980392157e-01 + 9.8823529411764710e-01 8.0392156862745101e-01 6.9803921568627447e-01 + 9.8823529411764710e-01 8.1176470588235294e-01 7.0980392156862748e-01 + 9.8823529411764710e-01 8.1960784313725488e-01 7.2156862745098038e-01 + 9.9215686274509807e-01 8.2745098039215681e-01 7.3333333333333328e-01 + 9.9215686274509807e-01 8.3529411764705885e-01 7.4117647058823533e-01 + 9.9215686274509807e-01 8.3921568627450982e-01 7.5294117647058822e-01 + 9.9215686274509807e-01 8.4705882352941175e-01 7.6078431372549016e-01 + 9.9215686274509807e-01 8.5490196078431369e-01 7.7254901960784317e-01 + 9.9215686274509807e-01 8.5882352941176465e-01 7.8039215686274510e-01 + 9.9215686274509807e-01 8.6274509803921573e-01 7.8823529411764703e-01 + 9.9215686274509807e-01 8.7058823529411766e-01 8.0000000000000004e-01 + 9.9215686274509807e-01 8.7450980392156863e-01 8.0784313725490198e-01 + 9.9215686274509807e-01 8.8235294117647056e-01 8.1568627450980391e-01 + 9.9215686274509807e-01 8.8627450980392153e-01 8.2745098039215681e-01 + 9.9215686274509807e-01 8.9411764705882357e-01 8.3529411764705885e-01 + 9.8823529411764710e-01 8.9803921568627454e-01 8.4705882352941175e-01 + 9.8823529411764710e-01 9.0588235294117647e-01 8.5490196078431369e-01 + 9.8823529411764710e-01 9.0980392156862744e-01 8.6666666666666670e-01 + 9.8823529411764710e-01 9.1764705882352937e-01 8.7450980392156863e-01 + 9.8823529411764710e-01 9.2156862745098034e-01 8.8627450980392153e-01 + 9.8823529411764710e-01 9.2549019607843142e-01 8.9411764705882357e-01 + 9.8431372549019602e-01 9.3333333333333335e-01 9.0196078431372551e-01 + 9.8431372549019602e-01 9.3725490196078431e-01 9.0980392156862744e-01 + 9.8431372549019602e-01 9.4117647058823528e-01 9.1764705882352937e-01 + 9.8431372549019602e-01 9.4509803921568625e-01 9.2549019607843142e-01 + 9.8039215686274506e-01 9.4901960784313721e-01 9.3333333333333335e-01 + 9.8039215686274506e-01 9.5294117647058818e-01 9.4117647058823528e-01 + 9.8039215686274506e-01 9.5686274509803926e-01 9.4509803921568625e-01 + 9.7647058823529409e-01 9.6078431372549022e-01 9.5294117647058818e-01 + 9.7647058823529409e-01 9.6078431372549022e-01 9.5686274509803926e-01 + 9.7647058823529409e-01 9.6470588235294119e-01 9.6078431372549022e-01 + 9.7254901960784312e-01 9.6470588235294119e-01 9.6470588235294119e-01 + 9.7254901960784312e-01 9.6862745098039216e-01 9.6862745098039216e-01 + 9.6862745098039216e-01 9.6862745098039216e-01 9.6862745098039216e-01 + 9.6862745098039216e-01 9.6862745098039216e-01 9.6862745098039216e-01 + 9.6862745098039216e-01 9.6862745098039216e-01 9.6862745098039216e-01 + 9.6470588235294119e-01 9.6862745098039216e-01 9.6862745098039216e-01 + 9.6078431372549022e-01 9.6862745098039216e-01 9.6862745098039216e-01 + 9.5686274509803926e-01 9.6470588235294119e-01 9.6862745098039216e-01 + 9.5294117647058818e-01 9.6470588235294119e-01 9.6862745098039216e-01 + 9.4901960784313721e-01 9.6078431372549022e-01 9.6470588235294119e-01 + 9.4509803921568625e-01 9.6078431372549022e-01 9.6470588235294119e-01 + 9.4117647058823528e-01 9.5686274509803926e-01 9.6470588235294119e-01 + 9.3333333333333335e-01 9.5686274509803926e-01 9.6470588235294119e-01 + 9.2941176470588238e-01 9.5294117647058818e-01 9.6078431372549022e-01 + 9.2156862745098034e-01 9.4901960784313721e-01 9.6078431372549022e-01 + 9.1372549019607840e-01 9.4509803921568625e-01 9.6078431372549022e-01 + 9.0980392156862744e-01 9.4117647058823528e-01 9.6078431372549022e-01 + 9.0196078431372551e-01 9.4117647058823528e-01 9.5686274509803926e-01 + 8.9411764705882357e-01 9.3725490196078431e-01 9.5686274509803926e-01 + 8.8627450980392153e-01 9.3333333333333335e-01 9.5686274509803926e-01 + 8.7843137254901960e-01 9.2941176470588238e-01 9.5294117647058818e-01 + 8.7058823529411766e-01 9.2549019607843142e-01 9.5294117647058818e-01 + 8.6666666666666670e-01 9.2156862745098034e-01 9.4901960784313721e-01 + 8.5882352941176465e-01 9.1764705882352937e-01 9.4901960784313721e-01 + 8.5098039215686272e-01 9.1372549019607840e-01 9.4901960784313721e-01 + 8.4313725490196079e-01 9.0980392156862744e-01 9.4509803921568625e-01 + 8.3529411764705885e-01 9.0588235294117647e-01 9.4509803921568625e-01 + 8.2745098039215681e-01 9.0196078431372551e-01 9.4117647058823528e-01 + 8.1960784313725488e-01 8.9803921568627454e-01 9.4117647058823528e-01 + 8.1176470588235294e-01 8.9411764705882357e-01 9.4117647058823528e-01 + 8.0392156862745101e-01 8.9019607843137250e-01 9.3725490196078431e-01 + 7.9607843137254897e-01 8.8627450980392153e-01 9.3725490196078431e-01 + 7.8823529411764703e-01 8.8235294117647056e-01 9.3333333333333335e-01 + 7.8039215686274510e-01 8.7843137254901960e-01 9.3333333333333335e-01 + 7.7254901960784317e-01 8.7450980392156863e-01 9.2941176470588238e-01 + 7.6470588235294112e-01 8.7058823529411766e-01 9.2549019607843142e-01 + 7.5294117647058822e-01 8.6666666666666670e-01 9.2549019607843142e-01 + 7.4509803921568629e-01 8.6274509803921573e-01 9.2156862745098034e-01 + 7.3725490196078436e-01 8.5882352941176465e-01 9.2156862745098034e-01 + 7.2549019607843135e-01 8.5098039215686272e-01 9.1764705882352937e-01 + 7.1764705882352942e-01 8.4705882352941175e-01 9.1372549019607840e-01 + 7.0588235294117652e-01 8.4313725490196079e-01 9.0980392156862744e-01 + 6.9803921568627447e-01 8.3921568627450982e-01 9.0980392156862744e-01 + 6.8627450980392157e-01 8.3137254901960789e-01 9.0588235294117647e-01 + 6.7843137254901964e-01 8.2745098039215681e-01 9.0196078431372551e-01 + 6.6666666666666663e-01 8.2352941176470584e-01 8.9803921568627454e-01 + 6.5882352941176470e-01 8.1960784313725488e-01 8.9803921568627454e-01 + 6.4705882352941180e-01 8.1176470588235294e-01 8.9411764705882357e-01 + 6.3529411764705879e-01 8.0784313725490198e-01 8.9019607843137250e-01 + 6.2745098039215685e-01 8.0000000000000004e-01 8.8627450980392153e-01 + 6.1568627450980395e-01 7.9607843137254897e-01 8.8235294117647056e-01 + 6.0392156862745094e-01 7.8823529411764703e-01 8.8235294117647056e-01 + 5.9215686274509804e-01 7.8431372549019607e-01 8.7843137254901960e-01 + 5.8431372549019611e-01 7.8039215686274510e-01 8.7450980392156863e-01 + 5.7254901960784310e-01 7.7254901960784317e-01 8.7058823529411766e-01 + 5.6078431372549020e-01 7.6470588235294112e-01 8.6666666666666670e-01 + 5.4901960784313730e-01 7.6078431372549016e-01 8.6274509803921573e-01 + 5.3725490196078429e-01 7.5294117647058822e-01 8.5882352941176465e-01 + 5.2549019607843139e-01 7.4509803921568629e-01 8.5490196078431369e-01 + 5.0980392156862742e-01 7.3725490196078436e-01 8.5098039215686272e-01 + 4.9803921568627452e-01 7.2941176470588232e-01 8.4705882352941175e-01 + 4.8627450980392156e-01 7.2549019607843135e-01 8.4313725490196079e-01 + 4.7058823529411764e-01 7.1764705882352942e-01 8.3921568627450982e-01 + 4.5490196078431372e-01 7.0588235294117652e-01 8.3529411764705885e-01 + 4.4313725490196076e-01 6.9803921568627447e-01 8.3137254901960789e-01 + 4.2745098039215684e-01 6.9019607843137254e-01 8.2745098039215681e-01 + 4.1568627450980394e-01 6.8235294117647061e-01 8.1960784313725488e-01 + 4.0000000000000002e-01 6.7450980392156867e-01 8.1568627450980391e-01 + 3.8431372549019610e-01 6.6666666666666663e-01 8.1176470588235294e-01 + 3.7254901960784315e-01 6.5882352941176470e-01 8.0784313725490198e-01 + 3.5686274509803922e-01 6.4705882352941180e-01 8.0392156862745101e-01 + 3.4509803921568627e-01 6.3921568627450975e-01 8.0000000000000004e-01 + 3.3333333333333331e-01 6.3137254901960782e-01 7.9607843137254897e-01 + 3.2156862745098042e-01 6.2352941176470589e-01 7.8823529411764703e-01 + 3.0980392156862746e-01 6.1568627450980395e-01 7.8431372549019607e-01 + 2.9803921568627451e-01 6.0784313725490191e-01 7.8039215686274510e-01 + 2.9019607843137257e-01 5.9999999999999998e-01 7.7647058823529413e-01 + 2.7843137254901962e-01 5.9215686274509804e-01 7.7254901960784317e-01 + 2.7058823529411763e-01 5.8431372549019611e-01 7.6862745098039220e-01 + 2.6274509803921570e-01 5.7647058823529407e-01 7.6470588235294112e-01 + 2.5490196078431371e-01 5.6862745098039214e-01 7.6078431372549016e-01 + 2.4705882352941178e-01 5.6078431372549020e-01 7.5686274509803919e-01 + 2.4313725490196078e-01 5.5686274509803924e-01 7.5294117647058822e-01 + 2.3529411764705882e-01 5.4901960784313730e-01 7.4901960784313726e-01 + 2.3137254901960785e-01 5.4117647058823526e-01 7.4901960784313726e-01 + 2.2352941176470589e-01 5.3333333333333333e-01 7.4509803921568629e-01 + 2.1960784313725490e-01 5.2941176470588236e-01 7.4117647058823533e-01 + 2.1176470588235294e-01 5.2156862745098043e-01 7.3725490196078436e-01 + 2.0784313725490197e-01 5.1372549019607838e-01 7.3725490196078436e-01 + 2.0392156862745098e-01 5.0980392156862742e-01 7.3333333333333328e-01 + 1.9607843137254902e-01 5.0196078431372548e-01 7.2941176470588232e-01 + 1.9215686274509805e-01 4.9411764705882355e-01 7.2941176470588232e-01 + 1.8823529411764706e-01 4.9019607843137253e-01 7.2549019607843135e-01 + 1.8431372549019609e-01 4.8235294117647060e-01 7.2156862745098038e-01 + 1.8039215686274510e-01 4.7450980392156861e-01 7.1764705882352942e-01 + 1.7254901960784313e-01 4.7058823529411764e-01 7.1372549019607845e-01 + 1.6862745098039217e-01 4.6274509803921571e-01 7.1372549019607845e-01 + 1.6470588235294117e-01 4.5490196078431372e-01 7.0980392156862748e-01 + 1.6078431372549021e-01 4.5098039215686275e-01 7.0588235294117652e-01 + 1.5686274509803921e-01 4.4313725490196076e-01 7.0196078431372544e-01 + 1.5294117647058825e-01 4.3529411764705883e-01 6.9803921568627447e-01 + 1.4901960784313725e-01 4.2745098039215684e-01 6.9411764705882351e-01 + 1.4509803921568629e-01 4.2352941176470588e-01 6.9019607843137254e-01 + 1.3725490196078433e-01 4.1568627450980394e-01 6.8627450980392157e-01 + 1.3333333333333333e-01 4.0784313725490196e-01 6.7843137254901964e-01 + 1.2941176470588237e-01 4.0000000000000002e-01 6.7450980392156867e-01 + 1.2549019607843137e-01 3.9215686274509803e-01 6.7058823529411760e-01 + 1.2156862745098039e-01 3.8431372549019610e-01 6.6274509803921566e-01 + 1.1372549019607843e-01 3.7647058823529411e-01 6.5490196078431373e-01 + 1.0980392156862745e-01 3.6862745098039218e-01 6.4705882352941180e-01 + 1.0588235294117647e-01 3.6078431372549019e-01 6.3921568627450975e-01 + 1.0196078431372549e-01 3.5294117647058826e-01 6.3137254901960782e-01 + 9.8039215686274508e-02 3.4509803921568627e-01 6.1960784313725492e-01 + 9.4117647058823528e-02 3.3725490196078434e-01 6.1176470588235299e-01 + 8.6274509803921567e-02 3.2941176470588235e-01 5.9999999999999998e-01 + 8.2352941176470587e-02 3.2156862745098042e-01 5.8823529411764708e-01 + 7.8431372549019607e-02 3.1372549019607843e-01 5.7647058823529407e-01 + 7.4509803921568626e-02 3.0196078431372547e-01 5.6470588235294117e-01 + 7.0588235294117646e-02 2.9411764705882354e-01 5.5294117647058827e-01 + 6.6666666666666666e-02 2.8627450980392155e-01 5.4117647058823526e-01 + 6.2745098039215685e-02 2.7843137254901962e-01 5.2941176470588236e-01 + 5.8823529411764705e-02 2.7058823529411763e-01 5.1372549019607838e-01 + 5.0980392156862744e-02 2.5882352941176473e-01 5.0196078431372548e-01 + 4.7058823529411764e-02 2.5098039215686274e-01 4.8627450980392156e-01 + 4.3137254901960784e-02 2.4313725490196078e-01 4.7058823529411764e-01 + 3.9215686274509803e-02 2.3529411764705882e-01 4.5882352941176469e-01 + 3.5294117647058823e-02 2.2352941176470589e-01 4.4313725490196076e-01 + 3.1372549019607843e-02 2.1568627450980393e-01 4.2745098039215684e-01 + 2.7450980392156862e-02 2.0784313725490197e-01 4.1176470588235292e-01 + 2.3529411764705882e-02 1.9607843137254902e-01 3.9607843137254900e-01 + 1.9607843137254902e-02 1.8823529411764706e-01 3.8039215686274508e-01]); + case 'land' + % Land colours from ETOPO1 + Data=[ + 0.56410 0.20000 0.40000 0.00000 + 0.56920 0.20000 0.80000 0.40000 + 0.57440 0.73333 0.89412 0.57255 + 0.58970 1.00000 0.86275 0.72549 + 0.61540 0.95294 0.79216 0.53725 + 0.64100 0.90196 0.72157 0.34510 + 0.66670 0.85098 0.65098 0.15294 + 0.69230 0.65882 0.60392 0.12157 + 0.71790 0.64314 0.56471 0.09804 + 0.74360 0.63529 0.52549 0.07451 + 0.76920 0.62353 0.48235 0.05098 + 0.79490 0.61176 0.44314 0.02745 + 0.82050 0.60000 0.40000 0.00000 + 0.84620 0.63529 0.34902 0.34902 + 0.87180 0.69804 0.46275 0.46275 + 0.89740 0.71765 0.57647 0.57647 + 0.92310 0.76078 0.69020 0.69020 + 0.94870 0.80000 0.80000 0.80000 + 0.97440 0.89804 0.89804 0.89804 + 1.00000 1.00000 1.00000 1.00000]; + r=(Data(:,1)-Data(1,1))/(Data(end,1)-Data(1,1))*255; + Data=Data(:,2:4); + case 'water' + % Water colours from ETOPO1 + Data=[0.00000 0.03922 0.00000 0.47451 + 0.02560 0.10196 0.00000 0.53725 + 0.05130 0.14902 0.00000 0.59608 + 0.07690 0.10588 0.01176 0.65098 + 0.10260 0.06275 0.02353 0.70588 + 0.12820 0.01961 0.03529 0.75686 + 0.15380 0.00000 0.05490 0.79608 + 0.17950 0.00000 0.08627 0.82353 + 0.20510 0.00000 0.11765 0.84706 + 0.23080 0.00000 0.15294 0.87451 + 0.25640 0.04706 0.26667 0.90588 + 0.28210 0.10196 0.40000 0.94118 + 0.30770 0.07451 0.45882 0.95686 + 0.33330 0.05490 0.52157 0.97647 + 0.35900 0.08235 0.61961 0.98824 + 0.38460 0.11765 0.69804 1.00000 + 0.41030 0.16863 0.72941 1.00000 + 0.43590 0.21569 0.75686 1.00000 + 0.46150 0.25490 0.78431 1.00000 + 0.48720 0.30980 0.82353 1.00000 + 0.51280 0.36863 0.87451 1.00000 + 0.53850 0.54118 0.89020 1.00000 + 0.56410 0.73725 0.90196 1.00000]; + r=(Data(:,1)-Data(1,1))/(Data(end,1)-Data(1,1))*255; + Data=Data(:,2:4); + case 'gland' + % Land colours from ETOPO1 + Data=[ + 0.56410 0.20000 0.40000 0.00000 + 0.56920 0.20000 0.80000 0.40000 + 0.57440 0.73333 0.89412 0.57255 + 0.58970 1.00000 0.86275 0.72549 + 0.61540 0.95294 0.79216 0.53725 + 0.64100 0.90196 0.72157 0.34510 + 0.66670 0.85098 0.65098 0.15294 + 0.69230 0.65882 0.60392 0.12157 + 0.71790 0.64314 0.56471 0.09804 + 0.74360 0.63529 0.52549 0.07451 + 0.76920 0.62353 0.48235 0.05098 + 0.79490 0.61176 0.44314 0.02745 + 0.82050 0.60000 0.40000 0.00000 + 0.84620 0.63529 0.34902 0.34902 + 0.87180 0.69804 0.46275 0.46275 + 0.89740 0.71765 0.57647 0.57647 + 0.92310 0.76078 0.69020 0.69020 + 0.94870 0.80000 0.80000 0.80000 + 0.97440 0.89804 0.89804 0.89804 + 1.00000 1.00000 1.00000 1.00000]; + % Same colours as in 'land' but I stretch the + % green a little + r=[0:length(Data)-1]/(length(Data)-1)*255; + Data=Data(:,2:4); + case 'bland' + % Land colours from ETOPO1 + Data=[ + % 0.56410 0.20000 0.40000 0.00000 + % 0.56920 0.20000 0.80000 0.40000 + % 0.57440 0.73333 0.89412 0.57255 + 0.58970 1.00000 0.86275 0.72549 + 0.61540 0.95294 0.79216 0.53725 + 0.64100 0.90196 0.72157 0.34510 + 0.66670 0.85098 0.65098 0.15294 + 0.69230 0.65882 0.60392 0.12157 + 0.71790 0.64314 0.56471 0.09804 + 0.74360 0.63529 0.52549 0.07451 + 0.76920 0.62353 0.48235 0.05098 + 0.79490 0.61176 0.44314 0.02745 + 0.82050 0.60000 0.40000 0.00000 + 0.84620 0.63529 0.34902 0.34902 + 0.87180 0.69804 0.46275 0.46275 + 0.89740 0.71765 0.57647 0.57647 + 0.92310 0.76078 0.69020 0.69020 + 0.94870 0.80000 0.80000 0.80000 + 0.97440 0.89804 0.89804 0.89804 + 1.00000 1.00000 1.00000 1.00000]; + % Same colours as in 'land' but I remove the + % Green + r=[0:length(Data)-1]/(length(Data)-1)*255; + Data=Data(:,2:4); + case 'odv' + % Created from CET toolbox. + Data=[ 9.0101331e-01 0.0000000e+00 9.3251202e-01 + 8.9241369e-01 5.4084707e-02 9.3493161e-01 + 8.8374697e-01 9.2009868e-02 9.3733662e-01 + 8.7501086e-01 1.1940643e-01 9.3972123e-01 + 8.6621022e-01 1.4173077e-01 9.4208765e-01 + 8.5733587e-01 1.6085164e-01 9.4443514e-01 + 8.4839234e-01 1.7779733e-01 9.4676122e-01 + 8.3937643e-01 1.9304161e-01 9.4906833e-01 + 8.3028040e-01 2.0703619e-01 9.5135665e-01 + 8.2110339e-01 2.1996946e-01 9.5362260e-01 + 8.1184800e-01 2.3203951e-01 9.5586460e-01 + 8.0250437e-01 2.4334747e-01 9.5808151e-01 + 7.9308093e-01 2.5406699e-01 9.6027147e-01 + 7.8356163e-01 2.6421451e-01 9.6243395e-01 + 7.7394557e-01 2.7387323e-01 9.6457095e-01 + 7.6424053e-01 2.8309721e-01 9.6668309e-01 + 7.5443764e-01 2.9192664e-01 9.6876443e-01 + 7.4452229e-01 3.0039475e-01 9.7081305e-01 + 7.3450848e-01 3.0856348e-01 9.7283330e-01 + 7.2437830e-01 3.1642474e-01 9.7481118e-01 + 7.1413293e-01 3.2400124e-01 9.7675955e-01 + 7.0377315e-01 3.3133238e-01 9.7866788e-01 + 6.9328911e-01 3.3844029e-01 9.8054235e-01 + 6.8267129e-01 3.4532943e-01 9.8237525e-01 + 6.7192363e-01 3.5200255e-01 9.8416286e-01 + 6.6103315e-01 3.5849315e-01 9.8590542e-01 + 6.5000382e-01 3.6480311e-01 9.8760208e-01 + 6.3881994e-01 3.7093737e-01 9.8924507e-01 + 6.2748126e-01 3.7692778e-01 9.9083128e-01 + 6.1597716e-01 3.8274509e-01 9.9236641e-01 + 6.0430713e-01 3.8842528e-01 9.9384206e-01 + 5.9245905e-01 3.9395999e-01 9.9524582e-01 + 5.8041851e-01 3.9936053e-01 9.9658429e-01 + 5.6818292e-01 4.0464332e-01 9.9785650e-01 + 5.5574776e-01 4.0981228e-01 9.9904764e-01 + 5.4311794e-01 4.1484604e-01 1.0000000e+00 + 5.3025652e-01 4.1977665e-01 1.0000000e+00 + 5.1717467e-01 4.2459106e-01 1.0000000e+00 + 5.0384831e-01 4.2929918e-01 1.0000000e+00 + 4.9028115e-01 4.3389560e-01 1.0000000e+00 + 4.7646435e-01 4.3840653e-01 1.0000000e+00 + 4.6239168e-01 4.4281244e-01 1.0000000e+00 + 4.4807735e-01 4.4710328e-01 1.0000000e+00 + 4.3348133e-01 4.5131439e-01 1.0000000e+00 + 4.1882644e-01 4.5541169e-01 1.0000000e+00 + 4.0463168e-01 4.5935111e-01 1.0000000e+00 + 3.9127493e-01 4.6308440e-01 1.0000000e+00 + 3.7887635e-01 4.6663821e-01 1.0000000e+00 + 3.6754491e-01 4.6997659e-01 9.9710824e-01 + 3.5727105e-01 4.7310156e-01 9.9361634e-01 + 3.4806754e-01 4.7605687e-01 9.8960956e-01 + 3.3991294e-01 4.7882200e-01 9.8516720e-01 + 3.3278841e-01 4.8142044e-01 9.8033564e-01 + 3.2657245e-01 4.8386769e-01 9.7517562e-01 + 3.2131863e-01 4.8617771e-01 9.6972157e-01 + 3.1692286e-01 4.8836273e-01 9.6400671e-01 + 3.1327820e-01 4.9042788e-01 9.5808298e-01 + 3.1036518e-01 4.9237894e-01 9.5195268e-01 + 3.0812518e-01 4.9424286e-01 9.4564700e-01 + 3.0652684e-01 4.9600072e-01 9.3918421e-01 + 3.0545194e-01 4.9770307e-01 9.3258337e-01 + 3.0485773e-01 4.9930273e-01 9.2586855e-01 + 3.0471500e-01 5.0085383e-01 9.1903664e-01 + 3.0497614e-01 5.0233287e-01 9.1211284e-01 + 3.0559984e-01 5.0375514e-01 9.0509893e-01 + 3.0652667e-01 5.0512067e-01 8.9799743e-01 + 3.0771336e-01 5.0643775e-01 8.9082591e-01 + 3.0918805e-01 5.0771753e-01 8.8359036e-01 + 3.1084258e-01 5.0894669e-01 8.7628822e-01 + 3.1265990e-01 5.1012895e-01 8.6893964e-01 + 3.1464971e-01 5.1127898e-01 8.6153178e-01 + 3.1677717e-01 5.1239777e-01 8.5407999e-01 + 3.1899621e-01 5.1348864e-01 8.4658877e-01 + 3.2129859e-01 5.1454679e-01 8.3906246e-01 + 3.2370068e-01 5.1556074e-01 8.3149691e-01 + 3.2615709e-01 5.1656269e-01 8.2388686e-01 + 3.2867278e-01 5.1754427e-01 8.1625836e-01 + 3.3117878e-01 5.1849579e-01 8.0859723e-01 + 3.3372872e-01 5.1942240e-01 8.0091115e-01 + 3.3627834e-01 5.2032367e-01 7.9320222e-01 + 3.3885910e-01 5.2121527e-01 7.8546403e-01 + 3.4141138e-01 5.2207962e-01 7.7770923e-01 + 3.4392756e-01 5.2294489e-01 7.6993203e-01 + 3.4645715e-01 5.2377972e-01 7.6213677e-01 + 3.4896939e-01 5.2459818e-01 7.5432975e-01 + 3.5143015e-01 5.2540630e-01 7.4649947e-01 + 3.5384400e-01 5.2620510e-01 7.3866259e-01 + 3.5626705e-01 5.2698442e-01 7.3080018e-01 + 3.5861057e-01 5.2774386e-01 7.2292779e-01 + 3.6090556e-01 5.2850832e-01 7.1504566e-01 + 3.6318916e-01 5.2925382e-01 7.0715015e-01 + 3.6541282e-01 5.2998346e-01 6.9923396e-01 + 3.6755212e-01 5.3070830e-01 6.9133423e-01 + 3.6961736e-01 5.3143077e-01 6.8342411e-01 + 3.7153984e-01 5.3216045e-01 6.7551926e-01 + 3.7333964e-01 5.3289069e-01 6.6762844e-01 + 3.7498875e-01 5.3361944e-01 6.5974393e-01 + 3.7651860e-01 5.3436635e-01 6.5187458e-01 + 3.7790211e-01 5.3511255e-01 6.4400546e-01 + 3.7916289e-01 5.3586250e-01 6.3616246e-01 + 3.8030058e-01 5.3663010e-01 6.2832375e-01 + 3.8132032e-01 5.3739134e-01 6.2049557e-01 + 3.8220248e-01 5.3815863e-01 6.1266534e-01 + 3.8298164e-01 5.3892674e-01 6.0486256e-01 + 3.8363602e-01 5.3969563e-01 5.9706617e-01 + 3.8417043e-01 5.4048220e-01 5.8926622e-01 + 3.8459090e-01 5.4126271e-01 5.8148982e-01 + 3.8489570e-01 5.4205784e-01 5.7372243e-01 + 3.8508983e-01 5.4286004e-01 5.6595990e-01 + 3.8517497e-01 5.4365697e-01 5.5820324e-01 + 3.8514825e-01 5.4446264e-01 5.5046654e-01 + 3.8500591e-01 5.4527490e-01 5.4273583e-01 + 3.8475369e-01 5.4609572e-01 5.3500496e-01 + 3.8439432e-01 5.4691158e-01 5.2728974e-01 + 3.8392969e-01 5.4773483e-01 5.1957424e-01 + 3.8335370e-01 5.4857211e-01 5.1186858e-01 + 3.8264961e-01 5.4940346e-01 5.0418316e-01 + 3.8184174e-01 5.5024295e-01 4.9647988e-01 + 3.8093456e-01 5.5108859e-01 4.8880378e-01 + 3.7989709e-01 5.5194307e-01 4.8112245e-01 + 3.7875488e-01 5.5279313e-01 4.7344838e-01 + 3.7750149e-01 5.5365179e-01 4.6578241e-01 + 3.7613365e-01 5.5452404e-01 4.5812639e-01 + 3.7463906e-01 5.5538969e-01 4.5047471e-01 + 3.7301856e-01 5.5626729e-01 4.4282654e-01 + 3.7128174e-01 5.5716409e-01 4.3518225e-01 + 3.6943191e-01 5.5804236e-01 4.2753741e-01 + 3.6744351e-01 5.5893816e-01 4.1989061e-01 + 3.6533681e-01 5.5984781e-01 4.1225487e-01 + 3.6309063e-01 5.6075086e-01 4.0460539e-01 + 3.6070294e-01 5.6167024e-01 3.9696864e-01 + 3.5819517e-01 5.6259588e-01 3.8934301e-01 + 3.5553881e-01 5.6352351e-01 3.8170805e-01 + 3.5271499e-01 5.6445380e-01 3.7408098e-01 + 3.4974311e-01 5.6539030e-01 3.6644835e-01 + 3.4660653e-01 5.6634992e-01 3.5879830e-01 + 3.4330675e-01 5.6731182e-01 3.5117765e-01 + 3.3982229e-01 5.6827515e-01 3.4353893e-01 + 3.3613030e-01 5.6925183e-01 3.3590528e-01 + 3.3226927e-01 5.7023982e-01 3.2827190e-01 + 3.2817437e-01 5.7123976e-01 3.2064919e-01 + 3.2386167e-01 5.7225439e-01 3.1300205e-01 + 3.1930992e-01 5.7327706e-01 3.0538599e-01 + 3.1448277e-01 5.7430284e-01 2.9775044e-01 + 3.0940512e-01 5.7535700e-01 2.9013069e-01 + 3.0397213e-01 5.7642766e-01 2.8255045e-01 + 2.9821634e-01 5.7749511e-01 2.7494949e-01 + 2.9213635e-01 5.7858904e-01 2.6736545e-01 + 2.8585508e-01 5.7968241e-01 2.5973929e-01 + 2.7979429e-01 5.8071733e-01 2.5182584e-01 + 2.7409306e-01 5.8169092e-01 2.4353615e-01 + 2.6895355e-01 5.8258780e-01 2.3488952e-01 + 2.6452586e-01 5.8339123e-01 2.2571999e-01 + 2.6115049e-01 5.8407359e-01 2.1600397e-01 + 2.5921386e-01 5.8459763e-01 2.0562062e-01 + 2.5917881e-01 5.8491193e-01 1.9457571e-01 + 2.6172691e-01 5.8493530e-01 1.8281914e-01 + 2.6736292e-01 5.8459009e-01 1.7079381e-01 + 2.7605556e-01 5.8384546e-01 1.5913201e-01 + 2.8684229e-01 5.8275563e-01 1.4851063e-01 + 2.9881924e-01 5.8141442e-01 1.3929985e-01 + 3.1118650e-01 5.7990916e-01 1.3150590e-01 + 3.2354119e-01 5.7827384e-01 1.2482607e-01 + 3.3571076e-01 5.7657878e-01 1.1919225e-01 + 3.4760451e-01 5.7479693e-01 1.1436156e-01 + 3.5917972e-01 5.7298881e-01 1.1035678e-01 + 3.7046210e-01 5.7112054e-01 1.0690929e-01 + 3.8146525e-01 5.6922129e-01 1.0397365e-01 + 3.9217543e-01 5.6729630e-01 1.0155055e-01 + 4.0262874e-01 5.6532047e-01 9.9563720e-02 + 4.1285471e-01 5.6333643e-01 9.8014331e-02 + 4.2283397e-01 5.6130090e-01 9.6695447e-02 + 4.3264027e-01 5.5924194e-01 9.5762755e-02 + 4.4224318e-01 5.5716236e-01 9.4951662e-02 + 4.5166986e-01 5.5503657e-01 9.4080622e-02 + 4.6093550e-01 5.5288878e-01 9.3190838e-02 + 4.7006969e-01 5.5071469e-01 9.2394545e-02 + 4.7905191e-01 5.4851288e-01 9.1613212e-02 + 4.8791547e-01 5.4627320e-01 9.0767770e-02 + 4.9663686e-01 5.4399494e-01 8.9948701e-02 + 5.0525765e-01 5.4168472e-01 8.9142595e-02 + 5.1377978e-01 5.3935013e-01 8.8344290e-02 + 5.2217703e-01 5.3698984e-01 8.7579467e-02 + 5.3049564e-01 5.3457717e-01 8.6781980e-02 + 5.3871960e-01 5.3213942e-01 8.5936085e-02 + 5.4684834e-01 5.2966356e-01 8.5197765e-02 + 5.5489406e-01 5.2715147e-01 8.4499111e-02 + 5.6286931e-01 5.2459702e-01 8.3736580e-02 + 5.7075371e-01 5.2200153e-01 8.2965076e-02 + 5.7857766e-01 5.1938381e-01 8.2294444e-02 + 5.8633451e-01 5.1671589e-01 8.1575183e-02 + 5.9402116e-01 5.1401457e-01 8.0830769e-02 + 6.0164481e-01 5.1125679e-01 8.0119227e-02 + 6.0921718e-01 5.0847758e-01 7.9421412e-02 + 6.1672372e-01 5.0562705e-01 7.8739648e-02 + 6.2417702e-01 5.0275308e-01 7.8075667e-02 + 6.3157495e-01 4.9982760e-01 7.7428325e-02 + 6.3892277e-01 4.9686181e-01 7.6797687e-02 + 6.4622234e-01 4.9384916e-01 7.6184872e-02 + 6.5347472e-01 4.9079302e-01 7.5589796e-02 + 6.6068297e-01 4.8767582e-01 7.5007376e-02 + 6.6785657e-01 4.8449686e-01 7.4444887e-02 + 6.7497536e-01 4.8128060e-01 7.3917039e-02 + 6.8205540e-01 4.7801106e-01 7.3382464e-02 + 6.8910997e-01 4.7469164e-01 7.2799197e-02 + 6.9611556e-01 4.7130644e-01 7.2248466e-02 + 7.0308682e-01 4.6785815e-01 7.1781405e-02 + 7.1002283e-01 4.6436799e-01 7.1317804e-02 + 7.1692989e-01 4.6078972e-01 7.0812391e-02 + 7.2379432e-01 4.5716541e-01 7.0334205e-02 + 7.3063604e-01 4.5347355e-01 6.9928066e-02 + 7.3744490e-01 4.4971842e-01 6.9550523e-02 + 7.4422586e-01 4.4588089e-01 6.9158288e-02 + 7.5098360e-01 4.4199555e-01 6.8753605e-02 + 7.5770386e-01 4.3801889e-01 6.8363033e-02 + 7.6440159e-01 4.3395308e-01 6.8000452e-02 + 7.7107741e-01 4.2983143e-01 6.7662807e-02 + 7.7772504e-01 4.2561806e-01 6.7345763e-02 + 7.8435064e-01 4.2131316e-01 6.7047765e-02 + 7.9094561e-01 4.1693930e-01 6.6769501e-02 + 7.9752256e-01 4.1246414e-01 6.6511686e-02 + 8.0408218e-01 4.0788143e-01 6.6274748e-02 + 8.1061283e-01 4.0321333e-01 6.6058803e-02 + 8.1712938e-01 3.9843601e-01 6.5863871e-02 + 8.2362256e-01 3.9354671e-01 6.5689946e-02 + 8.3010058e-01 3.8855623e-01 6.5537030e-02 + 8.3655552e-01 3.8344453e-01 6.5405124e-02 + 8.4299328e-01 3.7819900e-01 6.5294161e-02 + 8.4941547e-01 3.7282716e-01 6.5204178e-02 + 8.5581779e-01 3.6732198e-01 6.5135120e-02 + 8.6220650e-01 3.6168376e-01 6.5087154e-02 + 8.6857747e-01 3.5588751e-01 6.5060182e-02 + 8.7492597e-01 3.4992373e-01 6.5054456e-02 + 8.8126652e-01 3.4378373e-01 6.5069774e-02 + 8.8758708e-01 3.3748220e-01 6.5106460e-02 + 8.9389887e-01 3.3096597e-01 6.5164196e-02 + 9.0019487e-01 3.2426128e-01 6.5243333e-02 + 9.0647723e-01 3.1733910e-01 6.5343657e-02 + 9.1274449e-01 3.1018523e-01 6.5465418e-02 + 9.1899599e-01 3.0274206e-01 6.5608630e-02 + 9.2524045e-01 2.9504892e-01 6.5773425e-02 + 9.3147122e-01 2.8704671e-01 6.5959943e-02 + 9.3769166e-01 2.7873707e-01 6.6168130e-02 + 9.4389831e-01 2.7005145e-01 6.6398279e-02 + 9.5009275e-01 2.6094683e-01 6.6650135e-02 + 9.5627950e-01 2.5141834e-01 6.6923773e-02 + 9.6245047e-01 2.4136103e-01 6.7218475e-02 + 9.6861585e-01 2.3072982e-01 6.7533548e-02 + 9.7476660e-01 2.1945144e-01 6.7869417e-02 + 9.8091309e-01 2.0738932e-01 6.8229718e-02 + 9.8705021e-01 1.9442270e-01 6.8619747e-02 + 9.9317979e-01 1.8027042e-01 6.9032328e-02 + 9.9929581e-01 1.6476261e-01 6.9441308e-02 + 1.0000000e+00 1.4745190e-01 6.9829429e-02 + 1.0000000e+00 1.2757129e-01 7.0234818e-02 + 1.0000000e+00 1.0393299e-01 7.0711225e-02]; + + end + + + +end + +function colmap_demo + +clf; +axp=[.1 .1 .2 .08]; +dx=[.29 0 0 0]; +dy=[0 .19 0 0]; + +examples={... + 0,4,'m_colmap(''jet'',256)', {'Perceptually uniform jet replacement','with diverging luminance'} + 1,4,'m_colmap(''blue'',256)', 'Good for bathymetry' + 2,4,'m_colmap(''land'',256)', 'Land from coastal wetlands to mountains' + 0,3,'m_colmap(''diverging'',256)',{'Currents, echo-sounder images','diverging luminance with a ''zero'''} + 1,3,'m_colmap(''water'',256)', 'Another bathymetry map' + 2,3,'m_colmap(''gland'',256)', 'Land with more green' + 0,2,'m_colmap(''odv'',256)', 'Isoluminant (add your own shading)' + 1,2,'m_colmap(''green'',256)', 'Chlorophyll? Land?' + 2,2,'m_colmap(''bland'',256)', 'Land without green' + 0,0,'m_colmap(''jet'',''step'',10)',{'Banded continuous map (256 colours)','sort of like contouring'} + 1,0,'m_colmap(''jet'',10)', 'A few discrete steps (10 colours)' + 2,0,'[m_colmap(''blues'',64);m_colmap(''gland'',128)]',{'Complex water + land example','must use ''caxis'' to get coastline correct'} + }; + + +for k=1:size(examples,1) + ax(k)=axes('pos',axp+dx*examples{k,1}+dy*examples{k,2}); + imagesc(1:256); + set(gca,'ytick',[],'xtick',[]);%[1 64:64:256]); + eval(['colormap(ax(k),' examples{k,3} ');']); + title([char('a'+k-1) ') ' examples{k,3}],'interp','none'); + xlabel(examples{k,4}); +end + +% print -dpng ./doc/exColmaps +end + + + + + + + + + + + + + + diff --git a/functions/plotting/m_coord.m b/functions/plotting/m_coord.m new file mode 100644 index 0000000..d41f3c2 --- /dev/null +++ b/functions/plotting/m_coord.m @@ -0,0 +1,60 @@ +function coordsys=m_coord(coordsys) +% M_COORD Initializes the coordinate system for varous conversions. +% +% M_COORD('set') tells you the current coordinate system +% M_COORD('get') gives you the current possibilities +% M_COORD(SYSTEM) sets the coordinate system to SYSTEM. +% +% Currently the available coordinate systems are: +% 'geographic' (usual lat/long) +% 'geomagnetic' (referenced to magnetic poles) + +% Rich Pawlowicz (rich@ocgy.ubc.ca) nOV/2001 +% +% This software is provided "as is" without warranty of any kind. But +% it's mine, so you can't sell it. + + +global MAP_COORDS + +if nargin==0, coordsys='usage'; end + +coordsys=lower(coordsys); + +coords=mc_coords('name'); + +switch coordsys + + case 'get' + disp(' '); + disp('Available coordinate systems are:'); + for k=1:length(coords.name) + disp([' ' coords.name{k}]); + end + + case 'set' + if isempty(MAP_COORDS) + disp('No coordinate system initialized'); + m_coord('usage'); + else + if nargout==0 + disp(MAP_COORDS.name); + else + coordsys=MAP_COORDS; + end + end + + case 'usage' + disp(' '); + disp('Possible calling options are:'); + disp(' ''usage'' - this list'); + disp(' ''set'' - list of coordinate systems'); + disp(' ''get'' - get current coordinate (if defined)'); + disp(' ''system'' - initialize coordinate system\n'); + + otherwise + k=strcmp(coordsys,lower(coords.name)); + MAP_COORDS=mc_coords('parameters',coords.name{k}); + +end + % Check to see if a non-lat/long coordinate system is being used. diff --git a/functions/plotting/m_grid.m b/functions/plotting/m_grid.m new file mode 100644 index 0000000..7b019f2 --- /dev/null +++ b/functions/plotting/m_grid.m @@ -0,0 +1,960 @@ +function m_grid(varargin) +% M_GRID make a grid on a map. +% M_GRID('parameter','value',...) with any number (or no) +% optional parameters is used to draw a lat/long grid for a +% previously initialized map projection. +% +% The optional parameters allow the user +% to control the look of the grid. These parameters are listed +% by M_GRID('get'), with default parameters in M_GRID('set'); +% +% see also M_PROJ + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 +% +% This software is provided "as is" without warranty of any kind. But +% it's mine, so you can't sell it. +% +% 19/6/97 - set visibility of titles and so forth to 'on' (they +% default to 'off' when axes visibility is turned off) +% 2/11/97 - for M5.1, the old way of making the patch at the bottom (i.e. +% by rearranging the axes children) instead causes matlab to lose +% track of titles. Try a different fix. +% 11/01/98 - Added way of making longitude lines cut off to prevent crowding near poles (you have +% to specify a vector for allowabale latitudes for this to work). +% 16/02/98 - Made a little fudge to allow the user to fully specify grid location +% without getting the edge points. It doesn't quite work if only *one* edge +% point is desired....but I hope it will be OK that way. +% 19/02/98 - PC-users complain about layers getting out of order! Their fault for using +% such an awful OS...however (with help from Eric Firing) I think I have +% a fix. +% 7/04/98 - Another fix to grid locations to not automatically add edge points +% (as requested by EF) +% 7/05/98 - Added 'fancy' outline box. +% 14/11/98 - Changed tag names from m_* to m_grid_*. +% 11/07/99 - Apparently fontname changing didn't work (thanks to Dave McCollum) +% 28/04/04 - Changed m_grid_color code so it works right under unix; old +% way retained for windows (ugh). +% 16/10/05 - Kirk Ireson discovered that the way to fix those annoying 'cut-throughs' +% in fancy_box was to add a 'large' zdata...so I've adapted his fix in +% fancybox and fancybox2. +% 21/11/06 - added 'backcolor' +% 16/4/07 - sorted ticklabels when user-specified (prevents an odd problem near in +% azimuthal projections). +% 4/DEc/11 - isstr to ischar +% 7/Dec/11 - cd /ocean/rich/home/matlab 3.2.3 compatibility +% 8/Sep/13 - added 'tickstyle' parameter +% 27/Sep/13 - matlab 2013b out, includes graphic bug. Workaround provided by +% Corinne Bassin. +% 10/Jul/14 - in 2014a BITMAX starts not to be used, changed to FLINTMAX... +% 13/Nov/14 - 2014b graphics changes are biting; a number of version-dependent +% fixes implemented. +% 17/Nov/17 - All kinds of "new graphics" changes in the background patch +% 27/Nov/17 - made a specialized fix for xaxis tick directions in Robinson and +% Sinusoidal projections. (problem noted by J. Tsoa, but I didn't like +% the way he fixed it. Also improved consistency of "lake" +% handling with non-white background colours, and more Octave +% compatibility. +% 8/Feb/18 - changed ^o to char(176) in labels. (thanks Brian Dushaw) +% 21/06/2018 added axes option to specify the axes to draw the grid on (instead of +% gca) - thanks to Yoann Ladroit. +% 23/12/2018 - aesthetic improvement to mollweide projection. + +% +% Note that much of the work in generating line data +% is done by calls to the individual projections - +% most of M_GRID is concerned with the mechanics of plotting + + +% These structures are initialized by m_proj() + +global MAP_PROJECTION MAP_VAR_LIST + +% Have to have initialized a map first + +if isempty(MAP_PROJECTION) + disp('No Map Projection initialized - call M_PROJ first!'); + return; +end + + + +% Otherwise we are drawing a grid! + +% Set current projection to geographic +Currentmap=m_coord('set'); +m_coord(MAP_PROJECTION.coordsystem.name); + +% Default parameters for grid + +ax_idx=find(strcmpi('axes',varargin)); +if isempty(ax_idx) + ax=gca; +else + ax=varargin{ax_idx+1}; +end + + + +xtick=6; +ytick=6; +xlabels=NaN; +ylabels=NaN; +gcolor='k'; +ggridcolor=[]; +gbackcolor='w'; %%get(gcf,'color'); +glinestyle=':'; +glinewidth=get(ax,'linewidth'); +gbox='on'; +gfontsize=get(ax,'fontsize'); +gfontname=get(ax,'fontname'); +gxaxisloc=get(ax,'xaxislocation'); +gyaxisloc=get(ax,'yaxislocation'); +gtickdir=get(ax,'tickdir'); +gticklen=get(ax,'ticklength'); gticklen=gticklen(1); +gxticklabeldir='middle'; +gyticklabeldir='end'; +gtickstyle='dm'; + +dpatch=5; % interpolation factor for fancy grids + +% Parse parameter list for options. I really should do some +% error checking here, but... + +k=1; +while k<=length(varargin) + switch lower(varargin{k}(1:3)) + case 'box' + gbox=varargin{k+1}; + case 'xti' + if length(varargin{k})==5 + xtick=sort(varargin{k+1}); % Added 'sort' here for people who put things in + else % a random order near poles + xlabels=varargin{k+1}; + end + case 'yti' + if length(varargin{k})==5 + ytick=sort(varargin{k+1}); + else + ylabels=varargin{k+1}; + end + case 'xla' + gxticklabeldir=varargin{k+1}; + case 'yla' + gyticklabeldir=varargin{k+1}; + case 'col' + gcolor=varargin{k+1}; + case 'gri' + ggridcolor=varargin{k+1}; + case 'bac' + gbackcolor=varargin{k+1}; + case 'lin' + switch lower(varargin{k}(1:5)) + case 'linew' + glinewidth=varargin{k+1}; + case 'lines' + glinestyle=varargin{k+1}; + end + case 'fon' + switch lower(varargin{k}(1:5)) + case 'fonts' + gfontsize=varargin{k+1}; + case 'fontn' + gfontname=varargin{k+1}; + end + case 'xax' + gxaxisloc=varargin{k+1}; + case 'yax' + gyaxisloc=varargin{k+1}; + case 'tic' + switch lower(varargin{k}(1:5)) + case 'tickl' + gticklen=varargin{k+1}; + case 'tickd' + gtickdir=varargin{k+1}; + case 'ticks' + gtickstyle=varargin{k+1}; + end + case {'get','usa'} + disp(' ''axes'',( gca | axis handle)'); + disp(' ''box'',( ''on'' | ''fancy'' | ''off'' )'); + disp(' ''xtick'',( num | [value1 value2 ...])'); + disp(' ''ytick'',( num | [value1 value2 ...])'); + disp(' ''xticklabels'',[label1;label2 ...]'); + disp(' ''yticklabels'',[label1;label2 ...]'); + disp(' ''xlabeldir'', ( ''middle'' | ''end'' )'); + disp(' ''ylabeldir'', ( ''end'' | ''middle'' )'); + disp(' ''ticklength'',value'); + disp(' ''tickdir'',( ''in'' | ''out'' )'); + disp(' ''tickstyle'',(''dm'' | ''da'' | ''dd'' )'); % deg-min or abbreviated deg-min or decimal-deg + disp(' ''color'',colorspec'); + disp(' ''gridcolor'',colorspec'); + disp(' ''backgroundcolor'',colorspec'); + disp(' ''linewidth'', value'); + disp(' ''linestyle'', ( linespec | ''none'' )'); + disp(' ''fontsize'',value'); + disp(' ''fontname'',name'); + disp(' ''XaxisLocation'',( ''bottom'' | ''middle'' | ''top'' ) '); + disp(' ''YaxisLocation'',( ''left'' | ''middle'' | ''right'' ) '); + return; + case 'set' + disp([' axes = ' ax]); + disp([' box = ' gbox]); + disp([' xtick = ' num2str(xtick)]); + disp([' ytick = ' num2str(ytick)]); + disp([' ticklength = ' num2str(gticklen)]); + disp([' tickdir = ' gtickdir]); + disp([' tickstyle = ' gtickstyle]); + disp([' xlabeldir = ' gxticklabeldir]); + disp([' ylabeldir = ' gyticklabeldir]); + disp([' color = ' gcolor]); + disp([' gridcolor = ' gcolor]); + disp([' backgroundcolor - ' gbackcolor]); + disp([' linewidth = ' num2str(glinewidth)]); + disp([' linestyle = ' glinestyle]); + disp([' fontsize = ' num2str(gfontsize)]); + disp([' fontname = ' gfontname]); + disp([' XaxisLocation = ' gxaxisloc]); + disp([' YaxisLocation = ' gyaxisloc]); + return; + end + k=k+2; +end + +if isempty(ggridcolor) + ggridcolor=gcolor; +end + + +if strcmp(gbox,'fancy') + if strcmp(MAP_VAR_LIST.rectbox,'on') || strcmp(MAP_VAR_LIST.rectbox,'circle') + gbox='on'; + warning([' No fancy outline with ''rectbox'' set to ''' MAP_VAR_LIST.rectbox '''']); + end +end + +[X,Y]=feval(MAP_PROJECTION.routine,'box'); + +% These color parts make Octave fail so I moved them here, otherwise +% they should be before this if block + +% If there are lakes around, make them the backgroundcolor.. +hh=get(ax,'children'); +hh_tags=get(hh,'tag'); +if length(hh)==1, hh_tags={hh_tags}; end +for i=1:length(hh_tags) + if ~isempty(strfind(hh_tags{i},'_lake')) && strcmp(get(hh(i),'type'),'patch') + set(hh(i),'facecolor',gbackcolor); + end +end + +% Set the axes colour so lakes get coloured right (if a coastline added +% next) + +set(ax,'color',gbackcolor'); + + +if MAP_PROJECTION.IsOctave + + + % Octave handling here all provided by Jamie Tsao + + % Note that both gnuplot and fltk doesn't really work well with the z-axis, + % so here we simply ignore it. + + % The tag is important for M_COAST to catch the correct underlying color. + % As a result, though, M_COAST should be called after M_GRID. + + + % IN 2018, this workaround no longer needed. + if 0,%strcmp(graphics_toolkit(), 'gnuplot') + % Unfortunately, gnuplot also has a bug with using patch, where a linestyle + % of 'none' would cause it to barf. This bug has been reported since 2013, + % but apparently it is still not fixed. It may have something to do with + % how Octave interacts with the underlying gnuplot backend. + + % On the other hand, this means I can set the linewidth to 0 and it should + % work exactly as intended. If there is no problems, then I can refactor + % this part, assuming ftlk doesn't barf on a zero linewidth. + patch('xdata', X(:), 'ydata', Y(:), 'facecolor', gbackcolor, ... + 'edgecolor', 'k', 'linewidth', 0, 'tag', 'm_grid_color','parent',ax); + else + + patch('xdata', X(:), 'ydata', Y(:), 'facecolor', gbackcolor, ... + 'edgecolor', 'k', 'linestyle', 'none', 'tag', 'm_grid_color','parent',ax); + end + + % Now I set it at the bottom of the children list so it gets drawn first + % (i.e. doesn't cover anything) + + % A bug in Octave 3.8.1 makes set(ax, 'children', -) insert the new + % permutation before the old one instead of replacing it. This only occurs + % when the ShowHiddenHandles flag is set to on instead of off. Although fltk + % is not affected, gnuplot still is. Combined with fltk's lack of support for + % unicode and hence the degree sign, this is still important. Furthermore, + % this bug causes delete() to function incorrectly. + + show = get(0, 'ShowHiddenHandles'); + set(0, 'ShowHiddenHandles', 'on'); + + hh = get(ax,'children'); + htags = get(hh,'tag'); + k = strcmp('m_grid_color', htags); + hht = hh; + hh(k) = []; + hh = [hh;hht(k)]; + + % Continuing on the bug, there is no particular need for why this needs to be + % placed under even hidden handles. Even so, as a workaround, we can grab all + % hidden handles, set them to be visible, turn off flag, reorder, then set + % them back as hidden, as noted below. + + hht_inv = strcmp('off', get(hht, 'HandleVisibility')); + set(hht(hht_inv), 'HandleVisibility', 'on'); + set(0, 'ShowHiddenHandles', 'off'); + set(ax,'children',hh); + set(hht(hht_inv), 'HandleVisibility', 'off'); + + set(0, 'ShowHiddenHandles', show); + + % Patch clipping does not work correctly in Octave, so I have to + % manually set the Z-limits to that fancy boxes (with 3D patches) + % works correctly. + zlim([-1 MAP_PROJECTION.LARGVAL]); +else % For MATLAB + + + + % This is a very problematic part of the code. It turns out the the interaction between + % PATCH objects and CONTOURF objects does not work correctly in the Painters renderer - + % this is true in all versions up to 7.7 at least. Patches with large negative Z just + % don't get drawn under contourgroup patches. + % + % There are several possible workarounds: + % + % 1) Make sure you use the 'v6' option in contourf calls (see m_contourf.m to see + % how I have tried to do that for some versions of matlab) + % - problem: the 'v6' option is going away soon, also you may want the + % contourgroup object that the v6 option destroys. + % + % 2) Change the renderer to something else: + % set(gcf,'renderer','opengl') or + % set(gcf,'renderer','zbuffer') + % - problem: These other renderers are not available on all systems, they may also + % give less-precise results. + % + % 3) Use the painters renderer, but reorder the children so that the patch is at the + % bottom of the list (painters cares about child order) + % - problem: sometimes the child order is rearranged if you click on the figure, + % also (at least in some versions of matlab) this causes labels to + % disappear. + % + % With version 7.4 onwards I have discovered that reordering the children apparently + % is Mathworks-blessed (c.f. the UISTACK function). So I am going to try to implement + % the latter as a default. + % + % Now, putting in a white background works under linux (at least) and + % NOT under windows...I don't know about macs. + % + % This broke with matlab 2014b - but eventually (I sent in a "bug + % report" and found it was a "feature") I learned of the 'sortmethod' + % tag, which made it work again - as long as I didn't use negative z + % values in the patch command. I don't know WHY that is... + + if ~MAP_PROJECTION.newgraphics + patch('xdata',X(:),'ydata',Y(:),'zdata',-MAP_PROJECTION.LARGVAL*ones(size(X(:))),'facecolor',gbackcolor,... + 'edgecolor','k','linestyle','none','tag','m_grid_color','Parent',ax); + % Now I set it at the bottom of the children list so it gets drawn first (i.e. doesn't + % cover anything) + show=get(0, 'ShowHiddenHandles'); + set(0, 'ShowHiddenHandles', 'on'); + hh=get(ax,'children'); + htags = get(hh,'tag'); + k = strcmp('m_grid_color',htags); + hht = hh; + hh(k) = []; + hh = [hh;hht(k)]; + set(ax,'children',hh); + set(0, 'ShowHiddenHandles', show); + + else % after 2014b + + patch('xdata',X(:),'ydata',Y(:),'zdata',-MAP_PROJECTION.LARGVAL*ones(size(X(:))),'facecolor',gbackcolor,... + 'edgecolor','k','linestyle','none','tag','m_grid_color','parent',ax); +% patch('xdata',X(:),'ydata',Y(:),'facecolor',gbackcolor,... +% 'edgecolor','k','linestyle','none','tag','m_grid_color'); + set(ax,'sortmethod','childorder'); + uistack(findobj(ax,'tag','m_grid_color'),'bottom'); + + end + + +end + + +% X-axis labels and grid + +if ~isempty(xtick) + + % Tricky thing - if we are drawing a map with the poles, its nasty when the lines get too close + % together. So we can sort of fudge this by altering MAP_VAR_LIST.lats to be slightly smaller, + % and then changing it back again later. + fudge_north='n';fudge_south='n'; + if ~isempty(ytick) && length(ytick)>1 + if MAP_VAR_LIST.lats(2)==90 + fudge_north='y'; + MAP_VAR_LIST.lats(2)=ytick(end); + end + if MAP_VAR_LIST.lats(1)==-90 + fudge_south='y'; + MAP_VAR_LIST.lats(1)=ytick(1); + end + end + + [X,Y,lg,lgI]=feval(MAP_PROJECTION.routine,'xgrid',xtick,gxaxisloc,gtickstyle); + [labs,scl]=m_labels('lon',lg,xlabels,gtickstyle); + + % Draw the grid. Every time we draw something, I first reshape the matrices into a long + % row so that a) it plots faster, and b) all lines are given the same handle (which cuts + % down on the number of children hanging onto the axes). + + [n,m]=size(X); + line(reshape([X;NaN+ones(1,m)],(n+1)*m,1),reshape([Y;NaN+ones(1,m)],(n+1)*m,1),... + 'linestyle',glinestyle,'color',ggridcolor,'linewidth',0.1,'tag','m_grid_xgrid','parent',ax); + + % Get the tick data + [ltx,lty,utx,uty]=maketicks(X,Y,gticklen,gtickdir); + + % Draw ticks if labels are on top or bottom (not if they are in the middle) + + if strcmp(gxticklabeldir,'middle') + if lgI==size(X,1) && strcmp(gxaxisloc,'top') % Check to see if the projection supports this option. + vert='bottom';horiz='center';drawticks=1; + xx=utx(1,:);yy=uty(1,:);rotang=atan2(diff(uty),diff(utx))*180/pi+90; + elseif lgI==1 && strcmp(gxaxisloc,'bottom') + vert='top';horiz='center';drawticks=1; + xx=ltx(1,:);yy=lty(1,:);rotang=atan2(diff(lty),diff(ltx))*180/pi-90; + else + vert='middle';horiz='center';lgIp1=lgI+1;drawticks=0; + xx=X(lgI,:); yy=Y(lgI,:);rotang=atan2(Y(lgIp1,:)-Y(lgI,:),X(lgIp1,:)-X(lgI,:))*180/pi-90; + end + else + if lgI==size(X,1) && strcmp(gxaxisloc,'top') % Check to see if the projection supports this option. + vert='middle';horiz='left';drawticks=1; + xx=utx(1,:);yy=uty(1,:);rotang=atan2(diff(uty),diff(utx))*180/pi+180; + elseif lgI==1 && strcmp(gxaxisloc,'bottom') + vert='middle';horiz='right';drawticks=1; + xx=ltx(1,:);yy=lty(1,:);rotang=atan2(diff(lty),diff(ltx))*180/pi; + else + vert='top';horiz='center';lgIp1=lgI+1;drawticks=0; + xx=X(lgI,:); yy=Y(lgI,:);rotang=atan2(Y(lgIp1,:)-Y(lgI,:),X(lgIp1,:)-X(lgI,:))*180/pi; + end + end + + % For some projections it is better if the x-grid labels are horizontal or + % vertical + + if any(strcmp(MAP_PROJECTION.name,{'Robinson','Sinusoidal'}) ) + if strcmp(gxaxisloc,'bottom') || strcmp(gxaxisloc,'top') + if strcmp(gxticklabeldir,'middle') + rotang = zeros(size(rotang)); % flat + yy=repmat(mean(yy),size(yy)); % Put them all on the same y-value. + else + rotang = zeros(size(rotang))+90; % upright + end + end + end + + + if strcmp(gbox,'fancy') + if gtickdir(1)=='i' + fancybox(lg,MAP_VAR_LIST.longs,'xgrid','bottom',dpatch,gticklen,gtickstyle,ax); + drawticks=0; + else + fancybox2(lg,MAP_VAR_LIST.longs,'xgrid','bottom',dpatch,gticklen,gtickstyle,ax); + end + end + if drawticks + [n,m]=size(ltx); + line(reshape([ltx;NaN+ones(1,m)],(n+1)*m,1),reshape([lty;NaN+ones(1,m)],(n+1)*m,1),... + 'linestyle','-','color',gcolor,'linewidth',glinewidth,'tag','m_grid_xticks-lower','clipping','off','parent',ax); + line(reshape([utx;NaN+ones(1,m)],(n+1)*m,1),reshape([uty;NaN+ones(1,m)],(n+1)*m,1),... + 'linestyle','-','color',gcolor,'linewidth',glinewidth,'tag','m_grid_xticks-upper','clipping','off','parent',ax); + end + + % Add the labels! (whew) + + ik=1:size(X,2); + + for k=ik + [rotang(k), horizk, vertk] = upright(rotang(k), horiz, vert); + text(xx(k),yy(k),labs{k},'horizontalalignment',horizk,'verticalalignment',vertk, ... + 'rotation',rotang(k),'fontsize',gfontsize*scl(k),'color',gcolor,... + 'tag','m_grid_xticklabel','fontname',gfontname,'parent',ax); + end + + if fudge_north=='y' + MAP_VAR_LIST.lats(2)=90; + end + if fudge_south=='y' + MAP_VAR_LIST.lats(1)=-90; + end + +end + +if ~isempty(ytick) + % Y-axis labels and grid + + [X,Y,lt,ltI]=feval(MAP_PROJECTION.routine,'ygrid',ytick,gyaxisloc,gtickstyle); + [labs,scl]=m_labels('lat',lt,ylabels,gtickstyle); + + % Draw the grid + [n,m]=size(X); + line(reshape([X;NaN+ones(1,m)],(n+1)*m,1),reshape([Y;NaN+ones(1,m)],(n+1)*m,1),... + 'linestyle',glinestyle,'color',ggridcolor,'linewidth',0.1,'tag','m_grid_ygrid','parent',ax); + + % Get the tick data + [ltx,lty,utx,uty]=maketicks(X,Y,gticklen,gtickdir); + + % Draw ticks if labels are on left or right (not if they are in the middle) + if strcmp(gyticklabeldir,'end') + if ltI==size(X,1) && strcmp(gyaxisloc,'right') % Check to see if the projection supports this option. + horiz='left';vert='middle';drawticks=1; + xx=utx(1,:);yy=uty(1,:);rotang=atan2(diff(uty),diff(utx))*180/pi+180; + elseif ltI==1 && strcmp(gyaxisloc,'left') + horiz='right';vert='middle';drawticks=1; + xx=ltx(1,:);yy=lty(1,:);rotang=atan2(diff(lty),diff(ltx))*180/pi; + else + horiz='center';vert='top';ltIp1=ltI+1;drawticks=0; + xx=X(ltI,:); yy=Y(ltI,:);rotang=atan2(Y(ltIp1,:)-Y(ltI,:),X(ltIp1,:)-X(ltI,:))*180/pi; + end + else + if ltI==size(X,1) && strcmp(gyaxisloc,'right') % Check to see if the projection supports this option. + horiz='center';vert='top';drawticks=1; + xx=utx(1,:);yy=uty(1,:);rotang=atan2(diff(uty),diff(utx))*180/pi+270; + elseif ltI==1 && strcmp(gyaxisloc,'left') + horiz='center';vert='bottom';drawticks=1; + xx=ltx(1,:);yy=lty(1,:);rotang=atan2(diff(lty),diff(ltx))*180/pi+90; + else + horiz='left';vert='middle';ltIp1=ltI+1;drawticks=0; + xx=X(ltI,:); yy=Y(ltI,:);rotang=atan2(Y(ltIp1,:)-Y(ltI,:),X(ltIp1,:)-X(ltI,:))*180/pi+90; + end + end + + % Added special case for latitudes. Dec/2018 + if any(strcmp(MAP_PROJECTION.name,{'Mollweide'}) ) + if strcmp(gyaxisloc,'left') + rotang=-lt; + elseif strcmp(gyaxisloc,'right') + rotang=lt; + end + end + + + if strcmp(gbox,'fancy') + if gtickdir(1)=='i' + fancybox(lt,MAP_VAR_LIST.lats,'ygrid','left',dpatch,gticklen,gtickstyle,ax); + drawticks=0; + else + fancybox2(lt,MAP_VAR_LIST.lats,'ygrid','left',dpatch,gticklen,gtickstyle,ax); + end + end + if drawticks + [n,m]=size(ltx); + line(reshape([ltx;NaN+ones(1,m)],(n+1)*m,1),reshape([lty;NaN+ones(1,m)],(n+1)*m,1),... + 'linestyle','-','color',gcolor,'linewidth',glinewidth,'tag','m_grid_yticks-left','clipping','off','parent',ax); + line(reshape([utx;NaN+ones(1,m)],(n+1)*m,1),reshape([uty;NaN+ones(1,m)],(n+1)*m,1),... + 'linestyle','-','color',gcolor,'linewidth',glinewidth,'tag','m_grid_yticks-right','clipping','off','parent',ax); + end + + % Finally - the labels! + ik=1:size(X,2); + + for k=ik + [rotang(k), horizk, vertk] = upright(rotang(k), horiz, vert); + text(xx(k),yy(k),labs{k},'horizontalalignment',horizk,'verticalalignment',vertk,... + 'rotation',rotang(k),'fontsize',gfontsize*scl(k),'color',gcolor,... + 'tag','m_grid_yticklabel','fontname',gfontname,'parent',ax); + end + +end + +% Draw the plot box + + +if strcmp(gbox,'on') + [X,Y]=feval(MAP_PROJECTION.routine,'box'); + line(X(:),Y(:),'linestyle','-','linewidth',glinewidth,'color',gcolor,'tag','m_grid_box','clipping','off','parent',ax); +end + +% Give a 1-1 aspect ratio and get rid of the matlab-provided axes stuff. + + +if isempty(strfind(version,'R2013b')) % 27/Sept/13 - Handling for 2013b provided by CB. + set(ax,'visible','off',... + 'dataaspectratio',[1 1 1],... + 'xlim',MAP_VAR_LIST.xlims,... + 'ylim',MAP_VAR_LIST.ylims); +else + set(ax,'visible','off',... + 'dataaspectratio',[1 1 1e16],... + 'xlim',MAP_VAR_LIST.xlims,... + 'ylim',MAP_VAR_LIST.ylims); +end + +set(ax,'tag',['m_grid_' MAP_PROJECTION.name]); + +set(get(ax,'title'),'visible','on'); +set(get(ax,'xlabel'),'visible','on'); +set(get(ax,'ylabel'),'visible','on'); + +% Set coordinate system back + +m_coord(Currentmap.name); + +end + + + +%------------------------------------------------------------- +% upright simply turns tick labels right-side up while leaving +% their positions unchanged. +% Sat 98/02/21 Eric Firing +% +function [rotang, horiz, vert] = upright(rotang, horiz, vert); +if isnan(rotang), rotang=0; end % Added in 2014! +if rotang > 180, rotang = rotang - 360; end +if rotang < -180, rotang = rotang + 360; end +if rotang > 90 + rotang = rotang - 180; +elseif rotang < -90 + rotang = 180 + rotang; +else + return % no change needed. +end +switch horiz(1) + case 'l' + horiz = 'right'; + case 'r' + horiz = 'left'; +end +switch vert(1) + case 't' + vert = 'bottom'; + case 'b' + vert = 'top'; +end + +end + +%-------------------------------------------------------------------------- +function [L,fs]=m_labels(dir,vals,uservals,tickstyle) +% M_LONLABEL creates longitude labels +% Default values are calculated automatically when the grid is +% generated. However, the user may wish to specify the labels +% as either numeric values or as strings (in the usual way +% for axes). +% +% If auto-labelling occurs, minutes are labelled in a different +% (smaller) fontsize than even degrees. + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 + +% If the user has specified [] (i.e. no labels), we return blanks. + +if isempty(uservals) + L=cellstr(char(' '*ones(length(vals),1))); + fs=1.0*ones(length(L),1); + return; +end + +% If the user has specified strings, we merely need to make +% sure that there are enough to cover all ticks. + +if any(ischar(uservals)) + L=cellstr( uservals((rem([0:length(vals)-1],length(uservals))+1),:) ); + fs=1.0*ones(length(L),1); + return; +end + +% Otherwise we are going to have to generate labels from numeric +% data. + +if length(uservals)==1 && isnan(uservals) % use default values + vals=vals(:)'; % make it a row. +else % or ones provided + lv=length(vals); + vals=uservals(:)'; + while length(vals)0;vals==0]; % get the 'names' (i.e. N/S or E/W) +%modified by Changyong He the label for 0 or +/-180 will not show the +%an E or W. +i=[-180~=vals & vals<0; 180~=vals & vals>0; vals==0 | abs(vals) == 180]; + + +L=cell(length(vals),1); +fs=ones(length(vals),1); + +if strcmp(tickstyle,'dm') + vals=abs(vals); % Convert to +ve values + + % For each label we have different options: + % 1 - even degrees are just labelled as such. + % 2 - ticks that fall on even minutes are just labelled as even minutes + % in a smaller fontsize. + % 3 - fractional minutes are labelled to 2 decimal places in the + % smaller fontsize. + for k=1:length(vals) + if rem(vals(k),1)==0 + nam=find(i(:,k)); + L{k}=sprintf([' %3.0f' char(176) labname(nam) ' '],vals(k)); + elseif abs(vals*60-round(vals*60))<.01 + L{k}=sprintf([' %2.0f'' '],rem(vals(k),1)*60); + fs(k)=0.75; + else + L{k}=sprintf([' %2.2f'' '],rem(vals(k),1)*60); + fs(k)=0.75; + end + end + + % In most cases, the map will have at least one tick with an even degree label, + % but for very small regions (<1 degree in size) this won't happen so we + % want to force one label to show degrees *and* minutes. + + if ~any(fs==1) + k=round(length(vals)/2); + nam=find(i(:,k)); + L{k}={sprintf([' %3.0f' char(176) labname(nam) ' '],fix(vals(k))),... + sprintf([' %2.2f'' '],rem(vals(k),1)*60)}; + fs(k)=1; + end + +elseif strcmp(tickstyle,'da') + % Abbreviated option suggested by Brooke Jones - Dec/2018 + % For each label we have different options: + % 1 - even degrees are just labelled as such. + % 2 - 2 decimal place intervals use 2 decimal places + % 3 - the rest fo to 4 + for k=1:length(vals) + if rem(vals(k),1)==0 + nam=find(i(:,k)); + L{k}=sprintf([' %4.0f '],vals(k)); + elseif abs(vals*100-round(vals*100))<0.01 + L{k}=sprintf([' %2.0f'' '],rem(abs(vals(k)),1)*60); + fs(k)=0.6; + else + L{k}=sprintf([' %2.2f'' '],rem(abs(vals(k)),1)*60); + fs(k)=0.6; + end + end + + % In most cases, the map will have at least one tick with an even degree label, + % but for very small regions (<1 degree in size) this won't happen so we + % want to force one label to show degrees *and* minutes. + + if ~any(fs==1) + k=round(length(vals)/2); + nam=find(i(:,k)); + L{k}={sprintf([' %4.0f '],fix(vals(k))),... + sprintf([' %2.2f'' '],abs(rem(vals(k),1))*60)}; + fs(k)=1; + end + +elseif strcmp(tickstyle,'dd') + vals=abs(vals); % Convert to +ve values + % For each label we have different options: + % 1 - even degrees are just labelled as such. + % 2 - 2 decimal place intervals use 2 decimal places + % 3 - the rest fo to 4 + for k=1:length(vals) + if rem(vals(k),1)==0 + nam=find(i(:,k)); + L{k}=sprintf([' %3.0f' char(176) labname(nam) ' '],vals(k)); + elseif abs(vals*100-round(vals*100))<0.01 + L{k}=sprintf([' %2.2f'],vals(k)); + fs(k)=0.75; + else + L{k}=sprintf([' %6.4f'],vals(k)); + fs(k)=0.75; + end + end + + + % write code. +end +end + +%--------------------------------------------------------- +function [ltx,lty,utx,uty]=maketicks(X,Y,gticklen,gtickdir) +% MAKETICKS makes the axis ticks. +% AXes ticks are based on making short lines at +% the end of the grid lines X,Y. + + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 + +global MAP_VAR_LIST + +tlen=gticklen*max( diff(MAP_VAR_LIST.xlims),diff(MAP_VAR_LIST.ylims)); + +lx=sqrt((X(2,:)-X(1,:)).^2+(Y(2,:)-Y(1,:)).^2); + +if strcmp(gtickdir,'out') + ltx=[X(1,:)-tlen*(X(2,:)-X(1,:))./lx;X(1,:)]; + lty=[Y(1,:)-tlen*(Y(2,:)-Y(1,:))./lx;Y(1,:)]; +else + ltx=[X(1,:);X(1,:)+tlen*(X(2,:)-X(1,:))./lx]; + lty=[Y(1,:);Y(1,:)+tlen*(Y(2,:)-Y(1,:))./lx]; +end + +lx=sqrt((X(end,:)-X(end-1,:)).^2+(Y(end,:)-Y(end-1,:)).^2); + +if strcmp(gtickdir,'out') + utx=[X(end,:)-tlen*(X(end-1,:)-X(end,:))./lx;X(end,:)]; + uty=[Y(end,:)-tlen*(Y(end-1,:)-Y(end,:))./lx;Y(end,:)]; +else + utx=[X(end,:);X(end,:)+tlen*(X(end-1,:)-X(end,:))./lx]; + uty=[Y(end,:);Y(end,:)+tlen*(Y(end-1,:)-Y(end,:))./lx]; +end +end + +%--------------------------------------------------------- +function fancybox(vals,lims,gridarg1,gridarg2,dpatch,gticklen,gridarg3,ax); +% +% FANCYBOX - draws fancy outlines for either top/bottom or left/right sides, +% depending on calling parameters. + +global MAP_PROJECTION + +% Get xlocations including endpoints +xval=sort([lims(1) vals(vals>lims(1) & valslims(1) & valsMAP_VAR_LIST.longs(2) & HLG-360>MAP_VAR_LIST.longs(1); + if any(ii(:)) HLG(ii)=HLG(ii)-360; end +end + +% Find pixels outside the limits of the actual map (if the boundary +% isn't a rectangle) +if strcmp(MAP_VAR_LIST.rectbox,'off') + [I,J]=find(HLTMAP_VAR_LIST.lats(2) | HLGMAP_VAR_LIST.longs(2)); +elseif strcmp(MAP_VAR_LIST.rectbox,'circle') + R=(XX.^2 +YY.^2); + [I,J]=find(R>MAP_VAR_LIST.rhomax.^2); +else + I=[];J=[]; +end + +% Find pixels outside the limits of the input data + [I1,J1]=find(HLT < lat(1) | HLT>lat(end) | HLGlon(end) ); + + +% This is for true-colour images + +if strcmp(class(C),'uint8') && length(size(C))==3 + + backcolor=uint8(get(gcf,'color')*255); + + GI=zeros(length(ylm),length(xlm),3,'uint8'); + for k=1:3 + F=griddedInterpolant(GC1,GC2,single(C(:,:,k)),'nearest'); % Set up interpolant + + GI(:,:,k)=uint8(F(HLT,HLG)); % Interpolate each color + + if any(I1) % if some pixels are gridded area + IJ=sub2ind(size(GI),I1,J1,repmat(k,size(I1))); + GI(IJ)=uint8(255); % Set them to white + end + if any(I) % if some pixels are outside the map area + IJ=sub2ind(size(GI),I,J,repmat(k,size(I))); + GI(IJ)=backcolor(k); % Set them to the background colour + end + + end + +elseif strcmp(class(C),'double') && length(size(C))==2 + + GI=zeros(length(ylm),length(xlm)); + + F=griddedInterpolant(GC1,GC2,C,'linear','none'); % Set up interpolant + + GI=F(HLT,HLG); % Interpolate each color + + if any(I) % if some pixels are outside the map area + IJ=sub2ind(size(GI),I,J); + GI(IJ)=NaN; % Set them to NaN + end + + +end + +if nargout<=1 + if strcmp(class(C),'uint8') && length(size(C))==3 + if any(I) % Points outside the map + alphadata= ones(size(GI,1),size(GI,2),'logical'); + IJ=sub2ind(size(alphadata),I,J); + alphadata(IJ)=0; + GI=image('XData',xlm,'YData',ylm,'CData',GI,'alphadata',alphadata,varargin{:},'tag','m_image'); + else + GI=image('XData',xlm,'YData',ylm,'CData',GI,varargin{:},'tag','m_image'); + end + elseif strcmp(class(C),'double') && length(size(C))==2 + GI=image('XData',xlm,'YData',ylm,'CData',GI,varargin{:},'tag','m_image',... + 'CDataMapping','scaled','alphadata',~isnan(GI)); + end +end + + diff --git a/functions/plotting/m_proj.m b/functions/plotting/m_proj.m new file mode 100644 index 0000000..b27c71e --- /dev/null +++ b/functions/plotting/m_proj.m @@ -0,0 +1,247 @@ +function outval=m_proj(proj,varargin) +% M_PROJ Initializes map projections info, putting the result into a structure +% +% M_PROJ('get') tells you the current state +% M_PROJ('set') gives you a list of all possibilities +% M_PROJ('set','proj name') gives info about a projection in the +% 'get' list. +% M_PROJ('proj name','property',value,...) initializes a projection. +% +% OUT=M_PROJ(...) returns a data structure with projection settings +% +% see also M_GRID, M_LL2XY, M_XY2LL. + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 +% +% This software is provided "as is" without warranty of any kind. But +% it's mine, so you can't sell it. +% +% 20/Sep/01 - Added support for other coordinate systems. +% 25/Feb/07 - Swapped "get" and "set" at lines 34 and 47 +% to make it consistent with the help +% (and common Matlab style) +% - Added lines 62-70 & 74 +% to harden against error when no proj is set +% (fixes thanks to Lars Barring) +% 18/Jan/18 - added output variable +% 19/Feb/19 - added some error checking on lat/lon limits + +global MAP_PROJECTION MAP_VAR_LIST MAP_COORDS + +%georef +% given points. +latmin = -50.9640; +latmax = -50.8920; +longmin= -73.7460; +longmax = -73.4730; + +xlims = [longmin longmax]; +ylims = [latmin latmax]; + + +% Get all the projections +projections=m_getproj; + +if nargin==0, proj='usage'; end + +proj=lower(proj); + +switch proj + + case 'set' % Print out their names + if nargin==1 + disp(' '); + disp('Available projections are:'); + for k=1:length(projections) + disp([' ' projections(k).name]); + end + else + k=m_match(varargin{1},projections(:).name); + eval(['X=' projections(k).routine '(''set'',projections(k).name);']); + disp(X); + end + + case 'get' % Get the values of all set parameters + if nargin==1 + if isempty(MAP_PROJECTION) + disp('No map projection initialized'); + m_proj('usage'); + else + k=m_match(MAP_PROJECTION.name,projections(:).name); + eval(['X=' projections(k).routine '(''get'');']); + disp('Current mapping parameters -'); + disp(X); + end + else + if isempty(MAP_PROJECTION) + k=m_match(varargin{1},projections(:).name); + eval(['X=' projections(k).routine '(''set'',projections(k).name);']); + X=strvcat(X, ... + ' ', ... + '**** No projection is currently defined ****', ... + ['**** USE "m_proj(''' varargin{1} ''',)" ****']); + disp(X); + else + k=m_match(varargin{1},projections(:).name); + eval(['X=' projections(k).routine '(''get'');']); + disp(X); + end + end + + case 'usage' + disp(' '); + disp('Possible calling options are:'); + disp(' ''usage'' - this list'); + disp(' ''set'' - list of projections'); + disp(' ''set'',''projection'' - list of properties for projection'); + disp(' ''get'' - get current mapping parameters (if defined)'); + disp(' ''projection'' <,properties> - initialize projection\n'); + + otherwise % If a valid name, give the usage. + k=m_match(proj,projections(:).name); + MAP_PROJECTION=projections(k); + + eval([ projections(k).routine '(''initialize'',projections(k).name,varargin{:});']); + + % Some error checking + if diff(MAP_VAR_LIST.lats)<=0.0001 % if you make this too small drawing ticks in m_grid can screw up + error(sprintf('Lower latitude (%.3f) is not < upper latitude (%.3f)',MAP_VAR_LIST.lats)); + clear MAP_PROJECTION + return + end + if MAP_VAR_LIST.lats(1)<-90 || MAP_VAR_LIST.lats(2)>90 || any(isnan(MAP_VAR_LIST.lats)) + error(sprintf('Latitude range (%.3f %.3f) is outside of known bounds of -90 to 90',MAP_VAR_LIST.lats)); + clear MAP_PROJECTION + return + end + if diff(MAP_VAR_LIST.longs)<=0.0001 + error(sprintf('Left longitude (%.3f) is not < right longitude (%.3f)',MAP_VAR_LIST.longs)); + clear MAP_PROJECTION + return + end + if MAP_VAR_LIST.longs(1)<-540 || MAP_VAR_LIST.longs(2)>540 || any(isnan(MAP_VAR_LIST.longs)) + error(sprintf('Longitude range (%.3f %.3f) is outside of known bounds of -540 to 540',MAP_VAR_LIST.longs)); + clear MAP_PROJECTION + return + end + if diff(MAP_VAR_LIST.xlims)<=0 + error('Map has zero width - check m_proj input parameters'); + clear MAP_PROJECTION + return + end + if diff(MAP_VAR_LIST.ylims)<=0 + error('Map has zero height - check m_proj input parameters'); + clear MAP_PROJECTION + return + end + + + + % With the projection store what coordinate system we are using to define it. + if isempty(MAP_COORDS) + m_coord('geographic'); + end + MAP_PROJECTION.coordsystem=MAP_COORDS; + + % Save some other stuff that otherwise seems to take a while to run + MAP_PROJECTION.version=ver('matlab'); + if isempty(MAP_PROJECTION.version) + MAP_PROJECTION.version=ver('octave'); + end + if strcmp(MAP_PROJECTION.version.Name,'Octave') + MAP_PROJECTION.IsOctave=true; + MAP_PROJECTION.newgraphics=false; + MAP_PROJECTION.LARGVAL=flintmax; % was bitmax, but flintmax works in 3.8.1 and in 4.2 and later + % octave issues a warning that bitmax should be replaced with flintmax + else + MAP_PROJECTION.IsOctave=false; + if verLessThan('matlab','8.4') + MAP_PROJECTION.newgraphics=false; + else + MAP_PROJECTION.newgraphics=true; + end + % I use bitmax in various places as 'a large number', but + % as of 2014b this has been renamed + if verLessThan('matlab','8.3') + MAP_PROJECTION.LARGVAL=bitmax; + else + MAP_PROJECTION.LARGVAL=flintmax; + end + end + + if nargout==1 + outval=MAP_VAR_LIST; + end + + +end + +%--------------------------------------------------------- +function projections=m_getproj +% M_GETPROJ Gets a list of the different projection routines +% and returns a structure containing both their +% names and the formal name of the projection. +% (used by M_PROJ). + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 9/May/1997 +% +% 9/May/97 - fixed paths for Macs (thanks to Dave Enfield) +% +% 7/05/98 - VMS pathnames (thanks to Helmut Eggers) + +% Get all the projections + +lpath=which('m_proj'); +fslashes=strfind(lpath,'/'); +bslashes=strfind(lpath,'\'); +colons=strfind(lpath,':'); +closparantheses=strfind(lpath,']'); +if ~isempty(fslashes) + lpath=[ lpath(1:max(fslashes)) './plotting/']; +elseif ~isempty(bslashes) + lpath=[ lpath(1:max(bslashes)) './plotting\']; +elseif ~isempty(closparantheses) % for VMS computers only, others don't use ']' in filenames + lpath=[ lpath(1:max(closparantheses)-1) './plotting]']; +else + lpath=[ lpath(1:max(colons)) './plotting:']; +end + +w=dir([lpath 'mp_*.m']); + +if isempty(w) % Not installed correctly + disp('**********************************************************'); + disp('* ERROR - Can''t find anything in a /plotting subdirectory *'); + disp('* m_map probably unzipped incorrectly - please *'); + disp('* unpack again, preserving directory structure *'); + disp('* *'); + disp('* ...Abandoning m_proj now. *'); + error('**********************************************************'); +end + +l=1; +projections=[]; +for k=1:length(w) + funname=w(k).name(1:(strfind(w(k).name,'.'))-1); + projections(l).routine=funname; + eval(['names= ' projections(l).routine '(''name'');']); + for m=1:length(names) + projections(l).routine=funname; + projections(l).name=names{m}; + l=l+1; + end +end + + +%---------------------------------------------------------- +function match=m_match(arg,varargin) +% M_MATCH Tries to match input string with possible options + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 + +match=find(strncmpi(deblank(arg),cellstr(char(varargin)),length(deblank(arg)))); + +if length(match)>1 + error(['Projection ''' arg ''' not a unique specification']); +elseif isempty(match) + error(['Projection ''' arg ''' not recognized']); +end diff --git a/functions/plotting/m_xy2ll.m b/functions/plotting/m_xy2ll.m new file mode 100644 index 0000000..618ed9f --- /dev/null +++ b/functions/plotting/m_xy2ll.m @@ -0,0 +1,39 @@ +function [long,lat]=m_xy2ll(X,Y) +% M_XY2LL Converts X,Y to long,lat coordinates using the current projection +% [LONGITUDE,LATITUDE]=m_ll2xy(X,Y) +% This is useful for finding locations using ginput. + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 +% +% This software is provided "as is" without warranty of any kind. But +% it's mine, so you can't sell it. + +% 6/Nov/00 - eliminate returned stuff if ';' neglected (thx to D Byrne) +% 4/DEc/11 - isstr to ischar + +global MAP_PROJECTION MAP_COORDS + +if isempty(MAP_PROJECTION) + disp('No Map Projection initialized - call M_PROJ first!'); + return; +end + +if nargin==0 || ischar(X) + disp(' Usage:'); + disp(' [LONGITUDE,LATITUDE]=m_xy2ll(X,Y);'); +else + [long,lat]=feval(MAP_PROJECTION.routine,'xy2ll',X,Y); + if ~strcmp(MAP_COORDS.name,MAP_PROJECTION.coordsystem.name) + if strcmp(MAP_COORDS.name,'geographic') + [long,lat]=mc_coords('mag2geo',long,lat); + else + [long,lat]=mc_coords('geo2mag',long,lat); + end + end +end + +if nargout==0 + clear long lat +end + + diff --git a/functions/plotting/mc_coords.m b/functions/plotting/mc_coords.m new file mode 100644 index 0000000..fee644b --- /dev/null +++ b/functions/plotting/mc_coords.m @@ -0,0 +1,159 @@ +function [longOUT,latOUT,phiVecOUT,thetaVecOUT]=mc_coords(optn,longIN,latIN,phiVecIN,thetaVecIN) +% MP_COORD Converts between coordinate systems based on different +% poles. Generally used in space physics to plot things in +% geomagnetic (dipole) coordinate systems. +% +% This function should not be used directly; instead it is +% is accessed by various high-level functions named M_*. +% +% Vector rotations can be carried out using the following: +% +% [latOUT,longOUT,phiVecOUT,thetaVecOUT]=M_GEO2MAG(latIN,longIN,phiVecIN,thetaVecIN) +% +% where +% +% thetaVecIN - north component of the vector in geographic coordinates +% phiVecIN - east component of the vector in geographic coordinates +% thetaVecOUT - north component of the vector in geomagnetic coordinates +% phiVecOUT - east component of the vector in geomagnetic coordinates +% + +% References: +% +% Hapgood, M.A., Space Physics Coordinate Transformations: +% A User Guide, Planet. Space Sci., Vol. 40, N0. 5, 1992. + +% Antti Pulkkinen, September 2001. +% R. Pawlowicz 9/01 - Vectorized, changed functionality, put into standard M_MAP form. +% +% 29/Sep/2005 - fixed bug (apparently no-one ever used this option before now!) +% +% 1 Nov 2012 - added IGRF2011 coords (thanks to Joe Kinrade) + +global MAP_PROJECTION MAP_COORDS + +pi180=pi/180; + + +switch optn + case 'name' + + longOUT.name={'geographic','IGRF2000-geomagnetic','IGRF2011-geomagnetic'}; + return; + + case 'parameters' + switch longIN + case 'geographic' + longOUT.name='geographic'; + longOUT.lambda = 0; + longOUT.phi = 0; + + case 'IGRF2000-geomagnetic' + g10=-29615; + g11=-1728; + h11=5186; + longOUT.name='IGRF2000-geomagnetic'; + longOUT.lambda= atan(h11/g11); + longOUT.phi = atan((g11*cos(longOUT.lambda)+h11*sin(longOUT.lambda))/g10); + + case 'IGRF2011-geomagnetic' %ADDED 2012-11-02 Joe Kinrade, Uni. of Bath + g10=-29496.5; %1st order IGFR2011 coefficient + g11=-1585.9; %2nd order + h11=4945.1; %3rd order + longOUT.name='IGRF2011-geomagnetic'; + longOUT.lambda= atan(h11/g11); + longOUT.phi = atan((g11*cos(longOUT.lambda)+h11*sin(longOUT.lambda))/g10); + + otherwise + error('Unrecognized coordinate system'); + end + return; + case 'geo2mag' + + % Rotation matrices + lambda=MAP_PROJECTION.coordsystem.lambda; + phi=MAP_PROJECTION.coordsystem.phi; + Tz=[ cos(lambda) sin(lambda) 0 ; + -sin(lambda) cos(lambda) 0 ; + 0 0 1 ]; + + Ty=[ cos(phi) 0 -sin(phi) ; + 0 1 0 ; + sin(phi) 0 cos(phi) ]; + T=Ty*Tz; + + case 'mag2geo' + % Rotation matrices + lambda=MAP_COORDS.lambda; + phi=MAP_COORDS.phi; + Tz=[ cos(-lambda) sin(-lambda) 0 ; + -sin(-lambda) cos(-lambda) 0 ; + 0 0 1 ]; + + Ty=[ cos(-phi) 0 -sin(-phi) ; + 0 1 0 ; + sin(-phi) 0 cos(-phi) ]; + T=Tz*Ty; + + +end + +[n,m]=size(latIN); + +% Degrees to radians, and make into rows. +latIN=(90 - latIN(:)')*pi180; +longIN=longIN(:)'*pi180; + + + +% Transformation to cartesian coordinates. +x=sin(latIN).*cos(longIN); +y=sin(latIN).*sin(longIN); +z=cos(latIN); + +% Rotations of the coordinates. +tmp=T*[x; y; z]; +xp=tmp(1,:);yp=tmp(2,:);zp=tmp(3,:); + +% Transformation back to spherical coordinates. Choosing the correct quadrant. +latOUT=acos(zp./sqrt(xp.^2+yp.^2+zp.^2)); +longOUT=atan2(yp,xp); + +if nargin > 3 + % Sign change due to sign convention used here. + thetaVecIN=-thetaVecIN(:)'; + phiVecIN=phiVecIN(:)'; + + % Computing vector rotations. + % First, transformation to cartesian coordinates. + + % Rotation matrix is + % [x] [ sLcG cLcG -sG ][radial] + % [y]=[ sLsG cLsG cG ][south ] + % [z] [ cL -sL 0 ][east ] + + % Radial component is zero. + Xvec= 0+ cos(latIN).*cos(longIN).*thetaVecIN - sin(longIN).*phiVecIN; + Yvec= 0+ cos(latIN).*sin(longIN).*thetaVecIN + cos(longIN).*phiVecIN; + Zvec= 0+ -sin(latIN).*thetaVecIN + 0; + + % Rotations of the system. + tmp=T*[Xvec;Yvec; Zvec]; + Xvecp=tmp(1,:);Yvecp=tmp(2,:);Zvecp=tmp(3,:); + + % Transformation back to spherical coordinates. + + thetaVecOUT=cos(latOUT).*cos(longOUT).*Xvecp + cos(latOUT).*sin(longOUT).*Yvecp -sin(latOUT).*Zvecp ; + phiVecOUT = -sin(longOUT).*Xvecp + cos(longOUT).*Yvecp +0 ; + + % Sign change due to sign convention used here. + thetaVecOUT=-reshape(thetaVecOUT,n,m); + phiVecOUT = reshape(phiVecOUT,n,m); +end + + +% Radians to degrees. +latOUT=90 - reshape(latOUT,n,m)/pi180; +longOUT=reshape(longOUT,n,m)/pi180; + + diff --git a/functions/plotting/plotting/._mc_coords.m b/functions/plotting/plotting/._mc_coords.m new file mode 100644 index 0000000..bb81195 Binary files /dev/null and b/functions/plotting/plotting/._mc_coords.m differ diff --git a/functions/plotting/plotting/._mc_ellips.m b/functions/plotting/plotting/._mc_ellips.m new file mode 100644 index 0000000..bb81195 Binary files /dev/null and b/functions/plotting/plotting/._mc_ellips.m differ diff --git a/functions/plotting/plotting/._mp_azim.m b/functions/plotting/plotting/._mp_azim.m new file mode 100644 index 0000000..bb81195 Binary files /dev/null and b/functions/plotting/plotting/._mp_azim.m differ diff --git a/functions/plotting/plotting/._mp_conic.m b/functions/plotting/plotting/._mp_conic.m new file mode 100644 index 0000000..bb81195 Binary files /dev/null and b/functions/plotting/plotting/._mp_conic.m differ diff --git a/functions/plotting/plotting/._mp_cyl.m b/functions/plotting/plotting/._mp_cyl.m new file mode 100644 index 0000000..bb81195 Binary files /dev/null and b/functions/plotting/plotting/._mp_cyl.m differ diff --git a/functions/plotting/plotting/._mp_omerc.m b/functions/plotting/plotting/._mp_omerc.m new file mode 100644 index 0000000..bb81195 Binary files /dev/null and b/functions/plotting/plotting/._mp_omerc.m differ diff --git a/functions/plotting/plotting/._mp_tmerc.m b/functions/plotting/plotting/._mp_tmerc.m new file mode 100644 index 0000000..bb81195 Binary files /dev/null and b/functions/plotting/plotting/._mp_tmerc.m differ diff --git a/functions/plotting/plotting/._mp_utm.m b/functions/plotting/plotting/._mp_utm.m new file mode 100644 index 0000000..bb81195 Binary files /dev/null and b/functions/plotting/plotting/._mp_utm.m differ diff --git a/functions/plotting/plotting/._mu_coast.m b/functions/plotting/plotting/._mu_coast.m new file mode 100644 index 0000000..bb81195 Binary files /dev/null and b/functions/plotting/plotting/._mu_coast.m differ diff --git a/functions/plotting/plotting/._mu_util.m b/functions/plotting/plotting/._mu_util.m new file mode 100644 index 0000000..bb81195 Binary files /dev/null and b/functions/plotting/plotting/._mu_util.m differ diff --git a/functions/plotting/plotting/clabel.m.OLD b/functions/plotting/plotting/clabel.m.OLD new file mode 100644 index 0000000..43e0272 --- /dev/null +++ b/functions/plotting/plotting/clabel.m.OLD @@ -0,0 +1,567 @@ +function hh = clabel(cs,varargin) +%CLABEL Contour plot elevation labels. +% CLABEL(CS,H) adds height labels to the current contour +% plot. The labels are rotated and inserted within the contour +% lines. CS and H are the contour matrix output and object handle +% outputs from CONTOUR, CONTOUR3, or CONTOURF. +% +% CLABEL(CS,H,V) labels just those contour levels given in +% vector V. The default action is to label all known contours. +% The label positions are selected randomly. +% +% CLABEL(CS,H,'manual') places contour labels at the locations +% clicked on with a mouse. Pressing the return key terminates +% labeling. Use the space bar to enter contours and the arrow +% keys to move the crosshair if no mouse is available. +% +% CLABEL(CS) or CLABEL(CS,V) or CLABEL(CS,'manual') places +% contour labels as above, except that the labels are drawn as +% plus signs on the contour with a nearby height value. +% +% H = CLABEL(...) returns handles to the TEXT (and possibly LINE) +% objects created. The UserData property of the TEXT objects contain +% the height value for each label. +% +% Text property/value pairs can be appended to the list of +% input arguments in the above: +% CLABEL(clabel options, 'text property', property_value , ... ) +% +% One special property ('label') is also available to specify +% the spacing between labels (in points). This defaults to 144, or +% 2 inches. +% +% Example +% subplot(1,3,1), [cs,h] = contour(peaks); clabel(cs,h,'label',72) +% subplot(1,3,2), cs = contour(peaks); clabel(cs) +% subplot(1,3,3), [cs,h] = contour(peaks); +% clabel(cs,h,'fontsize',15,'color','r','rotation',0) +% +% See also CONTOUR, CONTOUR3, CONTOURF, LINELABEL. + +% Thanks to R. Pawlowicz (IOS) rich@ios.bc.ca for the algorithm used +% in 'inline_labels' so that clabel can produce inline labeling. + +% Copyright (c) 1984-96 by The MathWorks, Inc. +% $Revision: 5.19 $ $Date: 1996/10/25 17:43:58 $ + +% Modified by R Pawlowicz to allow for text properties as in extcontour code 14/5/97 +% 28/10/97 - modified to work in map contouring +% 9/01/98 - improved calculation of gaps for line labels +% Fix by Eric Firing, efiring@soest.hawaii.edu, 4/97, to +% make the rotation angles correct when XDir and/or YDir are +% reverse. +% 4/DEc/11 - isstr to ischar + +if nargin == 0 + error('Not enough input arguments.') +end +if min(size(cs)) > 2 + error('First input must be a valid contour description matrix.') +end +threeD = IsThreeD(gca); + +if nargin == 1, + h = plus_labels(threeD,cs); +else + if ~isempty(varargin{1}(1)) & ishandle(varargin{1}(1)) & ... + (strcmp(get(varargin{1}(1),'type'),'line') | strcmp(get(varargin{1}(1),'type'),'patch')), + h = inline_labels(cs,varargin{:}); + else + h = plus_labels(threeD,cs,varargin{:}); + end; +end; + + +if nargout>0, hh = h; end +if ~ishold, + if threeD, view(3), else view(2), end +end + +%-------------------------------------------------------------- +function H = inline_labels(CS,h,varargin) +% +% Draw the labels along the contours and rotated to match the local slope. +% + +% To open up space in the contours, we rely on the order in which +% the handles h are created in CONTOUR3. If CONTOUR3 changes you +% might need to change the algorithm below. + +% Author: R. Pawlowicz IOS rich@ios.bc.ca +% 12/12/94 +% changes - R. Pawlowicz 14/5/97 - small bug in "that ole' matlab magic" fixed, +% also another in manual selection of locations. + +manual=0; v=[]; inargs=zeros(1,length(varargin)); + +if nargin>=3 & ischar(varargin{1}) & strcmp(varargin{1},'manual'), + manual = 1; + inargs(1)=1; +end + +if ~manual & nargin>=3 & ~ischar(varargin{1}), + v = varargin{1}; + inargs(1)=1; +end; + +lab_int=72*2; % label interval (points) + +for k=find(inargs==0), + if ischar(varargin{k}) & ~isempty(findstr(varargin{k},'lab')), + inargs([k k+1])=1; + lab_int=varargin{k+1}; + end; +end; + +varargin(find(inargs))=[]; + +if strcmp(get(h(1),'type'),'patch') & ~strcmp(get(h(1),'facecolor'),'none'), + isfilled = 1; +else + isfilled = 0; +end + +%% EF 4/97 +if (strcmp(get(gca, 'XDir'), 'reverse')), XDir = -1; else XDir = 1; end +if (strcmp(get(gca, 'YDir'), 'reverse')), YDir = -1; else YDir = 1; end +%% + +% Compute scaling to make sure printed output looks OK. We have to go via +% the figure's 'paperposition', rather than the the absolute units of the +% axes 'position' since those would be absolute only if we kept the 'units' +% property in some absolute units (like 'points') rather than the default +% 'normalized'. + +UN=get(gca,'units'); +if (UN(1:3)=='nor'), + UN=get(gcf,'paperunits'); + set(gcf,'paperunits','points'); + PA=get(gcf,'paperposition'); + set(gcf,'paperunits',UN); + PA=PA.*[get(gca,'position')]; +else + set(gca,'units','points'); + PA=get(gca,'pos'); + set(gca,'units',UN); +end; + +% Find beginning of all lines + +lCS=size(CS,2); + +if ~isempty(get(gca,'children')), + XL=get(gca,'xlim'); + YL=get(gca,'ylim'); +else + iL=[]; + k=1; + XL=[Inf -Inf]; + YL=[Inf -Inf]; + while (k lCS, break, end + c = CS(1,ii); n = CS(2,ii); nn = 2 .* n -1; + xtemp = zeros(nn, 1); ytemp = zeros(nn, 1); + xtemp(1:2:nn) = CS(1, ii+1:ii+n); + xtemp(2:2:nn) = (xtemp(1:2:nn-2) + xtemp(3:2:nn)) ./ 2; + ytemp(1:2:nn) = CS(2, ii+1:ii+n); + ytemp(2:2:nn) = (ytemp(1:2:nn-2) + ytemp(3:2:nn)) ./ 2; + x = [x; xtemp]; y = [y; ytemp]; % Keep these. + ilist = [ilist; ii(ones(nn,1))]; + klist = [klist; k(ones(nn,1))]; + plist = [plist; (1:.5:n)']; + end + ax = axis; + xmin = ax(1); xmax = ax(2); ymin = ax(3); ymax = ax(4); + xrange = xmax - xmin; yrange = ymax - ymin; + xylist = (x .* yrange + sqrt(-1) .* y .* xrange); + view(2) + disp(' '); + disp(' Carefully select contours for labeling.') + disp(' When done, press RETURN while the Graph window is the active window.') +end + +% Get labels all at once to get the length of the longest string. +% This allows us to call extent only once, thus speeding up this routine +if ~manual, + labels = getlabels(CS); + % Get the size of the label + set(H1,'string',repmat('9',1,size(labels,2)),'visible','on',varargin{:}) + EX=get(H1,'extent'); set(H1,'visible','off') + len_lab=EX(3)/2; +end + +ii=1; k = 0; +levels = []; positions = []; +while (ii xmax, break, end + if yy < ymin | yy > ymax, break, end + xy = xx .* yrange + sqrt(-1) .* yy .* xrange; + dist = abs(xylist - xy); + f = find(dist == min(dist)); + if ~isempty(f) + f = f(1); + ii = ilist(f); + k = klist(f); + p = floor(plist(f)); + end + else + k = k+1; + end + + if ~isfilled & k>length(h), error('Not enough contour handles.'); end + + l=CS(2,ii); + x=CS(1,ii+(1:l)); + y=CS(2,ii+(1:l)); + + lvl=CS(1,ii); + + if manual + lab=num2str(lvl); + % Get the size of the label + set(H1,'string',lab,'visible','on',varargin{:}) + EX=get(H1,'extent'); set(H1,'visible','off') + len_lab=EX(3)/2; + else + %RP - get rid of all blanks in label + lab=labels(k,labels(k,:)~=' '); + %RP - scale label length by string size instead of a fixed length + len_lab=EX(3)/2*length(lab)/size(labels,2); + end + + % RP28/10/97 - Contouring sometimes returns x vectors with NaN in them - we want to handle + % this case! + sx=x*Aspx; + sy=y*Aspy; + d=[0 sqrt(diff(sx).^2 +diff(sy).^2) ];d(isnan(d))=0; + d=cumsum(d); + if ~manual + psn=[max(len_lab,lab_int+lab_int*(rand(1)-.5)):lab_int:d(l)-len_lab]; + else + psn = min(max(max(d(p),d(2)+eps*d(2)),d(1)+len_lab),d(end)-len_lab); +%%RP levels = [levels;lvl]; + levels = [levels;ii]; + positions = [positions;psn]; +%%RP kk = find(levels==lvl) + kk = find(levels==ii); + psn = positions(kk)'; + end + lp=size(psn,2); + + if (lp>0) & isfinite(lvl) & ... + (isempty(v) | any(abs(lvl-v)/max(eps+abs(v)) < .00001)), + + Ic=sum( d(ones(1,lp),:)' < psn(ones(1,l),:) ); + Il=sum( d(ones(1,lp),:)' <= psn(ones(1,l),:)-len_lab ); + Ir=sum( d(ones(1,lp),:)' < psn(ones(1,l),:)+len_lab ); + + Ir = max(0,min(Ir,length(d)-1)); + Il = max(0,min(Il,length(d)-1)); + Ic = max(0,min(Ic,length(d)-1)); + + % Endpoints of text in data coordinates + wl=(d(Il+1)-psn+len_lab)./(d(Il+1)-d(Il)); + wr=(psn-len_lab-d(Il) )./(d(Il+1)-d(Il)); + xl=x(Il).*wl+x(Il+1).*wr; + yl=y(Il).*wl+y(Il+1).*wr; + + wl=(d(Ir+1)-psn-len_lab)./(d(Ir+1)-d(Ir)); + wr=(psn+len_lab-d(Ir) )./(d(Ir+1)-d(Ir)); + xr=x(Ir).*wl+x(Ir+1).*wr; + yr=y(Ir).*wl+y(Ir+1).*wr; + + trot=atan2( (yr-yl)*YDir*Aspy, (xr-xl)*XDir*Aspx )*180/pi; %% EF 4/97 + backang=abs(trot)>90; + trot(backang)=trot(backang)+180; + + % Text location in data coordinates + + wl=(d(Ic+1)-psn)./(d(Ic+1)-d(Ic)); + wr=(psn-d(Ic) )./(d(Ic+1)-d(Ic)); + xc=x(Ic).*wl+x(Ic+1).*wr; + yc=y(Ic).*wl+y(Ic+1).*wr; + + % Shift label over a little if in a curvy area + shiftfrac=.5; + + xc=xc*(1-shiftfrac)+(xr+xl)/2*shiftfrac; + yc=yc*(1-shiftfrac)+(yr+yl)/2*shiftfrac; + + % Remove data points under the label... + % First, find endpoint locations as distances along lines + + dr=d(Ir)+sqrt( ((xr-x(Ir))*Aspx).^2 + ((yr-y(Ir))*Aspy).^2 ); + dl=d(Il)+sqrt( ((xl-x(Il))*Aspx).^2 + ((yl-y(Il))*Aspy).^2 ); + + % Now, remove the data points in those gaps using that + % ole' Matlab magic. We use the sparse array stuff instead of + % something like: + % f1=zeros(1,l); f1(Il)=ones(1,lp); + % because the sparse functions will sum into repeated indices, + % rather than just take the last accessed element - compare + % x=[0 0 0]; x([2 2])=[1 1] + % with + % x=full(sparse([1 1],[2 2],[1 1],1,3)) + % (bug fix in original code 18/7/95 - RP) + + f1=full(sparse(ones(1,lp),Il,ones(1,lp),1,l)); + f2=full(sparse(ones(1,lp),Ir,ones(1,lp),1,l)); + irem=find(cumsum(f1)-cumsum(f2))+1; + x(irem)=[]; + y(irem)=[]; + d(irem)=[]; + l=l-size(irem,2); + + % Put the points in the correct order... + + xf=[x(1:l),xl,repmat(NaN,size(xc)),xr]; + yf=[y(1:l),yl,yc,yr]; + + [df,If]=sort([d(1:l),dl,psn,dr]); + + % ...and draw. + % + % Here's where we assume the order of the h(k). + % + + z = get(h(k),'zdata'); + if ~isfilled, % Only modify lines or patches if unfilled + set(h(k),'xdata',[xf(If) NaN],'ydata',[yf(If) NaN]) + + % Handle contour3 case (z won't be empty). + if ~isempty(z), z = repmat(z(1),size(get(h(k),'xdata'))); end + + if strcmp(get(h(k),'type'),'patch') + set(h(k),'cdata',lvl+[0*xf(If) 0]) + end + end + + for jj=1:lp, + % Handle contour3 case (z won't be empty). + if ~isempty(z), + H = [H;text(xc(jj),yc(jj),z(1),lab,'rotation',trot(jj), ... + 'verticalAlignment','middle','horizontalAlignment','center',... + 'clipping','on','userdata',lvl,varargin{:})]; + else + H = [H;text(xc(jj),yc(jj),lab,'rotation',trot(jj), ... + 'verticalAlignment','middle','horizontalAlignment','center',... + 'clipping','on','userdata',lvl,varargin{:})]; + end + end; + else + if ~isfilled, % Only modify lines or patches if unfilled + % + % Here's another place where we assume the order of the h(k) + % + set(h(k),'xdata',[x NaN],'ydata',[y NaN], ... + 'zdata',[0*x 0]) + if strcmp(get(h(k),'type'),'patch') + set(h(k),'cdata',lvl+[0*x 0]) + end + end + end; + + if ~manual + ii=ii+1+CS(2,ii); + end +end; + +% delete dummy string +delete(H1); +%------------------------------------------------------- + +%------------------------------------------------------- +function h = plus_labels(threeD,cs,varargin); +% +% Draw the labels as plus symbols next to text (v4 compatible) +% + +% RP - 14/5/97 +% Clay M. Thompson 6-7-96 +% Charles R. Denham, MathWorks, 1988, 1989, 1990. +cax = gca; +manual = 0; +choice = 0; + + +if nargin > 2 + if ischar(varargin{1}), + if strcmp(varargin{1}, 'manual') + varargin(1)=[]; + manual=1; + end; + else + choice = 1; + v = sort(varargin{1}(:)); + varargin(1)=[]; + end +end + +[mcs, ncs] = size(cs); + +% Find range of levels. +k = 1; i = 1; +while k <= ncs + levels(i) = cs(1,k); + i = i + 1; + k = k + cs(2,k) + 1; +end +cmin = min(levels); +cmax = max(levels); +crange = max(abs(levels)); +cdelta = abs(diff(levels)); +cdelta = min(cdelta(cdelta > eps))/max(eps,crange); % Minimum significant change +if isempty(cdelta), cdelta = 0; end + +% Decompose contour data structure if manual mode. + +if manual + disp(' '), disp(' Please wait a moment...') + x = []; y = []; clist = []; k = 0; n = 0; + while (1) + k = k + n + 1; if k > ncs, break, end + c = cs(1,k); n = cs(2,k); nn = 2 .* n -1; + xtemp = zeros(nn, 1); ytemp = zeros(nn, 1); + xtemp(1:2:nn) = cs(1, k+1:k+n); + xtemp(2:2:nn) = (xtemp(1:2:nn-2) + xtemp(3:2:nn)) ./ 2; + ytemp(1:2:nn) = cs(2, k+1:k+n); + ytemp(2:2:nn) = (ytemp(1:2:nn-2) + ytemp(3:2:nn)) ./ 2; + x = [x; xtemp]; y = [y; ytemp]; % Keep these. + clist = [clist; c .* ones(2*n-1, 1)]; + end + ax = axis; + xmin = ax(1); xmax = ax(2); ymin = ax(3); ymax = ax(4); + xrange = xmax - xmin; yrange = ymax - ymin; + xylist = (x .* yrange + sqrt(-1) .* y .* xrange); + view(2) + disp(' '); + disp(' Carefully select contours for labeling.') + disp(' When done, press RETURN while the Graph window is the active window.') +end + +k = 0; n = 0; flip = 0; h = []; + +while (1) + +% Use GINPUT and select nearest point if manual. + + if manual + [xx, yy, button] = ginput(1); + if isempty(button) | isequal(button,13), break, end + if xx < xmin | xx > xmax, break, end + if yy < ymin | yy > ymax, break, end + xy = xx .* yrange + sqrt(-1) .* yy .* xrange; + dist = abs(xylist - xy); + f = find(dist == min(dist)); + if length(f) > 0 + f = f(1); xx = x(f); yy = y(f); c = clist(f); + okay = 1; + else + okay = 0; + end + end + +% Select a labeling point randomly if not manual. + + if ~manual + k = k + n + 1; if k > ncs, break, end + c = cs(1, k); n = cs(2, k); + if choice + f = find(abs(c-v)/max(eps+abs(v)) < .00001); + okay = length(f) > 0; + else + okay = 1; + end + if okay + r = rand; + j = fix(r.* (n - 1)) + 1; + if flip, j = n - j; end + flip = ~flip; + if n == 1 % if there is only one point + xx = cs(1, j+k); yy = cs(2, j+k); + else + x1 = cs(1, j+k); y1 = cs(2, j+k); + x2 = cs(1, j+k+1); y2 = cs(2, j+k+1); + xx = (x1 + x2) ./ 2; yy = (y1 + y2) ./ 2; % Test was here; removed. + end + end + end + +% Label the point. + + if okay + % Set tiny labels to zero. + if abs(c) <= 10*eps*crange, c = 0; end + % Determine format string number of digits + if cdelta > 0, + ndigits = max(3,ceil(-log10(cdelta))); + else + ndigits = 3; + end + s = num2str(c,ndigits); + hl = line('xdata',xx,'ydata',yy,'marker','+','erasemode','none'); + ht = text(xx, yy, s, 'verticalalignment', 'bottom', ... + 'horizontalalignment', 'left','erasemode','none', ... + 'clipping','on','userdata',c,varargin{:}); + if threeD, + set(hl,'zdata',c); + set(ht,'position',[xx yy c]); + end + h = [h;hl]; + h = [h;ht]; + end +end +%------------------------------------------------------- + +%------------------------------------------------------- +function labels = getlabels(CS) +%GETLABELS Get contour labels +v = []; i =1; +while i < size(CS,2), + v = [v,CS(1,i)]; + i = i+CS(2,i)+1; +end +labels = num2str(v'); + +%--------------------------------------------------- +function threeD = IsThreeD(cax) +%ISTHREED True for a contour3 plot +hp = findobj(cax,'type','patch'); +if isempty(hp), hp = findobj(gca,'type','line'); end +if ~isempty(hp), + % Assume a contour3 plot if z data not empty + threeD = ~isempty(get(hp(1),'zdata')); +else + threeD = 0; +end + diff --git a/functions/plotting/plotting/m_coasts.mat b/functions/plotting/plotting/m_coasts.mat new file mode 100644 index 0000000..eb4dc04 Binary files /dev/null and b/functions/plotting/plotting/m_coasts.mat differ diff --git a/functions/plotting/plotting/m_topo.mat b/functions/plotting/plotting/m_topo.mat new file mode 100644 index 0000000..3eca70d Binary files /dev/null and b/functions/plotting/plotting/m_topo.mat differ diff --git a/functions/plotting/plotting/mc_coords.m b/functions/plotting/plotting/mc_coords.m new file mode 100644 index 0000000..fee644b --- /dev/null +++ b/functions/plotting/plotting/mc_coords.m @@ -0,0 +1,159 @@ +function [longOUT,latOUT,phiVecOUT,thetaVecOUT]=mc_coords(optn,longIN,latIN,phiVecIN,thetaVecIN) +% MP_COORD Converts between coordinate systems based on different +% poles. Generally used in space physics to plot things in +% geomagnetic (dipole) coordinate systems. +% +% This function should not be used directly; instead it is +% is accessed by various high-level functions named M_*. +% +% Vector rotations can be carried out using the following: +% +% [latOUT,longOUT,phiVecOUT,thetaVecOUT]=M_GEO2MAG(latIN,longIN,phiVecIN,thetaVecIN) +% +% where +% +% thetaVecIN - north component of the vector in geographic coordinates +% phiVecIN - east component of the vector in geographic coordinates +% thetaVecOUT - north component of the vector in geomagnetic coordinates +% phiVecOUT - east component of the vector in geomagnetic coordinates +% + +% References: +% +% Hapgood, M.A., Space Physics Coordinate Transformations: +% A User Guide, Planet. Space Sci., Vol. 40, N0. 5, 1992. + +% Antti Pulkkinen, September 2001. +% R. Pawlowicz 9/01 - Vectorized, changed functionality, put into standard M_MAP form. +% +% 29/Sep/2005 - fixed bug (apparently no-one ever used this option before now!) +% +% 1 Nov 2012 - added IGRF2011 coords (thanks to Joe Kinrade) + +global MAP_PROJECTION MAP_COORDS + +pi180=pi/180; + + +switch optn + case 'name' + + longOUT.name={'geographic','IGRF2000-geomagnetic','IGRF2011-geomagnetic'}; + return; + + case 'parameters' + switch longIN + case 'geographic' + longOUT.name='geographic'; + longOUT.lambda = 0; + longOUT.phi = 0; + + case 'IGRF2000-geomagnetic' + g10=-29615; + g11=-1728; + h11=5186; + longOUT.name='IGRF2000-geomagnetic'; + longOUT.lambda= atan(h11/g11); + longOUT.phi = atan((g11*cos(longOUT.lambda)+h11*sin(longOUT.lambda))/g10); + + case 'IGRF2011-geomagnetic' %ADDED 2012-11-02 Joe Kinrade, Uni. of Bath + g10=-29496.5; %1st order IGFR2011 coefficient + g11=-1585.9; %2nd order + h11=4945.1; %3rd order + longOUT.name='IGRF2011-geomagnetic'; + longOUT.lambda= atan(h11/g11); + longOUT.phi = atan((g11*cos(longOUT.lambda)+h11*sin(longOUT.lambda))/g10); + + otherwise + error('Unrecognized coordinate system'); + end + return; + case 'geo2mag' + + % Rotation matrices + lambda=MAP_PROJECTION.coordsystem.lambda; + phi=MAP_PROJECTION.coordsystem.phi; + Tz=[ cos(lambda) sin(lambda) 0 ; + -sin(lambda) cos(lambda) 0 ; + 0 0 1 ]; + + Ty=[ cos(phi) 0 -sin(phi) ; + 0 1 0 ; + sin(phi) 0 cos(phi) ]; + T=Ty*Tz; + + case 'mag2geo' + % Rotation matrices + lambda=MAP_COORDS.lambda; + phi=MAP_COORDS.phi; + Tz=[ cos(-lambda) sin(-lambda) 0 ; + -sin(-lambda) cos(-lambda) 0 ; + 0 0 1 ]; + + Ty=[ cos(-phi) 0 -sin(-phi) ; + 0 1 0 ; + sin(-phi) 0 cos(-phi) ]; + T=Tz*Ty; + + +end + +[n,m]=size(latIN); + +% Degrees to radians, and make into rows. +latIN=(90 - latIN(:)')*pi180; +longIN=longIN(:)'*pi180; + + + +% Transformation to cartesian coordinates. +x=sin(latIN).*cos(longIN); +y=sin(latIN).*sin(longIN); +z=cos(latIN); + +% Rotations of the coordinates. +tmp=T*[x; y; z]; +xp=tmp(1,:);yp=tmp(2,:);zp=tmp(3,:); + +% Transformation back to spherical coordinates. Choosing the correct quadrant. +latOUT=acos(zp./sqrt(xp.^2+yp.^2+zp.^2)); +longOUT=atan2(yp,xp); + +if nargin > 3 + % Sign change due to sign convention used here. + thetaVecIN=-thetaVecIN(:)'; + phiVecIN=phiVecIN(:)'; + + % Computing vector rotations. + % First, transformation to cartesian coordinates. + + % Rotation matrix is + % [x] [ sLcG cLcG -sG ][radial] + % [y]=[ sLsG cLsG cG ][south ] + % [z] [ cL -sL 0 ][east ] + + % Radial component is zero. + Xvec= 0+ cos(latIN).*cos(longIN).*thetaVecIN - sin(longIN).*phiVecIN; + Yvec= 0+ cos(latIN).*sin(longIN).*thetaVecIN + cos(longIN).*phiVecIN; + Zvec= 0+ -sin(latIN).*thetaVecIN + 0; + + % Rotations of the system. + tmp=T*[Xvec;Yvec; Zvec]; + Xvecp=tmp(1,:);Yvecp=tmp(2,:);Zvecp=tmp(3,:); + + % Transformation back to spherical coordinates. + + thetaVecOUT=cos(latOUT).*cos(longOUT).*Xvecp + cos(latOUT).*sin(longOUT).*Yvecp -sin(latOUT).*Zvecp ; + phiVecOUT = -sin(longOUT).*Xvecp + cos(longOUT).*Yvecp +0 ; + + % Sign change due to sign convention used here. + thetaVecOUT=-reshape(thetaVecOUT,n,m); + phiVecOUT = reshape(phiVecOUT,n,m); +end + + +% Radians to degrees. +latOUT=90 - reshape(latOUT,n,m)/pi180; +longOUT=reshape(longOUT,n,m)/pi180; + + diff --git a/functions/plotting/plotting/mc_ellips.m b/functions/plotting/plotting/mc_ellips.m new file mode 100644 index 0000000..aa8ece0 --- /dev/null +++ b/functions/plotting/plotting/mc_ellips.m @@ -0,0 +1,20 @@ +function MAP_ELLIP=mc_ellips() +% +% Definitions of different ellipsoids +% + +% Rich Pawlowicz (rich@ocgy.ubc.ca) + +MAP_ELLIP = struct ( ... + 'normal', [1.0, 0], ... + 'sphere', [6370997.0, 0], ... + 'grs80' , [6378137.0, 1/298.257], ... + 'grs67' , [6378160.0, 1/247.247], ... + 'wgs84' , [6378137.0, 1/298.257], ... + 'wgs72' , [6378135.0, 1/298.260], ... + 'wgs66' , [6378145.0, 1/298.250], ... + 'wgs60' , [6378165.0, 1/298.300], ... + 'clrk66', [6378206.4, 1/294.97870], ... + 'clrk80', [6378249.1, 1/293.466], ... + 'intl24', [6378388.0, 1/297.000], ... + 'intl67', [6378157.5, 1/298.250]); diff --git a/functions/plotting/plotting/mp_azim.m b/functions/plotting/plotting/mp_azim.m new file mode 100644 index 0000000..2759f67 --- /dev/null +++ b/functions/plotting/plotting/mp_azim.m @@ -0,0 +1,290 @@ +function [X,Y,vals,labI]=mp_azim(optn,varargin) +% MP_AZIM Azimuthal projections +% This function should not be used directly; instead it is +% is accessed by various high-level functions named M_*. + + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 +% +% 13/5/97 - Added satellite perspective +% 1/6/97 - Another stab at removing some /0 errors. +% 10/8/00 - Rotation for projections? +% +% This software is provided "as is" without warranty of any kind. But +% it's mine, so you can't sell it. +% +% Mathematical formulas for the projections and their inverses are taken from +% +% Snyder, John P., Map Projections used by the US Geological Survey, +% Geol. Surv. Bull. 1532, 2nd Edition, USGPO, Washington D.C., 1983. +% +% These are azimuthal projections, best suited for circular areas. The +% stereographic is commonly used for polar regions. +% Stereographic - conformal +% Orthographic - neither conformal nor equal-area, but looks like globe +% with viewpoint at infinity. +% Azimuthal Equal-area - equal area, but not conformal (by Lambert) +% Azimuthal Equidistant - distance and direction from center are true +% Gnomonic - all great circles are straight lines. +% Satellite - a perspective view from a finite distance + +global MAP_PROJECTION MAP_VAR_LIST + +name={'Stereographic','Orthographic','Azimuthal Equal-area','Azimuthal Equidistant','Gnomonic','Satellite'}; + +pi180=pi/180; + + +switch optn + + case 'name' + X=name; + + case {'usage','set'} + X=char({[' ''' varargin{1} ''''],... + ' <,''lon'',center_long>',... + ' <,''lat'', center_lat>',... + ' <,''rad'', ( degrees | [longitude latitude] ) | ''alt'', alt_frac >',... + ' <,''rec'', ( ''on'' | ''off'' | ''circle'' )>',... + ' <,''rot'', degrees CCW>'}); + + case 'get' + + X=char([' Projection: ' MAP_PROJECTION.name ' (function: ' MAP_PROJECTION.routine ')'],... + [' center longitude: ' num2str(MAP_VAR_LIST.ulong) ],... + [' center latitude: ' num2str(MAP_VAR_LIST.ulat) ],... + [' radius/altitude : ' num2str(MAP_VAR_LIST.uradius) ],... + [' Rectangular border: ' MAP_VAR_LIST.rectbox ],... + [' Rotation angle: ' num2str(MAP_VAR_LIST.rotang) ]); + + case 'initialize' + + MAP_VAR_LIST=[]; + MAP_PROJECTION.name=varargin{1}; + MAP_VAR_LIST.ulong=0; + MAP_VAR_LIST.ulat=60; + MAP_VAR_LIST.rectbox='circle'; + MAP_VAR_LIST.uradius=90; + MAP_VAR_LIST.rotang=0; + MAP_VAR_LIST.ellipsoid='normal'; + k=2; + while k0 for points on the other side of the + % globe whereas c does not! + + % Also, we clip on rho even if we later clip on X/Y because in some projections (e.g. the + % orthographic) the X/Y locations wrap back. + if ~strcmp(varargin{4},'off') + vals = vals | cosc<=MAP_VAR_LIST.cosradius+eps*10; + [rho,Az]=mu_util('clip',varargin{4},rho,MAP_VAR_LIST.rhomax,cosc=MAP_VAR_LIST.xlims(2)-eps*10 | ... + Y<=MAP_VAR_LIST.ylims(1)+eps*10 | Y>=MAP_VAR_LIST.ylims(2)-eps*10; + [X,Y]=mu_util('clip',varargin{4},X,MAP_VAR_LIST.xlims(1),XMAP_VAR_LIST.xlims(2) | isnan(X),Y); + [Y,X]=mu_util('clip',varargin{4},Y,MAP_VAR_LIST.ylims(1),YMAP_VAR_LIST.ylims(2) | isnan(Y),X); + end + + case 'xy2ll' + + + rho=sqrt(varargin{1}.^2+varargin{2}.^2); + Z=exp(i*(atan2(varargin{2},varargin{1})-MAP_VAR_LIST.rotang*pi180)); + V1=rho.*real(Z); + V2=rho.*imag(Z); + + ir=rho==0; % To prevent /0 warnings when rho is 0 + rho(ir)=eps; + + switch MAP_PROJECTION.name + case name(1) + c=2*atan(rho/2); + case name(2) + c=asin(rho); + c(abs(rho)>1.0)=NaN; % points outside the map + case name(3) + c=2*asin(rho/2); + c(abs(rho)>2.0)=NaN; % points outside the map + case name(4) + c=rho; + case name(5) + c=atan(rho); + case name(6) + arg1=(MAP_VAR_LIST.uradius+1)./sqrt(1+(MAP_VAR_LIST.uradius./rho).^2); + c=asin(arg1) - atan(rho/MAP_VAR_LIST.uradius); + c(arg1>1.0)=NaN; + end + c(ir)=eps; % we offset this slightly so that the correct limit is achieved in the + % division below: + +% Y=(asin(cos(c)*sin(MAP_VAR_LIST.rlat) + ... +% cos(MAP_VAR_LIST.rlat)*sin(c).*varargin{2}./rho))/pi180; +% +% switch MAP_VAR_LIST.ulat, +% case 90, +% X=(MAP_VAR_LIST.rlong+atan2(varargin{1},-varargin{2}))/pi180; +% case -90, +% X=(MAP_VAR_LIST.rlong+atan2(varargin{1},varargin{2}))/pi180; +% otherwise +% X=(MAP_VAR_LIST.rlong+atan2( varargin{1}.*sin(c), ... +% cos(MAP_VAR_LIST.rlat)*cos(c).*rho - sin(MAP_VAR_LIST.rlat)*varargin{2}.*sin(c) ) )/pi180; +% end; + + % Can be problem if the argument is slightly larger than 1 - then the asin + % returns a complex number. + arg=cos(c)*sin(MAP_VAR_LIST.rlat) + ... + cos(MAP_VAR_LIST.rlat)*sin(c).*V2./rho; + arg=min(max(arg,-1),1); + + Y=(asin(arg))/pi180; + + switch MAP_VAR_LIST.ulat + case 90 + X=(MAP_VAR_LIST.rlong+atan2(V1,-V2))/pi180; + case -90 + X=(MAP_VAR_LIST.rlong+atan2(V1,V2))/pi180; + otherwise + X=(MAP_VAR_LIST.rlong+atan2( V1.*sin(c), ... + cos(MAP_VAR_LIST.rlat)*cos(c).*rho - sin(MAP_VAR_LIST.rlat)*V2.*sin(c) ) )/pi180; + end + + case 'xgrid' + + [X,Y,vals,labI]=mu_util('xgrid',MAP_VAR_LIST.longs,MAP_VAR_LIST.lats,varargin{1},31,varargin{2:3}); + + case 'ygrid' + + [X,Y,vals,labI]=mu_util('ygrid',MAP_VAR_LIST.lats,MAP_VAR_LIST.longs,varargin{1},91,varargin{2:3}); + + case 'box' + + [X,Y]=mu_util('box',31); + +end + + + diff --git a/functions/plotting/plotting/mp_conic.m b/functions/plotting/plotting/mp_conic.m new file mode 100644 index 0000000..01c70d7 --- /dev/null +++ b/functions/plotting/plotting/mp_conic.m @@ -0,0 +1,322 @@ +function [X,Y,vals,labI]=mp_conic(optn,varargin) +% MP_CONIC Conic projections +% This function should not be used directly; instead it is +% is accessed by various high-level functions named M_*. + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 +% +% This software is provided "as is" without warranty of any kind. But +% it's mine, so you can't sell it. +% +% Mathematical formulas for the projections and their inverses are taken from +% +% Snyder, John P., Map Projections used by the US Geological Survey, +% Geol. Surv. Bull. 1532, 2nd Edition, USGPO, Washington D.C., 1983. +% +% These are conic projections with two standard parallels, useful +% for showing limited areas at mid-latitudes. +% Albers equal-area - has an equal-area property +% Lambert conformal - is conformal +% +% 7/6/99 - fixed tendency to re-define .ulongs if .clong set by user +% 3/4/02 - added error if parallels are equidistant from equator (i.e. not conic projection really) +% 24/10/08 - added ellipsoidal earth computations for lambert conformal conic projection +% 16/10/09 - added ellipsoidal earth computations for albers conic projection +% 06/03/17 - changed 'false_origin' to 'origin' as option name, also it +% didn't work correctly with the 'normal' spheroid so this was +% fixed, AND changed the default parallels so they were at 25% +% and 75% limits instead of being a single parallel at the +% center to prevent blowups with the albers ellipsoidal +% projection AND made it work with SPHERE ellipsoid. + +global MAP_PROJECTION MAP_VAR_LIST + +MAP_ELLIP=mc_ellips; + +name={'Albers Equal-Area Conic','Lambert Conformal Conic'}; + +pi180=pi/180; + +switch optn + + case 'name' + + X=name; + + case {'usage','set'} + + m_names=fieldnames(MAP_ELLIP); + + X=char({[' ''' varargin{1} ''''],... + ' <,''lon'',[min max]>',... + ' <,''lat'',[min max]>',... + ' <,''clo'',value>',... + ' <,''par'',[lat1 lat2]>',... + ' <,''rec'', ( ''on'' | ''off'' )>',... + ' <,''ell'', one of',... + reshape(sprintf(' %6s',m_names{:}),15,length(m_names))',... + ' >',... + ' <,''ori'', [long lat]>'}); + + case 'get' + + X=char([' Projection: ' MAP_PROJECTION.name ' (function: ' MAP_PROJECTION.routine ')'],... + [' longitudes: ' num2str(MAP_VAR_LIST.ulongs) ' (centered at ' num2str(MAP_VAR_LIST.clong) ')'],... + [' latitudes: ' num2str(MAP_VAR_LIST.ulats) ],... + [' standard parallels: ' num2str(MAP_VAR_LIST.parallels) ],... + [' Rectangular border: ' MAP_VAR_LIST.rectbox ],... + [' ellipsoid: ' MAP_VAR_LIST.ellipsoid ],... + [' origin: ' num2str(MAP_VAR_LIST.origin) ]); + + case 'initialize' + + MAP_VAR_LIST=[]; + MAP_PROJECTION.name=varargin{1}; + MAP_VAR_LIST.ulongs=[-180 -50]; + MAP_VAR_LIST.ulats=[10 85]; + MAP_VAR_LIST.parallels=NaN; + MAP_VAR_LIST.clong=NaN; + MAP_VAR_LIST.origin=NaN; + MAP_VAR_LIST.rectbox='off'; + MAP_VAR_LIST.ellipsoid = 'normal'; + MAP_VAR_LIST.aussiemode=false; + k=2;longs_def=0; + while kMAP_VAR_LIST.ulongs(2) + MAP_VAR_LIST.ulongs=MAP_VAR_LIST.ulongs([2 1]); + end + case 'clo' + MAP_VAR_LIST.clong=varargin{k+1}; + case 'lat' + MAP_VAR_LIST.ulats=varargin{k+1}(:)'; + case 'par' + MAP_VAR_LIST.parallels=varargin{k+1}; + case 'rec' + switch lower(varargin{k+1}(1:2)) + case {'on','bo'} + MAP_VAR_LIST.rectbox='on'; + case 'of' + MAP_VAR_LIST.rectbox='on'; + otherwise + error(['m_proj: Unrecognized box option: ' varargin{k+1}]); + end + case 'ell' + MAP_VAR_LIST.ellipsoid=varargin{k+1}; + case 'ori' + MAP_VAR_LIST.origin=varargin{k+1}; + case 'fal' + error(' FALSE_ORIGIN option has been renamed to ORIGIN - Change your m_proj call! '); + case 'aus' % aussiemode - my joke + if strcmp(varargin{k+1},'on') + MAP_VAR_LIST.aussiemode=true; + end + otherwise + disp(['Unknown option: ' varargin{k}]); + end + k=k+2; + end + if isnan(MAP_VAR_LIST.clong) + if isnan(MAP_VAR_LIST.origin) + MAP_VAR_LIST.clong=mean(MAP_VAR_LIST.ulongs); + else + MAP_VAR_LIST.clong=MAP_VAR_LIST.origin(1); + end + elseif ~longs_def + MAP_VAR_LIST.ulongs=MAP_VAR_LIST.clong+[-180 180]; + end + if isnan(MAP_VAR_LIST.parallels), MAP_VAR_LIST.parallels=mean(MAP_VAR_LIST.ulats)*[1 1]+diff(MAP_VAR_LIST.ulats)*[-1/6 1/6]; end % change default mar/2017 + if isnan(MAP_VAR_LIST.origin), MAP_VAR_LIST.origin=[MAP_VAR_LIST.clong mean(MAP_VAR_LIST.parallels)]; end + + MAP_VAR_LIST.rlongs=MAP_VAR_LIST.ulongs*pi180; + MAP_VAR_LIST.rlats=MAP_VAR_LIST.ulats*pi180; + MAP_VAR_LIST.rparallels=MAP_VAR_LIST.parallels*pi180; + MAP_VAR_LIST.rorigin=MAP_VAR_LIST.origin*pi180; + + MAP_VAR_LIST.ellip=getfield(MAP_ELLIP,MAP_VAR_LIST.ellipsoid); + + % These are constants used by the projection formulas + + switch MAP_PROJECTION.name + case name(1) + if MAP_VAR_LIST.ellip(2)==0 % spherical + MAP_VAR_LIST.n=sum(sin(MAP_VAR_LIST.rparallels))/2; + if MAP_VAR_LIST.n==0 + error('Your parallels are equidistant from the equator - use a cylindrical projection!'); + end + MAP_VAR_LIST.C=cos(MAP_VAR_LIST.rparallels(1)).^2+2*MAP_VAR_LIST.n*sin(MAP_VAR_LIST.rparallels(1)); + MAP_VAR_LIST.rho0=MAP_VAR_LIST.ellip(1)*sqrt(MAP_VAR_LIST.C-2*MAP_VAR_LIST.n*sin( MAP_VAR_LIST.rorigin(2) ))/MAP_VAR_LIST.n; + else + e=sqrt(2*MAP_VAR_LIST.ellip(2)-MAP_VAR_LIST.ellip(2)^2); + m12=cos(MAP_VAR_LIST.rparallels)./sqrt(1-(e.*sin(MAP_VAR_LIST.rparallels)).^2); + q12=(1-e.^2)*(sin(MAP_VAR_LIST.rparallels)./(1-(e.*sin(MAP_VAR_LIST.rparallels)).^2) - ... + 1./(2*e)*log((1-e.*sin(MAP_VAR_LIST.rparallels))./(1+e.*sin(MAP_VAR_LIST.rparallels))) ); + q0= (1-e.^2)*(sin(MAP_VAR_LIST.rorigin(2))./(1-(e.*sin(MAP_VAR_LIST.rorigin(2))).^2) - ... + 1./(2*e)*log((1-e.*sin(MAP_VAR_LIST.rorigin(2)))./(1+e.*sin(MAP_VAR_LIST.rorigin(2)))) ); + if diff( MAP_VAR_LIST.rparallels )==0 + MAP_VAR_LIST.n=sin(MAP_VAR_LIST.rparallels(1)); + else + MAP_VAR_LIST.n=-diff(m12.^2)/diff(q12); + end + MAP_VAR_LIST.C=m12(1).^2 + MAP_VAR_LIST.n.*q12(1); + MAP_VAR_LIST.rho0=MAP_VAR_LIST.ellip(1)*sqrt(MAP_VAR_LIST.C-MAP_VAR_LIST.n*q0)/MAP_VAR_LIST.n; + end + case name(2) + if strcmp(MAP_VAR_LIST.ellipsoid,'normal') + if diff(MAP_VAR_LIST.parallels)==0 + MAP_VAR_LIST.n=sin(MAP_VAR_LIST.rparallels(1)); + else + MAP_VAR_LIST.n=-diff(log(cos(MAP_VAR_LIST.rparallels)))/diff(log(tan(MAP_VAR_LIST.rparallels/2+pi/4))); + end + MAP_VAR_LIST.F=cos(MAP_VAR_LIST.rparallels(1))/MAP_VAR_LIST.n* ... + tan(pi/4+MAP_VAR_LIST.rparallels(1)/2).^MAP_VAR_LIST.n; + MAP_VAR_LIST.rho0=MAP_VAR_LIST.F/tan(pi/4+ MAP_VAR_LIST.rorigin(2)/2).^MAP_VAR_LIST.n; + else + e=sqrt(2*MAP_VAR_LIST.ellip(2)-MAP_VAR_LIST.ellip(2)^2); + m12=cos(MAP_VAR_LIST.rparallels)./sqrt(1-(e.*sin(MAP_VAR_LIST.rparallels)).^2); + t12=tan(pi/4-MAP_VAR_LIST.rparallels/2)./( (1-e*sin(MAP_VAR_LIST.rparallels))./(1+e*sin(MAP_VAR_LIST.rparallels)) ).^(e/2); + tF=tan(pi/4-MAP_VAR_LIST.rorigin(2)/2)./( (1-e*sin(MAP_VAR_LIST.rorigin(2)))./(1+e*sin(MAP_VAR_LIST.rorigin(2))) ).^(e/2); + if diff(MAP_VAR_LIST.rparallels)==0 + MAP_VAR_LIST.n=sin(MAP_VAR_LIST.rparallels(1)); + else + MAP_VAR_LIST.n=diff(log(m12))/diff(log(t12)); + end + MAP_VAR_LIST.F=m12(1)/MAP_VAR_LIST.n/t12(1).^MAP_VAR_LIST.n; + MAP_VAR_LIST.rho0=MAP_VAR_LIST.ellip(1)*MAP_VAR_LIST.F*tF.^MAP_VAR_LIST.n; + end + end + + % check for a valid ellipsoid. if not, use the normalized sphere + + if ~isfield(MAP_ELLIP,MAP_VAR_LIST.ellipsoid) + MAP_VAR_LIST.ellipsoid = 'normal'; + end + + % Get X/Y and (if we are in a box) update the lat/long limits. + + mu_util('xylimits'); + if strcmp(MAP_VAR_LIST.rectbox,'on'), mu_util('lllimits'); end + + + case 'll2xy' + + long=varargin{1}; + lat=varargin{2}; + vals=zeros(size(long)); + + % Clip out-of-range values (lat/long box) + + if ~strcmp(MAP_VAR_LIST.rectbox,'on') && ~strcmp(varargin{4},'off') + vals=vals | long<=MAP_VAR_LIST.longs(1)+eps*10 | long>=MAP_VAR_LIST.longs(2)-eps*10 | ... + lat<=MAP_VAR_LIST.lats(1)+eps*10 | lat>=MAP_VAR_LIST.lats(2)-eps*10; + [long,lat]=mu_util('clip',varargin{4},long,MAP_VAR_LIST.longs(1),longMAP_VAR_LIST.longs(2),lat); + [lat,long]=mu_util('clip',varargin{4},lat,MAP_VAR_LIST.lats(1),latMAP_VAR_LIST.lats(2),long); + end + + switch MAP_PROJECTION.name + case name(1) + if MAP_VAR_LIST.ellip(2)==0 % spherical + rho=MAP_VAR_LIST.ellip(1)*sqrt(MAP_VAR_LIST.C-2*MAP_VAR_LIST.n*sin(lat*pi180))/MAP_VAR_LIST.n; + else + e=sqrt(2*MAP_VAR_LIST.ellip(2)-MAP_VAR_LIST.ellip(2)^2); + q= (1-e.^2)*(sin(lat*pi180)./(1-(e.*sin(lat*pi180)).^2) - ... + 1./(2*e)*log((1-e.*sin(lat*pi180))./(1+e.*sin(lat*pi180))) ); + rho=MAP_VAR_LIST.ellip(1)*sqrt(MAP_VAR_LIST.C-MAP_VAR_LIST.n*q)/MAP_VAR_LIST.n; + end + case name(2) + if strcmp(MAP_VAR_LIST.ellipsoid,'normal') + lat(lat==-90)=-89.999; % Prevents /0 problems in next line + rho=MAP_VAR_LIST.F ./ tan(pi/4+lat*pi180/2).^MAP_VAR_LIST.n; + else + e=sqrt(2*MAP_VAR_LIST.ellip(2)-MAP_VAR_LIST.ellip(2)^2); + t=tan(pi/4-lat*pi180/2)./( (1-e*sin(lat*pi180))./(1+e*sin(lat*pi180)) ).^(e/2); + rho=MAP_VAR_LIST.ellip(1)*MAP_VAR_LIST.F*t.^MAP_VAR_LIST.n; + end + end + theta=MAP_VAR_LIST.n*(long-MAP_VAR_LIST.origin(1))*pi180; + + X=real(rho.*sin(theta)); + Y=real(MAP_VAR_LIST.rho0-rho.*cos(theta)); + + % Clip out-of-range values (rectangular box) + + if strcmp(MAP_VAR_LIST.rectbox,'on') && ~strcmp(varargin{4},'off') + vals= vals | X<=MAP_VAR_LIST.xlims(1)+eps*10 | X>=MAP_VAR_LIST.xlims(2)-eps*10 | ... + Y<=MAP_VAR_LIST.ylims(1)+eps*10 | Y>=MAP_VAR_LIST.ylims(2)-eps*10; + [X,Y]=mu_util('clip',varargin{4},X,MAP_VAR_LIST.xlims(1),XMAP_VAR_LIST.xlims(2),Y); + [Y,X]=mu_util('clip',varargin{4},Y,MAP_VAR_LIST.ylims(1),YMAP_VAR_LIST.ylims(2),X); + end + if MAP_VAR_LIST.aussiemode, Y=-Y; X=-X; end + + + case 'xy2ll' + + pi180=pi/180; + + if MAP_VAR_LIST.aussiemode, varargin{2}=-varargin{2}; varargin{1}=-varargin{1}; end + switch MAP_PROJECTION.name + case name(1) + rho=sqrt(varargin{1}.^2+(MAP_VAR_LIST.rho0-varargin{2}).^2); + theta=atan(varargin{1}./(MAP_VAR_LIST.rho0-varargin{2})); + if MAP_VAR_LIST.ellip(2)==0 + Y=asin((MAP_VAR_LIST.C-(rho*MAP_VAR_LIST.n/MAP_VAR_LIST.ellip(1)).^2)/(2*MAP_VAR_LIST.n))/pi180; + else + e=sqrt(2*MAP_VAR_LIST.ellip(2)-MAP_VAR_LIST.ellip(2)^2); + q=(MAP_VAR_LIST.C - (rho.*MAP_VAR_LIST.n/MAP_VAR_LIST.ellip(1)).^2)./MAP_VAR_LIST.n; + % Y is computed iteratively + Y=asin(q/2); + for k=1:4 + Y=Y+(1-(e.*sin(Y)).^2).^2./(2*cos(Y)).*( q./(1-e.^2) - sin(Y)./(1-(e.*sin(Y)).^2) + ... + 1./(2*e)*log( (1-e*sin(Y))./(1+e*sin(Y)) ) ); + end + Y=Y/pi180; + end + % The pole is an arc in this projection, so for points inside that + % arc there is no inverse. If so, the math above can return complex + % values - instead set these to NaN + if ~isreal(Y) + Y(imag(Y)>1e-7)=NaN; + Y=real(Y); + end + + case name(2) + rho=sign(MAP_VAR_LIST.n)*sqrt(varargin{1}.^2+(MAP_VAR_LIST.rho0-varargin{2}).^2); + theta=atan(varargin{1}./(MAP_VAR_LIST.rho0-varargin{2})); + if strcmp(MAP_VAR_LIST.ellipsoid,'normal') + Y=(2*atan((MAP_VAR_LIST.F./rho).^(1/MAP_VAR_LIST.n))-pi/2)/pi180; + else + e=sqrt(2*MAP_VAR_LIST.ellip(2)-MAP_VAR_LIST.ellip(2)^2); + tp=(rho./MAP_VAR_LIST.ellip(1)/MAP_VAR_LIST.F).^(1./MAP_VAR_LIST.n); + % Y is computed iteratively + Y=pi/2 - 2*atan(tp); + for k=1:4 + Y=pi/2 - 2*atan(tp.*((1-e*sin(Y))./(1+e*sin(Y))).^(e/2) ); + end + Y=Y/pi180; + end + end + % Clip out-of-range values (lat/long box) + X=MAP_VAR_LIST.origin(1)+(theta/MAP_VAR_LIST.n)/pi180; + + case 'xgrid' + + [X,Y,vals,labI]=mu_util('xgrid',MAP_VAR_LIST.longs,MAP_VAR_LIST.lats,varargin{1},3,varargin{2:3}); + + case 'ygrid' + + [X,Y,vals,labI]=mu_util('ygrid',MAP_VAR_LIST.lats,MAP_VAR_LIST.longs,varargin{1},31,varargin{2:3}); + + case 'box' + + [X,Y]=mu_util('box',31); + +end + + + diff --git a/functions/plotting/plotting/mp_cyl.m b/functions/plotting/plotting/mp_cyl.m new file mode 100644 index 0000000..d5f63c8 --- /dev/null +++ b/functions/plotting/plotting/mp_cyl.m @@ -0,0 +1,172 @@ +function [X,Y,vals,labI]=mp_cyl(optn,varargin) +% MP_CYL Cylindrical projections +% This function should not be used directly; instead it is +% is accessed by various high-level functions named M_*. + + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 +% +% This software is provided "as is" without warranty of any kind. But +% it's mine, so you can't sell it. +% +% 21/5/97 - allow unequal lat limits for mercator and miler projections +% (to match with user's guide). +% +% Mathematical formulas for the projections and thie inverses are taken from +% +% Snyder, John P., Map Projections used by the US Geological Survey, +% Geol. Surv. Bull. 1532, 2nd Edition, USGPO, Washington D.C., 1983. +% +% These are cylindrical projections wrapped around the equator +% Mercator - conformal +% Miller - "looks" nice. +% Equidistant - basically plotting by lat/long, with distances stretched. +% +% Jan/18 - added option to put map into units of meters by specifying spheroid. +% May/18 - rescaled equidistant projection so it does distances properly +% (multiplied x by cos(lat) instead of dividing y by that value). + +global MAP_PROJECTION MAP_VAR_LIST + +MAP_ELLIP=mc_ellips; + +name={'Mercator','Miller Cylindrical','Equidistant Cylindrical'}; + +pi180=pi/180; + + +switch optn + + case 'name' + + X=name; + + case {'usage','set'} + + m_names=fieldnames(MAP_ELLIP); + + X=char({[' ''' varargin{1} ''''],... + ' <,''lon'',( [min max] | center)>',... + ' <,''lat'',( maxlat | [min max]>',... + ' <,''sph'', one of',... + reshape(sprintf(' %6s',m_names{:}),15,length(m_names))'} ); + + case 'get' + + X=char([' Projection: ' MAP_PROJECTION.name ' (function: ' MAP_PROJECTION.routine ')'],... + [' longitudes: ' num2str(MAP_VAR_LIST.ulongs) ],... + [' Latitudes: ' num2str(MAP_VAR_LIST.ulats) ],... + [' sphere: ' MAP_VAR_LIST.ellipsoid ]); + + case 'initialize' + + MAP_VAR_LIST=[]; + MAP_PROJECTION.name=varargin{1}; + MAP_VAR_LIST.ulongs=[-180 180]; + MAP_VAR_LIST.ulats=[-85 85]; + MAP_VAR_LIST.clong=0; + MAP_VAR_LIST.rectbox='off'; %always...(this is because we actually want lat/long grids + % to include the edges; this is turned off in rectboxes). + MAP_VAR_LIST.ellipsoid = 'normal'; + MAP_VAR_LIST.aussiemode=false; + + k=2; + while k1 + MAP_VAR_LIST.ulongs=varargin{k+1}(:)'; + MAP_VAR_LIST.clong=mean(MAP_VAR_LIST.ulongs); + else + MAP_VAR_LIST.clong=varargin{k+1}; + MAP_VAR_LIST.ulongs=MAP_VAR_LIST.clong+[-180 180]; + end + case 'lat' + MAP_VAR_LIST.ulats=varargin{k+1}(:)'; + case 'sph' + MAP_VAR_LIST.ellipsoid=varargin{k+1}; + case 'aus' % aussiemode - my joke + if strcmp(varargin{k+1},'on') + MAP_VAR_LIST.aussiemode=true; + end + otherwise + disp(['Unknown option: ' varargin{k}]); + end + k=k+2; + end + + if length(MAP_VAR_LIST.ulats)==1 + MAP_VAR_LIST.ulats=[-1 1]*abs(MAP_VAR_LIST.ulats(1)); + end + + if ~isfield(MAP_ELLIP,MAP_VAR_LIST.ellipsoid) + MAP_VAR_LIST.ellipsoid = 'normal'; + end + MAP_VAR_LIST.ellip=getfield(MAP_ELLIP,MAP_VAR_LIST.ellipsoid); + + mu_util('xylimits'); + + case 'll2xy' + + + long=varargin{1}; + lat=varargin{2}; + vals=zeros(size(long)); + + % Clip out-of-range values + + if ~strcmp(varargin{4},'off') + vals=vals | long<=MAP_VAR_LIST.longs(1)+eps*10 | long>=MAP_VAR_LIST.longs(2)-eps*10 | ... + lat<=MAP_VAR_LIST.lats(1)+eps*10 | lat>=MAP_VAR_LIST.lats(2)-eps*10; + [long,lat]=mu_util('clip',varargin{4},long,MAP_VAR_LIST.longs(1),longMAP_VAR_LIST.longs(2),lat); + [lat,long]=mu_util('clip',varargin{4},lat,MAP_VAR_LIST.lats(1),latMAP_VAR_LIST.lats(2),long); + end + + + switch MAP_PROJECTION.name + case name(1) + X=MAP_VAR_LIST.ellip(1)*(long-MAP_VAR_LIST.clong)*pi180; + Y=MAP_VAR_LIST.ellip(1)*atanh(sin(lat*pi180)); + case name(2) + X=MAP_VAR_LIST.ellip(1)*(long-MAP_VAR_LIST.clong)*pi180; + Y=MAP_VAR_LIST.ellip(1)*atanh(sin(lat*pi180*0.8))/0.8; + case name(3) + X=MAP_VAR_LIST.ellip(1)*(long-MAP_VAR_LIST.clong)*pi180*cos(mean(MAP_VAR_LIST.lats)*pi180); + Y=MAP_VAR_LIST.ellip(1)*lat*pi180; + end + if MAP_VAR_LIST.aussiemode, Y=-Y; X=-X; end; + + case 'xy2ll' + + if MAP_VAR_LIST.aussiemode, varargin{2}=-varargin{2};varargin{1}=-varargin{1}; end; + + + switch MAP_PROJECTION.name + case name(1) + X=varargin{1}/MAP_VAR_LIST.ellip(1)/pi180+mean(MAP_VAR_LIST.longs); + Y=90-2/pi180*atan(exp(-varargin{2}/MAP_VAR_LIST.ellip(1))); + case name(2) + X=varargin{1}/MAP_VAR_LIST.ellip(1)/pi180+mean(MAP_VAR_LIST.longs); + Y=(2/pi180*atan(exp(varargin{2}/MAP_VAR_LIST.ellip(1)*0.8))-90)/0.8; + case name(3) + X=varargin{1}/MAP_VAR_LIST.ellip(1)/pi180/cos(mean(MAP_VAR_LIST.lats)*pi180)+mean(MAP_VAR_LIST.longs); + Y=varargin{2}/MAP_VAR_LIST.ellip(1)/pi180; + end + + case 'xgrid' + + [X,Y,vals,labI]=mu_util('xgrid',MAP_VAR_LIST.longs,MAP_VAR_LIST.lats,varargin{1},3,varargin{2:3}); + + case 'ygrid' + + [X,Y,vals,labI]=mu_util('ygrid',MAP_VAR_LIST.lats,MAP_VAR_LIST.longs,varargin{1},3,varargin{2:3}); + + case 'box' + + [X,Y]=mu_util('box',2); + +end + + diff --git a/functions/plotting/plotting/mp_omerc.m b/functions/plotting/plotting/mp_omerc.m new file mode 100644 index 0000000..0eac2ac --- /dev/null +++ b/functions/plotting/plotting/mp_omerc.m @@ -0,0 +1,181 @@ +function [X,Y,vals,labI]=mp_omerc(optn,varargin) +% MP_TMERC Oblique Mercator projection +% This function should not be used directly; instead it is +% is accessed by various high-level functions named M_*. + + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 +% +% This software is provided "as is" without warranty of any kind. But +% it's mine, so you can't sell it. +% +% Mathematical formulas for the projections and thie inverses are taken from +% +% Snyder, John P., Map Projections used by the US Geological Survey, +% Geol. Surv. Bull. 1532, 2nd Edition, USGPO, Washington D.C., 1983. +% +% The oblique mercator is a cylindrical projection around an arbitrary +% great-circle route. This is a handy projection for coastlines and so +% forth. +% Oblique Mercator - cylindrical conformal + +% 22/Mar/2019 - handled longitudes in inverse mapping better (off by +% 360 issues) + +global MAP_PROJECTION MAP_VAR_LIST + +name={'Oblique Mercator'}; + +pi180=pi/180; + +switch optn + + case 'name' + + X=name; + + case {'usage','set'} + + X=char({[' ''' varargin{1} ''''],... + ' <,''lon'',[value1 value2]>',... + ' <,''lat'',[value1 value2]>',... + ' <,''asp'',value>',... + ' <,''dir'',( ''horizontal'' | ''vertical'' )'}); + + case 'get' + + X=char([' Projection: ' MAP_PROJECTION.name ' (function: ' MAP_PROJECTION.routine ')'],... + [' longitudes: ' num2str(MAP_VAR_LIST.ulongs)],... + [' latitudes: ' num2str(MAP_VAR_LIST.ulats) ],... + [' Aspect ratio: ' num2str(MAP_VAR_LIST.aspect)],... + [' Baseline direction ' MAP_VAR_LIST.direc]); + + case 'initialize' + + MAP_VAR_LIST=[]; + MAP_PROJECTION.name=varargin{1}; + MAP_VAR_LIST.ulongs=[-132 -125]; + MAP_VAR_LIST.ulats=[56 40]; + MAP_VAR_LIST.aspect=0.5; + MAP_VAR_LIST.direc='ver'; + MAP_VAR_LIST.rectbox='on'; % THis is always the case for this projection; it's just + % too difficult to comtemplate the other possibility + MAP_VAR_LIST.ellipsoid='normal'; + k=2; + while k=MAP_VAR_LIST.xlims(2)-eps*10 | ... + Y<=MAP_VAR_LIST.ylims(1)+eps*10 | Y>=MAP_VAR_LIST.ylims(2)-eps*10; + [X,Y]=mu_util('clip',varargin{4},X,MAP_VAR_LIST.xlims(1),XMAP_VAR_LIST.xlims(2),Y); + [Y,X]=mu_util('clip',varargin{4},Y,MAP_VAR_LIST.ylims(1),YMAP_VAR_LIST.ylims(2),X); + end + + case 'xy2ll' + + l_0=MAP_VAR_LIST.rpolelong+pi/2; + + switch MAP_VAR_LIST.direc(1:3) + case 'hor' + Y=asin( sin(MAP_VAR_LIST.rpolelat)*tanh(varargin{2}) ... + +cos(MAP_VAR_LIST.rpolelat)*sin(varargin{1})./cosh(varargin{2}) )/pi180; + X=(l_0+atan2( sin(MAP_VAR_LIST.rpolelat)*sin(varargin{1}) ... + -cos(MAP_VAR_LIST.rpolelat)*sinh(varargin{2}), cos(varargin{1}) ) )/pi180; + case 'ver' + Y=asin( sin(MAP_VAR_LIST.rpolelat)*tanh(-varargin{1}) ... + +cos(MAP_VAR_LIST.rpolelat)*sin(varargin{2})./cosh(-varargin{1}) )/pi180; + X=(l_0+atan2( sin(MAP_VAR_LIST.rpolelat)*sin(varargin{2}) ... + -cos(MAP_VAR_LIST.rpolelat)*sinh(-varargin{1}), cos(varargin{2}) ) )/pi180; + end + + % If we input in negative longitudes, the answer might come back wrapped 360 + % if mean(MAP_VAR_LIST.ulongs)<0 + % X(X>0)=X(X>0)-360; + % end + % Get longitudes in the range of inputs. Better handling of 360 wraps - Mar/2019 + ii=(X-mean(MAP_VAR_LIST.ulongs))>180; + if any(ii) X(ii)=X(ii)-360; end + ii=(X-mean(MAP_VAR_LIST.ulongs))<-180; + if any(ii) X(ii)=X(ii)+360; end + + case 'xgrid' + + [X,Y,vals,labI]=mu_util('xgrid',MAP_VAR_LIST.longs,MAP_VAR_LIST.lats,varargin{1},31,varargin{2:3}); + + + case 'ygrid' + + [X,Y,vals,labI]=mu_util('ygrid',MAP_VAR_LIST.lats,MAP_VAR_LIST.longs,varargin{1},31,varargin{2:3}); + + case 'box' + + [X,Y]=mu_util('box',2); + +end + + diff --git a/functions/plotting/plotting/mp_tmerc.m b/functions/plotting/plotting/mp_tmerc.m new file mode 100644 index 0000000..48cbe80 --- /dev/null +++ b/functions/plotting/plotting/mp_tmerc.m @@ -0,0 +1,268 @@ +function [X,Y,vals,labI]=mp_tmerc(optn,varargin) +% MP_TMERC Transverse Mercator projection +% This function should not be used directly; instead it is +% is accessed by various high-level functions named M_*. + + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 +% +% This software is provided "as is" without warranty of any kind. But +% it's mine, so you can't sell it. +% +% Mathematical formulas for the projections and their inverses are taken from +% +% Snyder, John P., Map Projections used by the US Geological Survey, +% Geol. Surv. Bull. 1532, 2nd Edition, USGPO, Washington D.C., 1983. +% +% It was handy to include both the TM (a cylindrical projection) and the +% so-called "pseudo-cylindrical" sinusoidal projection here, and since we have +% the sinusoidal, I started including the other "global" projections like the hammer. +% +% Transverse Mercator - cylindrical conformal +% Sinusoidal - cylindrical equal-area +% Gall-Peters - an area-conserving rectangular projection. +% Hammer-Aitoff - another equal-area projection (for global pics) + +% 7/2/98 - Added defaults for Sinusoidal projection +% 15/4/98 - Gall-Peters projection +% 8/8/98 - Hammer-Aitoff +% 17/8/98 - Mollweide projection. +% 7/6/99 - fixed tendency to re-define .ulongs if .clong set by user +% Mar/26/04 - 'varagin' to 'varargin' bug fixed (thanks to John Douglas) +% Jan/10/08 - Robinson projection +% May/17/12 - some fixes to Mollweide projection +% DEc/11/14 - 'clon' fixed to 'clong' in Robinson projection - thanks R. Watteaux. + +global MAP_PROJECTION MAP_VAR_LIST + +name={'Transverse Mercator','Sinusoidal','Gall-Peters','Hammer-Aitoff','Mollweide','Robinson'}; + +pi180=pi/180; + +% Table of scaling values needed for Robinson projection +% copied from the wikipedia entry for the robinson projection +Robscal=[... +00 1.0000 0.0000; +05 0.9986 0.0620; +10 0.9954 0.1240; +15 0.9900 0.1860; +20 0.9822 0.2480; +25 0.9730 0.3100; +30 0.9600 0.3720; +35 0.9427 0.4340; +40 0.9216 0.4958; +45 0.8962 0.5571; +50 0.8679 0.6176; +55 0.8350 0.6769; +60 0.7986 0.7346; +65 0.7597 0.7903; +70 0.7186 0.8435; +75 0.6732 0.8936; +80 0.6213 0.9394; +85 0.5722 0.9761; +90 0.5322 1.0000]; +Robscal(:,3)=Robscal(:,3)*0.5072; +Robscal_o=[flipud(Robscal) ; Robscal(2:end,:).*repmat([-1 1 -1],18,1) ]; +% Use splines to interpolate this to many more points - then we can use +% linear interpolate below and both the forward and reverse maps will be identical +Robscal=[-90:.05:90]'; +Robscal(:,2)=interp1(Robscal_o(:,1),Robscal_o(:,2),Robscal(:,1)); +Robscal(:,3)=interp1(Robscal_o(:,1),Robscal_o(:,3),Robscal(:,1)); + + +switch optn + + case 'name' + + X=name; + + case {'usage','set'} + + X=char({[' ''' varargin{1} ''''],... + ' <,''lon'',[min max]>',... + ' <,''lat'',[min max]>',... + ' <,''clo'',value>',... + ' <,''rec'', ( ''on'' | ''off'' )>'}); + + case 'get' + + X=char([' Projection: ' MAP_PROJECTION.name ' (function: ' MAP_PROJECTION.routine ')'],... + [' longitudes: ' num2str(MAP_VAR_LIST.ulongs) ' (centered at ' num2str(MAP_VAR_LIST.clong) ')'],... + [' latitudes: ' num2str(MAP_VAR_LIST.ulats) ],... + [' Rectangular border: ' MAP_VAR_LIST.rectbox ]); + + case 'initialize' + + MAP_VAR_LIST=[]; + MAP_PROJECTION.name=varargin{1}; + switch MAP_PROJECTION.name + case name(1) + MAP_VAR_LIST.ulongs=[-125 -122]; + MAP_VAR_LIST.ulats=[47 51]; + case name(2) + MAP_VAR_LIST.ulongs=[-90 30]; + MAP_VAR_LIST.ulats=[-65 65]; + case name(3) + MAP_VAR_LIST.ulongs=[30 390]; + MAP_VAR_LIST.ulats=[-65 65]; + case {name{4},name{5}} + MAP_VAR_LIST.ulongs=[-300 60]; + MAP_VAR_LIST.ulats=[-90 90]; + case {name{6}} + MAP_VAR_LIST.ulongs=[-180 180]; + MAP_VAR_LIST.ulats=[-90 90]; + end + MAP_VAR_LIST.clong=NaN; + MAP_VAR_LIST.rectbox='off'; + MAP_VAR_LIST.ellipsoid='normal'; + MAP_VAR_LIST.aussiemode=false; + k=2;longs_def=0; + while k=MAP_VAR_LIST.longs(2)-eps*10 | ... + lat<=MAP_VAR_LIST.lats(1)+eps*10 | lat>=MAP_VAR_LIST.lats(2)-eps*10; + [long,lat]=mu_util('clip',varargin{4},long,MAP_VAR_LIST.longs(1),longMAP_VAR_LIST.longs(2),lat); + [lat,long]=mu_util('clip',varargin{4},lat,MAP_VAR_LIST.lats(1),latMAP_VAR_LIST.lats(2),long); + end + + switch MAP_PROJECTION.name + case name(1) + B=cos(lat*pi180).*sin((long-MAP_VAR_LIST.clong)*pi180); + X=atanh(B); + Y=atan2(tan(lat*pi180),cos((long-MAP_VAR_LIST.clong)*pi180)) - MAP_VAR_LIST.clat*pi180; + case name(2) + Y=lat*pi180; + X=pi180*(long-MAP_VAR_LIST.clong).*cos(Y)+MAP_VAR_LIST.clong*pi180; + case name(3) + X=pi180*(long-MAP_VAR_LIST.clong)*cos(45*pi180); + Y=sin(lat*pi180)/cos(45*pi180); + case name(4) + z=sqrt((1+cos(lat*pi180).*cos((long-MAP_VAR_LIST.clong)*(pi180/2)))/2); + X=2*cos(lat*pi180).*sin((long-MAP_VAR_LIST.clong)*(pi180/2))./z; + Y=sin(lat*pi180)./z; + case name(5) + + % Have to use interative scheme to get intermediate variable "theta". + % cos(theta) changed to cos(2*theta) -thanks Zhigang Xu! Dec 2006. + % + %The program has a divide by zero + %error when theta= ±(pi/2). I've introduced the variable "notpoles" + %to handle this exception, although there are certainly other ways to + % deal with the special cases = Kevin Lewis Feb 2011 + % (my note - I'm just taking this as is) + % May/2012 - added a bunch more 'notpoles' references (thanks to M. Losch) + theta=(asin(lat/90)+lat*pi180)/2; + notpoles=find(abs(theta).001) && k<15 + theta(notpoles)=theta(notpoles)+dt(notpoles); % fixed May 2012 + dt=-(2*theta+sin(2*theta)-pi*sin(lat*pi180))./(1+cos(2*theta))/2; + k=k+1; + % fprintf('%f %f\n',max(theta(:))/pi180,max(abs(dt(:)))); + end + if k==15, warning('Iterative coordinate conversion is not converging!'); end + theta(notpoles)=theta(notpoles)+dt(notpoles); % fixed May 2012 + + X=((long-MAP_VAR_LIST.clong).*cos(theta)+MAP_VAR_LIST.clong)/90; + Y=sin(theta); + + case name(6) + Y=interp1(Robscal(:,1),Robscal(:,3),lat)*pi; + X=(long-MAP_VAR_LIST.clong)/180.*interp1(Robscal(:,1),Robscal(:,2),lat)*pi; + + end + + % Clip out-of-range values (rectboxes) + + if strcmp(MAP_VAR_LIST.rectbox,'on') && ~strcmp(varargin{4},'off') + vals= vals | X<=MAP_VAR_LIST.xlims(1) | X>=MAP_VAR_LIST.xlims(2) | ... + Y<=MAP_VAR_LIST.ylims(1) | Y>=MAP_VAR_LIST.ylims(2); + [X,Y]=mu_util('clip',varargin{4},X,MAP_VAR_LIST.xlims(1),XMAP_VAR_LIST.xlims(2),Y); + [Y,X]=mu_util('clip',varargin{4},Y,MAP_VAR_LIST.ylims(1),YMAP_VAR_LIST.ylims(2),X); + end + if MAP_VAR_LIST.aussiemode, Y=-Y; X=-X; end; + + case 'xy2ll' + + if MAP_VAR_LIST.aussiemode, varargin{2}=-varargin{2}; varargin{1}=-varargin{1}; end; + switch MAP_PROJECTION.name + case name(1) + D=varargin{2}+MAP_VAR_LIST.clat*pi180; + X=MAP_VAR_LIST.clong+atan2(sinh(varargin{1}),cos(D))/pi180; + Y=asin(sin(D)./cosh(varargin{1}))/pi180; + case name(2) + Y=varargin{2}/pi180; + X=MAP_VAR_LIST.clong+(varargin{1}-MAP_VAR_LIST.clong*pi180)./cos(varargin{2})/pi180; + case name(3) + X=varargin{1}/cos(45*pi180)/pi180 + MAP_VAR_LIST.clong; + Y=asin(varargin{2}*cos(45*pi180))/pi180; + case name(4) + z=sqrt(1-(varargin{1}/4).^2-(varargin{2}/2).^2); + X=MAP_VAR_LIST.clong+2*atan2(z.*varargin{1},2*(2*z.^2-1))/pi180; + Y=asin(varargin{2}.*z)/pi180; + case name(5) + theta=asin(varargin{2}); + Y=asin((2*theta+sin(2*theta))/pi)/pi180; + X=(varargin{1}*90-MAP_VAR_LIST.clong)./cos(theta)+MAP_VAR_LIST.clong; + case name(6) + Y=interp1(Robscal(:,3),Robscal(:,1),varargin{2}/pi); + X=varargin{1}./interp1(Robscal(:,1),Robscal(:,2),Y)*180/pi+MAP_VAR_LIST.clong; + end + + case 'xgrid' + + [X,Y,vals,labI]=mu_util('xgrid',MAP_VAR_LIST.longs,MAP_VAR_LIST.lats,varargin{1},31,varargin{2:3}); + + case 'ygrid' + + [X,Y,vals,labI]=mu_util('ygrid',MAP_VAR_LIST.lats,MAP_VAR_LIST.longs,varargin{1},31,varargin{2:3}); + + case 'box' + + [X,Y]=mu_util('box',31); + +end + + diff --git a/functions/plotting/plotting/mp_utm.m b/functions/plotting/plotting/mp_utm.m new file mode 100644 index 0000000..ad5c831 --- /dev/null +++ b/functions/plotting/plotting/mp_utm.m @@ -0,0 +1,373 @@ +function [X,Y,vals,labI]=mp_utm(optn,varargin) +% MP_UTM Universal Transverse Mercator projection +% This function should not be used directly; instead it is +% is accessed by various high-level functions named M_*. + +% mp_utm.m, Peter Lemmond (peter@whoi.edu) + +% created mp_utm.m 13Aug98 from mp_tmerc.m, v1.2d distribution, by: +% +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 +% +% This software is provided "as is" without warranty of any kind. But +% it's mine, so you can't sell it. +% +% Mathematical formulas for the projections and their inverses are taken from +% +% Snyder, John P., Map Projections used by the US Geological Survey, +% Geol. Surv. Bull. 1532, 2nd Edition, USGPO, Washington D.C., 1983. +% + +% 10/Dec/98 - PL added various ellipsoids. +% 17/May/12 - clarified hemisphere setting + +global MAP_PROJECTION MAP_VAR_LIST + +% define a structure of various ellipsoids. each has a name, and +% a vector consisting of equatorial radius and flattening. the first +% two are somewhat special cases. + +MAP_ELLIP = struct ( 'normal', [1.0, 0], ... + 'sphere', [6370997.0, 0], ... + 'grs80' , [6378137.0, 1/298.257], ... + 'grs67' , [6378160.0, 1/247.247], ... + 'wgs84' , [6378137.0, 1/298.257], ... + 'wgs72' , [6378135.0, 1/298.260], ... + 'wgs66' , [6378145.0, 1/298.250], ... + 'wgs60' , [6378165.0, 1/298.300], ... + 'clrk66', [6378206.4, 1/294.980], ... + 'clrk80', [6378249.1, 1/293.466], ... + 'intl24', [6378388.0, 1/297.000], ... + 'intl67', [6378157.5, 1/298.250]); + + +name={'UTM'}; + +switch optn + + case 'name' + + X=name; + + case {'usage','set'} + + m_names=fieldnames(MAP_ELLIP); + + X=char({[' ''' varargin{1} ''''],... + ' <,''lon'',[min max]>',... + ' <,''lat'',[min max]>',... + ' <,''zon'',value>',... + ' <,''hem'',[1|0] (0 for N)>',... + ' <,''ell'', one of',... + reshape(sprintf(' %6s',m_names{:}),15,length(m_names))',... + ' >',... + ' <,''rec'', ( ''on'' | ''off'' )>'}); + + case 'get' + + X=char([' Projection: ' MAP_PROJECTION.name ' (function: ' ... + MAP_PROJECTION.routine ')'],... + [' longitudes: ' num2str(MAP_VAR_LIST.ulongs) ],... + [' latitudes: ' num2str(MAP_VAR_LIST.ulats) ],... + [' zone: ' num2str(MAP_VAR_LIST.zone) ],... + [' hemisphere: ' num2str(MAP_VAR_LIST.hemisphere) ],... + [' ellipsoid: ' MAP_VAR_LIST.ellipsoid ], ... + [' Rectangular border: ' MAP_VAR_LIST.rectbox ]); + + + case 'initialize' + + MAP_VAR_LIST=[]; + MAP_PROJECTION.name=varargin{1}; + MAP_VAR_LIST.ulongs = [-72 -68]; + MAP_VAR_LIST.ulats = [40 44]; + MAP_VAR_LIST.zone = 0; % will be computed if not there + MAP_VAR_LIST.hemisphere = -1; + MAP_VAR_LIST.ellipsoid = 'wgs84'; + MAP_VAR_LIST.rectbox='off'; + k=2; + + while k=MAP_VAR_LIST.longs(2)-eps*10 | ... + lat<=MAP_VAR_LIST.lats(1)+eps*10 | lat>=MAP_VAR_LIST.lats(2)-eps*10; + [long,lat]=mu_util('clip',varargin{4},long,MAP_VAR_LIST.longs(1),longMAP_VAR_LIST.longs(2),lat); + [lat,long]=mu_util('clip',varargin{4},lat,MAP_VAR_LIST.lats(1),latMAP_VAR_LIST.lats(2),long); + end + + % do the forward transformation + + [X,Y] = mu_ll2utm(lat,long,MAP_VAR_LIST.zone,MAP_VAR_LIST.hemisphere, ... + getfield(MAP_ELLIP,MAP_VAR_LIST.ellipsoid)); + + % Clip out-of-range values (rectboxes) + + if strcmp(MAP_VAR_LIST.rectbox,'on') && ~strcmp(varargin{4},'off') + vals= vals | X<=MAP_VAR_LIST.xlims(1)+eps*10 | X>=MAP_VAR_LIST.xlims(2)-eps*10 | ... + Y<=MAP_VAR_LIST.ylims(1)+eps*10 | Y>=MAP_VAR_LIST.ylims(2)-eps*10; + [X,Y]=mu_util('clip',varargin{4},X,MAP_VAR_LIST.xlims(1),XMAP_VAR_LIST.xlims(2),Y); + [Y,X]=mu_util('clip',varargin{4},Y,MAP_VAR_LIST.ylims(1),YMAP_VAR_LIST.ylims(2),X); + end + + case 'xy2ll' + + [Y,X] = mu_utm2ll(varargin{1}, varargin{2}, MAP_VAR_LIST.zone, ... + MAP_VAR_LIST.hemisphere, getfield(MAP_ELLIP,MAP_VAR_LIST.ellipsoid)); + + case 'xgrid' + + [X,Y,vals,labI]=mu_util('xgrid',MAP_VAR_LIST.longs,MAP_VAR_LIST.lats,varargin{1},31,varargin{2:3}); + + case 'ygrid' + + [X,Y,vals,labI]=mu_util('ygrid',MAP_VAR_LIST.lats,MAP_VAR_LIST.longs,varargin{1},31,varargin{2:3}); + + case 'box' + + [X,Y]=mu_util('box',31); + +end + + +%------------------------------------------------------------------- + +function [x,y] = mu_ll2utm (lat,lon, zone, hemisphere,ellipsoid) +%mu_ll2utm Convert geodetic lat,lon to X/Y UTM coordinates +% +% [x,y] = mu_ll2utm (lat, lon, zone, hemisphere,ellipsoid) +% +% input is latitude and longitude vectors, zone number, +% hemisphere(N=0,S=1), ellipsoid info [eq-rad, flat] +% output is X/Y vectors +% +% see also mu_utm2ll, utmzone + + +% some general constants + +DEG2RADS = 0.01745329252; +RADIUS = ellipsoid(1); +FLAT = ellipsoid(2); +K_NOT = 0.9996; +FALSE_EAST = 500000; +FALSE_NORTH = 10000000; + +% check for valid numbers + +if (max(abs(lat)) > 90) + error('latitude values exceed 89 degree'); + return; +end + +if ((zone < 1) || (zone > 60)) + error ('utm zones only valid from 1 to 60'); + return; +end + +% compute some geodetic parameters + +lambda_not = ((-180 + zone*6) - 3) * DEG2RADS; + +e2 = 2*FLAT - FLAT*FLAT; +e4 = e2 * e2; +e6 = e4 * e2; +ep2 = e2/(1-e2); + +% some other constants, vectors + +lat = lat * DEG2RADS; +lon = lon * DEG2RADS; + +sinL = sin(lat); +tanL = tan(lat); +cosL = cos(lat); + +T = tanL.*tanL; +C = ep2 * (cosL.*cosL); +A = (lon - lambda_not).*cosL; +A2 = A.*A; +A4 = A2.*A2; +S = sinL.*sinL; + +% solve for N + +N = RADIUS ./ (sqrt (1-e2*S)); + +% solve for M + +M0 = 1 - e2*0.25 - e4*0.046875 - e6*0.01953125; +M1 = e2*0.375 + e4*0.09375 + e6*0.043945313; +M2 = e4*0.05859375 + e6*0.043945313; +M3 = e6*0.011393229; +M = RADIUS.*(M0.*lat - M1.*sin(2*lat) + M2.*sin(4*lat) - M3.*sin(6*lat)); + +% solve for x + +X0 = A4.*A/120; +X1 = 5 - 18*T + T.*T + 72*C - 58*ep2; +X2 = A2.*A/6; +X3 = 1 - T + C; +x = N.*(A + X3.*X2 + X1.* X0); + +% solve for y + +Y0 = 61 - 58*T + T.*T + 600*C - 330*ep2; +Y1 = 5 - T + 9*C + 4*C.*C; + +y = M + N.*tanL.*(A2/2 + Y1.*A4/24 + Y0.*A4.*A2/720); + + +% finally, do the scaling and false thing. if using a unit-normal radius, +% we don't bother. + +x = x*K_NOT + (RADIUS>1) * FALSE_EAST; + +y = y*K_NOT; +if (hemisphere) + y = y + (RADIUS>1) * FALSE_NORTH; +end + +return + + + +%------------------------------------------------------------------- + +function [lat,lon] = mu_utm2ll (x,y, zone, hemisphere,ellipsoid) +%mu_utm2ll Convert X/Y UTM coordinates to geodetic lat,lon +% +% [lat,lon] = mu_utm2ll (x,y, zone, hemisphere,ellipsoid) +% +% input is X/Y vectors, zone number, hemisphere(N=0,S=1), +% ellipsoid info [eq-rad, flat] +% output is lat/lon vectors +% +% see also mu_ll2utm, utmzone + + +% some general constants + +DEG2RADS = 0.01745329252; +RADIUS = ellipsoid(1); +FLAT = ellipsoid(2); +K_NOT = 0.9996; +FALSE_EAST = 500000; +FALSE_NORTH = 10000000; + +if ((zone < 1) || (zone > 60)) + error ('utm zones only valid from 1 to 60'); + return; +end + +% compute some geodetic parameters + +e2 = 2*FLAT - FLAT*FLAT; +e4 = e2 * e2; +e6 = e4 * e2; +eps = e2 / (1-e2); +em1 = sqrt(1-e2); +e1 = (1-em1)/(1+em1); +e12 = e1*e1; + +lambda_not = ((-180 + zone*6) - 3) * DEG2RADS; + +% remove the false things + +x = x - (RADIUS>1)*FALSE_EAST; +if (hemisphere) + y = y - (RADIUS>1)*FALSE_NORTH; +end + +% compute the footpoint latitude + +M = y/K_NOT; +mu = M/(RADIUS * (1 - 0.25*e2 - 0.046875*e4 - 0.01953125*e6)); +foot = mu + (1.5*e1 - 0.84375*e12*e1)*sin(2*mu) ... + + (1.3125*e12 - 1.71875*e12*e12)*sin(4*mu) ... + + (1.57291666667*e12*e1)*sin(6*mu) ... + + (2.142578125*e12*e12)*sin(8*mu); + +% some other terms + +sinF = sin(foot); +cosF = cos(foot); +tanF = tan(foot); + +N = RADIUS ./ sqrt(1-e2*(sinF.*sinF)); +T = tanF.*tanF; +T2 = T.*T; +C = eps * cosF.*cosF; +C2 = C.*C; +denom = sqrt(1-e2*(sinF.*sinF)); +R = RADIUS * em1*em1 ./ (denom.*denom.*denom); +D = x./(N*K_NOT); +D2 = D.*D; +D4 = D2.*D2; + +% can now compute the lat and lon + +lat = foot - (N.*tanF./R) .* (0.5*D2 - (5 + 3*T + 10*C - 4*C2 - 9*eps).*D4/24 ... + + (61 + 90*T + 298*C + 45*T2 - 252*eps - 3*C2) .* D4 .* D2/720); + +lon = lambda_not + (D - (1 + 2*T +C).*D2.*D/6 + ... + (5 - 2*C + 28*T - 3*C2 + 8*eps + 24*T2).*D4.*D./120)./cosF; + + +% convert back to degrees; + +lat=lat/DEG2RADS; +lon=lon/DEG2RADS; + +return diff --git a/functions/plotting/plotting/mu_coast.m b/functions/plotting/plotting/mu_coast.m new file mode 100644 index 0000000..0f5c229 --- /dev/null +++ b/functions/plotting/plotting/mu_coast.m @@ -0,0 +1,807 @@ +function [ncst,Area,k]=mu_coast(optn,varargin) +% MU_COAST Add a coastline to a given map. +% MU_COAST draw a coastline as either filled patches (slow) or +% lines (fast) on a given projection. It uses a coastline database with +% a resolution of about 1/4 degree. +% +% It is not meant to be called directly by the user, instead it contains +% code common to various functions in the m_map directory. +% +% Calling sequence is MU_COAST(option,arguments) where +% +% Option string +% c,l,i,h,f : Accesses various GSHHS databases. Next argument is +% GSHHS filename. +% +% u[ser] : Accesses user-specified coastline file (a mat-file of +% data saved from a previous MU_COAST call). Next argument +% is filename +% +% v[ector] : Uses input vector of data. Next argument is the +% data in the form of a nx2 matrix of [longitude latitude]. +% Patches must have first and last points the same. In a vector, +% different patches can be separated by NaN. +% +% d[efault] : Accesses default coastline. +% +% The arguments given above are then followed by (optional) arguments +% specifying lines or patches, in the form: +% +% optional arguments: , or +% 'line',. +% 'patch',. +% 'speckle',width,density,. +% +% If no or one output arguments are specified then the coastline is drawn, with +% patch handles returned. +% If 3 output arguments are specified in the calling sequence, then no drawing +% is done. This can be used to save subsampled coastlines for future use +% with the 'u' option, for fast drawing of multiple instances of a particular +% coastal region. +% +% +% +% See also M_PROJ, M_GRID + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 +% +% Notes: 15/June/98 - fixed some obscure problems that occured sometimes +% when using conic projections with large extents that +% crossed the 180-deg longitude line. +% 31/Aug/98 - added "f" gshhs support (Thanks to RAMO) +% 17/June/99 - 'line' option as per manual (thanks to Brian Farrelly) +% 3/Aug/01 - kludge fix for lines to South Pole in Antarctica (response +% to Matt King). +% 30/May/02 - fix to get gshhs to work in Antarctica. +% 15/Dec/05 - speckle additions +% 21/Mar/06 - handling of gshhs v1.3 (developed from suggestions by +% Martin Borgh) +% 26/Nov/07 - changed 'finite' to 'isfinite' after warnings +% 26/Sep/14 - added hierarchy flag to borders and rivers +% 13/Nov/14 - suggested matlab2014b graphics fix +% 8/Mar/17 - conic wrap-around not quite working right in a weird case when +% 'rectbox' was on. +% Nov/17 - redid a lot of the gshhs-related stuff +% +% This software is provided "as is" without warranty of any kind. But +% its mine, so you can't sell it. + + +global MAP_PROJECTION MAP_VAR_LIST + +% Have to have initialized a map first + +if isempty(MAP_PROJECTION) + disp('No Map Projection initialized - call M_PROJ first!'); + return; +end + + +% m_coasts.mat contains 3 variables: +% ncst: a Nx2 matrix of [LONG LAT] line segments, each of which form +% a closed contour (i.e. first and last points are the SAME), +% separated by NaN +% k=[find(isnan(ncst(:,1)))]; +% Area: a vector giving the areas of the different patches. Both ncst +% and Area should be ordered with biggest regions first. Area can +% be computed as follows: +% +% Area=zeros(length(k)-1,1); +% for i=1:length(k)-1, +% x=ncst([k(i)+1:(k(i+1)-1) k(i)+1],1); +% y=ncst([k(i)+1:(k(i+1)-1) k(i)+1],2); +% nl=length(x); +% Area(i)=sum( diff(x).*(y(1:nl-1)+y(2:nl))/2 ); +% end; +% +% Area should be >0 for land, and <0 for lakes and inland seas. + +switch optn(1) + case {'c','l','i','h','f'} + [ncst,k,Area]=get_coasts(optn,varargin{1}); + varargin(1)=[]; + case 'u' + eval(['load ' varargin{1} ' -mat']); + varargin(1)=[]; + case 'v' + ncst=[NaN NaN;varargin{1};NaN NaN]; + varargin(1)=[]; + k=[find(isnan(ncst(:,1)))]; % Get k + Area=ones(size(k)); % Make dummy Area vector (all positive). + otherwise + currloc=mfilename('fullpath'); % Octave has problems finding the file + load([currloc(1:end-8) 'm_coasts.mat']); + +end + + +% If all we wanted was to extract a sub-coastline, return. +if nargout==3 + return; +end + +% Handle wrap-arounds (not needed for azimuthal and oblique projections) + +switch MAP_PROJECTION.routine + case {'mp_cyl','mp_conic','mp_tmerc'} + if MAP_VAR_LIST.longs(2)<-180 + ncst(:,1)=ncst(:,1)-360; + elseif MAP_VAR_LIST.longs(1)>180 + ncst(:,1)=ncst(:,1)+360; + elseif MAP_VAR_LIST.longs(1)<-180 + Area=[Area;Area]; + k=[k;k(2:end)+k(end)-1]; + ncst=[ncst;[ncst(2:end,1)-360 ncst(2:end,2)]]; + % This is kinda kludgey - but sometimes adding all these extra points + % causes wrap-around in the conic projection, so we want to limit the + % longitudes to the range needed. However, we don't just clip them to + % min long because that can cause problems in trying to decide which way + % curves are oriented when doing the fill algorithm below. So instead + % I sort of crunch the scale, preserving topology. + % + % 12/Sep/2006 - in the gsshs_crude database we have a lot of long skinny + % things which interact badly with this - so I offset the scrunch 2 degrees + % away from the bdy + % + % Mar/2017 - OK, so somebody used a rectbox 'on' which gave a really wide range of + % lat/long, and it turns out I need to scale the *other* side as well! + nn=ncst(:,1)>MAP_VAR_LIST.longs(2)+2; % added 2017 + ncst(nn,1)=(ncst(nn,1)-MAP_VAR_LIST.longs(2)-2)/100+MAP_VAR_LIST.longs(2)+2; % " + nn=ncst(:,1)180 + Area=[Area;Area]; + k=[k;k(2:end)+k(end)-1]; + ncst=[ncst;[ncst(2:end,1)+360 ncst(2:end,2)]]; + % Ditto. + nn=ncst(:,1)>MAP_VAR_LIST.longs(2)+2; + ncst(nn,1)=(ncst(nn,1)-MAP_VAR_LIST.longs(2)-2)/100+MAP_VAR_LIST.longs(2)+2; + nn=ncst(:,1)xl(2),Y); + [Y,X]=mu_util('clip','on',Y,yl(1),Yyl(2),X); + oncearound=4; + case 'circle' + rl=MAP_VAR_LIST.rhomax; + [X,Y]=m_ll2xy(ncst(:,1),ncst(:,2),'clip','on'); + oncearound=2*pi; + end + + if ~MAP_PROJECTION.newgraphics + p_hand=zeros(length(k)-1,1); % Patch handles + else + p_hand=gobjects(length(k)-1,1); % Patch handles + end + + + for i=1:length(k)-1 + x=X(k(i)+1:k(i+1)-1); + fk=isfinite(x); + if any(fk) + y=Y(k(i)+1:k(i+1)-1);XX=x;YY=y; +%% if i>921, disp('pause 1'); pause; end; + nx=length(x); + if Area(i)<0, x=flipud(x);y=flipud(y); fk=flipud(fk); end +%clf +%line(x,y,'color','m'); + st=find(diff(fk)==1)+1; + ed=find(diff(fk)==-1); +%length(x), +%ed, +%st + if length(st)0 + p_hand(i)=m_hatch(xx,yy,'speckle',varargin{2:end}); + if ishandle(p_hand(i)),set(p_hand(i),'tag',[get(p_hand(i),'tag') '_lake']); end + else + p_hand(i)=m_hatch(xx,yy,'outspeckle',varargin{2:end}); + if ishandle(p_hand(i)),set(p_hand(i),'tag',[ get(p_hand(i),'tag') '_land']); end + end + end +%%%if i>921, disp(['paused-2 ' int2str(i)]);pause; end; + ed(1)=[];st(1)=[];edge2(1)=[];edge1(1)=[]; + else + xx=[xx;x(st(mi):ed(mi))]; + yy=[yy;y(st(mi):ed(mi))]; + ed(1)=ed(mi);st(mi)=[];ed(mi)=[]; + edge2(1)=edge2(mi);edge2(mi)=[];edge1(mi)=[]; + end +%%if i>921, disp(['paused-2 ' int2str(i)]);pause; end; + end + end + end + + otherwise + + % This handles the odd points required at the south pole by any Antarctic + % coastline by setting them to NaN (for lines only) + ii=ncst(:,2)<=-89.9; + if any(ii), ncst(ii,:)=NaN; end + + [X,Y]=m_ll2xy(ncst(:,1),ncst(:,2),'clip','on'); + + % Get rid of 2-point lines (these are probably clipped lines spanning the window) + fk=isfinite(X); + st=find(diff(fk)==1)+1; + ed=find(diff(fk)==-1); + k=find((ed-st)==1); + X(st(k))=NaN; + + p_hand=line(X,Y,varargin{:}); + +end + +ncst=p_hand; + +end +%----------------------------------------------------------------------- +function edg=c_edge(x,y) +% C_EDGE tests if a point is on the edge or not. If it is, it is +% assigned a value representing it's position oon the perimeter +% in the clockwise direction. For x/y or lat/long boxes, these +% values are +% 0 -> 1 on left edge +% 1 -> 2 on top +% 2 -> 3 on right edge +% 3 -> 4 on bottom +% For circular boxes, these values are the -ve of the angle +% from center. + +global MAP_VAR_LIST + +switch MAP_VAR_LIST.rectbox + case 'on' + xl=MAP_VAR_LIST.xlims; + yl=MAP_VAR_LIST.ylims; + case 'off' + xl=MAP_VAR_LIST.longs; + yl=MAP_VAR_LIST.lats; + case 'circle' + rl2=MAP_VAR_LIST.rhomax^2; +end + +edg=9999+zeros(length(x),1); +tol=1e-10; + +switch MAP_VAR_LIST.rectbox + case {'on','off'} + i=abs(x-xl(1))=2 + flaglim=str2num(optn(2)); +end + + +fid=fopen(file,'r','ieee-be'); + +if fid==-1 + warning(['Coastline file ' file ... + ' not found \n(Have you installed it? See the M_Map User''s Guide for details)' ... + '\n ---Using default coastline instead']); + load m_coasts + return +end + + +Area2=Area; + +% Read the File header + +[cnt,g]=get_gheader(fid); + + +l=0; +while cnt>0 + + C=fread(fid,g.N*2,'int32'); % Read all points in the current segment. + + % For versions > 12 there are 2 Antarctics - ice-line and grounding line, + % also they changed the limits from 0-360 to -180 to 180. + if g.ver>14 + switch g.level + case 6 + g.level=flaglim+1; % ice line - don't show + case 5 + g.level=1; % grounding line - use this. + end + else + %For Antarctica the lime limits are 0 to 360 (exactly), thus c==0 and the + %line is not chosen for (e.g. a conic projection of part of Antarctica) + % Fix 30may/02 + if g.extentE==360e6, g.extentE=g.extentE-1; end + end + + a=rlim>llim; % Map limits cross longitude jump? (a==1 is no) + b=g.greenwich<65536; % Cross boundary? (b==1 if no). + c=llimrem(g.extentW+360e6,360e6); + e=tlim>g.extentS & blim180;(dx>356) - (dx<-356)]); + + % Antarctic is a special case - extend contour to make nice closed polygon + % that doesn't surround the pole. + if g.ver<15 + % Range from 0-360 + if abs(x(1))<1 && abs(y(1)+68.9)<1 + y=[-89.9;-78.4;y(x<=-180);y(x>-180); -78.4;-89.9*ones(18,1)]; + x=[ 180; 180 ;x(x<=-180)+360;x(x>-180);-180; [-180:20:160]']; + end + else + % new version is from -180 to 180 + if abs(x(1))==180 && y(1)<-76 + y=[-89.9;-78.4;y; -78.4;-89.9*ones(19,1)]; + x=[ 180; 180 ;x; -180; [-180:20:180]']; + end + end + + + %plot(x,y);pause; + + % First and last point should be the same IF THIS IS A POLYGON + % if the Area=0 then this is a line, and don't add points! + + if g.area>0 + + if x(end)~=x(1) || y(end)~=y(1) % First and last points should be the same + x=[x;x(1)];y=[y;y(1)]; + end + + % get correct curve orientation for patch-fill algorithm. + + Area2(l)=sum( diff(x).*(y(1:(end-1))+y(2:end))/2 ); % Area "on the page" + Area(l)=g.area/10; % Area "on the globe" + + if rem(g.level,2)==0 % Make lakes (2) and islands (1) differently oriented + Area(l)=-abs(Area(l)); + if Area2(l)>0, x=x(end:-1:1);y=y(end:-1:1); end + else + if Area2(l)<0, x=x(end:-1:1);y=y(end:-1:1); end + end + + else + % Later on 2 point lines are clipped so we want to avoid that + if length(x)==2 + x=[x(1);mean(x);x(2)]; + y=[y(1);mean(y);y(2)]; + end + end + + % Here we try to reduce the number of points and clip them + % close to map limits (if they are too far away this can cause + % problems with some projections as they wrap around into the + % wrong place) + + [cx,cy]=clip_to_lims(x,y,m,decfac); + + k(l+1)=k(l)+length(cx)+1; + ncst(k(l)+1:k(l+1),:)=[cx,cy;NaN NaN]; + + % This is a little tricky...the filling algorithm expects data to be in the + % range -180 to 180 deg long. However, there are some land parts that cut across + % this divide so they appear at +190 but not -170. This causes problems later... + % so as a kludge I replicate some of the problematic features at 190-360=-170. + % I cut out the problematic points only, make sure the first and last + % points are the same, and then add this curve to ncst + if max(x)>180 + ii=find(x>179);ii=[ii;ii(1)]; + [cx,cy]=clip_to_lims(x(ii)-360,y(ii),m,decfac); + l=l+1; + k(l+1)=k(l)+length(cx)+1; + ncst(k(l)+1:k(l+1),:)=[cx,cy;NaN NaN]; + end + + %plot(ncst(:,1),ncst(:,2));drawnow; + end + [cnt,g]=get_gheader(fid); +end + +fclose(fid); + +%plot(ncst(:,1),ncst(:,2));pause;clf; + +ncst((k(l+1)+1):end,:)=[]; % get rid of unused part of data matrices +Area((l+1):end)=[]; +k((l+2):end)=[]; +%%%fprintf('Size ncst: %d, Area: %d, k %d\n',length(ncst),length(Area),length(k)) + + +end + +function [x,y]=clip_to_lims(x,y,m,decfac) +% Look for points outside the lat/long boundaries, and then decimate them + % by a factor of about 'decfac' (don't get rid of them completely because that + % can sometimes cause problems when polygon edges cross curved map edges). + + tol=.2; + + % Do y limits, then x so we can keep corner points. + + nn=(y>m.tlim+tol) | (y0)+([diff(nn);0]<0))); + nn([1 end])=0; + % decimate vigorously + nn=nn & rem(1:length(nn),decfac)'~=0; + x(nn)=[];y(nn)=[]; + + if m.rlim>m.llim % no wraparound + % sections of line outside lat/long limits + nn=(x>m.rlim+tol | xm.blim; + else % wraparound case + nn=(x>m.rlim+tol & xm.blim; + end + nn=logical(nn-min(1,([0;diff(nn)]>0)+([diff(nn);0]<0)));nn([1 end])=0; + nn=nn & rem(1:length(nn),decfac)'~=0; + x(nn)=[];y(nn)=[]; + + % Move all points "near" to map boundaries. + % I'm not sure about the wisdom of this - it might be better to clip + % to the boundaries instead of moving. Hmmm. + + y(y>m.tlim+tol)=m.tlim+tol; + y(ym.llim % Only clip long bdys if I can tell I'm on the right + % or left (i.e. not in wraparound case) + x(x>m.rlim+tol)=m.rlim+tol; + x(x> 8) & 255: Values: Should be 7 for GSHHS release 7 (i.e., version 2.0) +% 12 for version 2.2 +% 15 for 2.3.6 +% * 3rd byte: greenwich = (flag >> 16) & 1: Values: Greenwich is 1 if Greenwich is crossed +% * 4th byte: source = (flag >> 24) & 1: Values: 0 = CIA WDBII, 1 = WVS +% * 4th byte: river = (flag >> 25) & 1: Values: 0 = not set, 1 = river-lake and level = 2 +% */ +% int west, east, south, north; /* min/max extent in micro-degrees */ +% int area; /* Area of polygon in 1/10 km^2 */ +% int area_full; /* Area of original full-resolution polygon in 1/10 km^2 */ +% int container; /* Id of container polygon that encloses this polygon (-1 if none) */ +% int ancestor; /* Id of ancestor polygon in the full resolution set that was the source of this polygon (-1 if none) + + +% Now, in the calling code I have to use A(2),A(3),A(5-7), A(8), A(9) from original. + +[A,cnt]=fread(fid,8,'int32'); + +if cnt<8 % This gets triggered by the EOF + g=[]; + return; +end + +g.ver=bitand(bitshift(A(3),-8),255); + +if g.ver==0 % then its an old version, fake it to look new + + % This works for version 1.2, but not 1.3. + + [A2,cnt2]=fread(fid,1,'int32'); + A=[A;A2]; + + if (cnt+cnt2)==9 && A(9)==3 % we have version 1.3, this would be one of 0,1,65535,65536 in v 1.2 + % Read one more byte + A2=fread(fid,1,'int32'); + % This is the easiest way not to break existing code. + A(9)=A2; % one of 0,1,65536,65537 + end + +elseif g.ver>=7 % After v2.0 some more bytes around for original area and container/ancerstor IDs + + A2=fread(fid,3,'int32'); + +end + +% a newest versions +g.id=A(1); +g.N=A(2); +g.level=bitand(A(3),255); +g.greenwich=bitand(bitshift(A(3),-16),255)*65536; +g.source=bitand(bitshift(A(3),-24),255); +A(3)=g.level; +A(9)=g.greenwich; + +g.extentW=A(4); +g.extentE=A(5); +g.extentS=A(6); +g.extentN=A(7); +g.area=A(8); + + + +end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/functions/plotting/plotting/mu_util.m b/functions/plotting/plotting/mu_util.m new file mode 100644 index 0000000..051d38f --- /dev/null +++ b/functions/plotting/plotting/mu_util.m @@ -0,0 +1,371 @@ +function varargout=mu_util(optn,varargin) +% MU_UTIL Various utility routines +% This function should not be used directly; instead it is +% is accessed by other high- and low-level functions. + +% MU_UTIL is basically a driver for a number of lower-level routines collected +% together for convenience. They are specified by the first argument: +% 'clip' - clipping routine +% 'axisticks' - generates a "nice" set of ticks, optimized for degrees/minutes on maps +% angles of the circle. +% 'x/ygrid' - generates the lines for axis grids +% 'xylimits' - finds the x/y limits for a given map +% 'lllimits' - finds the lat/long limits for a given map (usually for rectboxes) +% 'box' - returns a line around the boundaries of the map. + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 4/April/97 +% +% This software is provided "as is" without warranty of any kind. But +% it's mine, so you can't sell it. + +% 31/Mar/04 - added a fix in m_rectgrid that caused problems when a map +% boundary coincided with a grid line. +% 26/Oct/07 - fixed the same problem when it occurred near SOUTH pole! +% 8/Sep/13 - added 'tickstyle' to grid generation + +switch optn + case 'clip' + [varargout{1},varargout{2}]=m_clip(varargin{:}); + case 'axisticks' + varargout{1}=m_getinterval(varargin{:}); + case {'xgrid','ygrid'} + [varargout{1},varargout{2},varargout{3},varargout{4}]=m_rectgrid(optn,varargin{:}); + case 'xylimits' + m_getxylimits; + case 'lllimits' + m_getlllimits; + case 'box' + [varargout{1},varargout{2}]=m_box(varargin{:}); + +end + + + +%--------------------------------------------------------- +function [Xc,Yc]=m_clip(cliptype,X,Xedge,indx,Y) +% M_CLIP performs clipping of data. Columns of points are +% assumed to be lines; the first points outside the +% clip area are recomputed to lie on the edge of the +% region; others are converted to either NaN or +% edge points depending on CLIPTYPE. +% +% indx = 0 for points inside the clip region, 1 +% for those outside +% +% 'on' - replaces points outside with NaN, but interpolates +% to provide points right on the border. +% 'patch' - replaces points outside with nearest border point +% 'point' - does no interpolation (just checks in/out) +% +% In general m_clip will be called 4 times, since it solves a 1-edge problem. + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 4/April/97 + +Xc=X; +Yc=Y; + +if ~strcmp(cliptype,'point') + + % Find regions where we suddenly come into the area + % (indices go from 1 to 0) + + [i,j]=find(diff(indx)==-1); + + if any(i) + I=i+(j-1)*size(X,1); % 1-d addressing + + % Linearly interpolate to boundary + + bt=(X(I+1)-X(I)); + ibt=abs(bt)<5*eps; + if any(ibt), bt(ibt)=1*eps; end % In these cases the delta(Y) also = 0, so we just want + % to avoid /0 warnings. + Yc(I)=Y(I)+(Xedge-X(I)).*(Y(I+1)-Y(I))./bt; + Yc(I(ibt))=(Y(I(ibt))+Y(I(ibt)+1))/2; + Xc(I)=Xedge; + indx(I(isfinite(Yc(I))))=0; + end + + % Find regions where we suddenly come out of the area + % (indices go from 0 to 1) + + + [i,j]=find(diff(indx)==1); + if any(i) + + I=i+(j-1)*size(X,1); + + bt=(X(I+1)-X(I)); + ibt=abs(bt)<5*eps; + if any(ibt), bt(ibt)=eps; end % In these cases the delta(Y) also = 0, so we just want + % to avoid /0 warnings. + + Yc(I+1)=Y(I)+(Xedge-X(I)).*(Y(I+1)-Y(I))./bt; + Yc(I(ibt)+1)=(Y(I(ibt))+Y(I(ibt)+1))/2; + Xc(I+1)=Xedge; + indx(I(isfinite(Yc(I+1)))+1)=0; + end + +end + +switch cliptype + case {'on','point'} + Xc(indx)=NaN; + Yc(indx)=NaN; + case 'patch' + Xc(indx)=Xedge; +end + + +%-------------------------------------------------------------------------- +function gval=m_getinterval(gmin,gmax,gtick,gtickstyle) +% M_GETINTERVAL picks nice spacing for grid ticks +% This occurs when the following call is made: +% TICKS=M_GRID('axisticks',MIN,MAX,APPROX_NUM_TICKS) +% + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 +% +% 9/Apr/98 - changed things so that max/min limits are not automatically +% added (this feature made map corners messy sometimes) + +% If ticks are specified, we just make sure they are within the limits +% of the map. + +if length(gtick)>1 + gval=[gtick(gtick(:)>=gmin & gtick(:)<=gmax)]; + +% Otherwise, we try to fit approximately gtick ticks in the interval +else + + if gtick>2 + + exactint=(gmax-gmin)/(gtick-1)*60; %interval in minutes + + if strcmp(gtickstyle,'dm') || strcmp(gtickstyle,'da') + % These are the intervals which we will allow (they are "nice" in the sense + % that they come to various even multiples of minutes or degrees) + niceints=[0.01 0.02 0.05 ... + 0.1 0.2 0.25 0.5 ... + 1 2 3 4 5 6 10 12 15 20 30 ... + 60*[1 2 3 4 5 6 8 9 10 12 15 18 20 25 30 40 50 60 100 120 180]]; + elseif strcmp(gtickstyle,'dd') + % these are decimal intervals + niceints=60*[1/1000 1/500 1/400 1/250 1/200 1/100 ... + 1/50 1/40 1/25 1/20 1/10 1/5 1/4 1/3 1/2 ... + 1 2 3 4 5 6 8 9 10 12 15 18 20 25 30 40 50 60 100 120 180]; + else + error(['bad tickstyle - ''' gtickstyle '''']); + end + + + [dun,I]=min(abs(niceints-exactint)); + + gval=niceints(I)/60*[ceil(gmin*60/niceints(I)):fix(gmax*60/niceints(I))]; + + gval=[gval(gval>=gmin & gval<=gmax) ]; + else + gval=[gmin gmax]; + end +end + + +%-------------------------------------------------------------- +function [X,Y,vals,labI]=m_rectgrid(direc,Xlims,Ylims,Nx,Ny,label_pos,tickstyle) +% M_RECTGRID This handles some of the computations involved in creating grids +% for rectangular maps. Essentially we make our "first guess" using the +% lat/long limits. Then these curves are clipped to the boundaries, after +% which we use the clip points as "new" boundaries and recompute the lines. + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 4/April/97 + +global MAP_PROJECTION MAP_VAR_LIST + +Ny1=Ny-1; +Ny2=Ny*2; +Ny21=Ny2-1; + +% First try some wildly oversampled lines (not including the boundaries) + +vals=mu_util('axisticks',Xlims(1),Xlims(2),Nx,tickstyle); + +if strcmp(MAP_VAR_LIST.rectbox,'on') || strcmp(MAP_VAR_LIST.rectbox,'circle') + + % We don't want the end limits here. + if vals(end) == Xlims(2), vals(end) = []; end + if vals(1) == Xlims(1), vals(1) = []; end + + if direc(1)=='x' + [lg,lt]=meshgrid(vals,Ylims(1)+diff(Ylims)*[0:1/Ny1:1]); + else + [lt,lg]=meshgrid(vals,Ylims(1)+diff(Ylims)*[0:1/Ny1:1]); + end + + % But sneakily we clip them in transforming, so we end up with finite values only + % inside the axis limits + + [X,Y]=feval(MAP_PROJECTION.routine,'ll2xy',lg,lt,'clip','on'); + + % Now we find the first/last unclipped values; these will be our correct starting points. + % (Note I am converting to one-dimensional addressing). + + istart=sum(cumsum(isfinite(X))==0)+1+[0:size(X,2)-1]*size(X,1); + iend=size(X,1)-sum(cumsum(isfinite(flipud(X)))==0)+[0:size(X,2)-1]*size(X,1); + + % Now, in the case where map boundaries coincide with limits it is just possible + % that an entire column might be NaN...so in this case make up something just + % slight non-zero. (31/Mar/04) + + i3=find(iend==0); + if any(i3), istart(i3)=1; iend(i3)=1; end + + % do same fix for istart (thanks Ben Raymond for finding this bug) + i3=find(istart>prod(size(X))); + if any(i3), istart(i3)=1; iend(i3)=1; end + + % Now go back and find the lat/longs corresponding to those points; these are our new + % starting points for the lines (Note that the linear interpolation for clipping at boundaries + % means that they will not *quite* be the exact longitudes due to curvature, but they should + % be very close. + + if direc(1)=='x' + + [lgs,lts]=feval(MAP_PROJECTION.routine,'xy2ll',X(istart),Y(istart),'clip','off'); + [lgs,lte]=feval(MAP_PROJECTION.routine,'xy2ll',X(iend),Y(iend),'clip','off'); + + % Finally compute the lines within those limits (these *may* include some out-of-bounds points + % depending on the geometry of the situation; these are converted to NaN as usual. + + [X,Y]=feval(MAP_PROJECTION.routine,'ll2xy',vals(ones(Ny2,1),:),... + lts(ones(Ny2,1),:)+[0:1/Ny21:1]'*(lte-lts),'clip','on'); + + else + + [lgs,lts]=feval(MAP_PROJECTION.routine,'xy2ll',X(istart),Y(istart),'clip','off'); + [lge,lts]=feval(MAP_PROJECTION.routine,'xy2ll',X(iend),Y(iend),'clip','off'); + + % Longitudes should be increasing here, but we can run into wrap problems after + % the tansformations back and forth. It is for this line that I need to make + % long-lims just a tad less than 360 when really they should be 360 (in m_lllimits) + + lge(lge<=lgs)=lge(lge<=lgs)+360; + + [X,Y]=feval(MAP_PROJECTION.routine,'ll2xy',lgs(ones(Ny2,1),:)+[0:1/Ny21:1]'*(lge-lgs),... + vals(ones(Ny2,1),:),'clip','on'); + + end + +else + if direc(1)=='x' + [lg,lt]=meshgrid(vals,Ylims(1)+diff(Ylims)*[0:1/Ny1:1]); + else + [lt,lg]=meshgrid(vals,Ylims(1)+diff(Ylims)*[0:1/Ny1:1]); + end + [X,Y]=feval(MAP_PROJECTION.routine,'ll2xy',lg,lt,'clip','off'); + +end + +switch label_pos + case {'left','bottom','west','south'} + labI=1; + case 'middle' + labI=round(size(X,1)/2+1/2); + case {'right','top','east','north'} + labI=size(X,1); +end + + + +%-------------------------------------------------------------------------------- +function m_getxylimits +% M_GET_LIMITS Converts X/Y limits to lat/long limits +% This is a chunk of code that is needed for most projections. + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 4/April/97 + +global MAP_PROJECTION MAP_VAR_LIST + +% Start with the user-specified lat/longs. + +MAP_VAR_LIST.lats=MAP_VAR_LIST.ulats; +MAP_VAR_LIST.longs=MAP_VAR_LIST.ulongs; + +% Now, let's get the map x/ylims +bX=MAP_VAR_LIST.longs(1)+diff(MAP_VAR_LIST.longs)*[0:1/30:1]; +bY=MAP_VAR_LIST.lats(1)+diff(MAP_VAR_LIST.lats)*[0:1/30:1]; +bX=[bX MAP_VAR_LIST.longs(2*ones(1,31)) fliplr(bX) MAP_VAR_LIST.longs(ones(1,31)) ]; +bY=[MAP_VAR_LIST.lats(ones(1,31)) bY MAP_VAR_LIST.lats(2*ones(1,31)) fliplr(bY) ]; +[X,Y]=feval(MAP_PROJECTION.routine,'ll2xy',bX,bY,'clip','off'); +MAP_VAR_LIST.xlims=[min(X) max(X)]; +MAP_VAR_LIST.ylims=[min(Y) max(Y)]; + + +%------------------------------------------------------------------------------- +function m_getlllimits +% M_GET_LIMITS Converts X/Y limits to lat/long limits +% This is a chunk of code that is needed for most projections. + +% Rich Pawlowicz (rich@ocgy.ubc.ca) 4/April/97 + +global MAP_PROJECTION MAP_VAR_LIST + +[bX,bY]=mu_util('box',31); +% Get its lat/longs. + +[lg,lt]=feval(MAP_PROJECTION.routine,'xy2ll',bX,bY,'clip','off'); +% Take real part because otherwise funny things might happen if the box is very large + +MAP_VAR_LIST.lats=[min(real(lt)) max(real(lt))]; + +% Are the poles within the axis limits? (Test necessary for oblique mercator and azimuthal) +[px,py]=feval(MAP_PROJECTION.routine,'ll2xy',[0 0],[-90 90],'clip','point'); +if isfinite(px(1)), MAP_VAR_LIST.lats(1)=-90; end +if isfinite(px(2)), MAP_VAR_LIST.lats(2)= 90; end + +if any(isfinite(px)) + MAP_VAR_LIST.longs=[-179.99 180]+exp(1); % we add a weird number (exp(1)) to get away from + % anything that might conceivably be desired as a + % boundary - it makes grid generation easier. + % Also make the limits just a little less than 180, this + % is necessary because I have to have the first and last points + % of lines just a little different in order to figure out orientation + % in 'm_rectgrid' +else + MAP_VAR_LIST.longs=[min(lg) max(lg)]; + if all(isnan(px)) && diff(MAP_VAR_LIST.longs)>360*30/31 + ii=lg