source: trunk/src/get_field.m @ 1023

Last change on this file since 1023 was 1023, checked in by sommeria, 6 years ago

bug repaired for ordinary plots

File size: 45.5 KB
Line 
1%'get_field': display variables and attributes from a Netcdf file, and OK selected fields
2%------------------------------------------------------------------------
3% GetFieldData=get_field(FileName,ParamIn)
4% associated with the GUI get_field.fig
5%
6% OUTPUT:
7% GetFieldData: structure containing the information on the selected
8%      fields, obtained by applying the fct red_GUI to the GUI get_field
9%   .FieldOption='vectors': variables are used for vector plot
10%                  'scalar': variables are used for scalar plot,
11%                  '1Dplot': variables are used for usual x-y plot,
12%                  'civdata...': go back to automatic reading of civ data
13%   .PanelVectors: sub-structure variables used as vector components
14%   .PanelScalar:
15% INPUT:
16% FileName: name (including path) of the netcdf file to open
17% ParmIn: structure containing parameters for preselecting menus:
18%   .Title: set the title of the GUI get_field
19%   .SwitchVarIndexTime='file index','variable' or 'matrix index': select the default option for 'time'
20%   .TimeAttrName: preselect the name of a global attribute for time
21%   .SeriesInput=1 if get_field is called by the GUI series,=0 otherwise (plot options provided in the latter case)
22%   .Coord_x,.Coord_y,.Coord_z, names of the variables used as the three coordinates
23%   .scalar : set the default choise of the scale variable
24%   .vector_x, .vector_y : set the default choise for the variables used for the x and y vector components
25
26%=======================================================================
27% Copyright 2008-2017, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
28%   http://www.legi.grenoble-inp.fr
29%   Joel.Sommeria - Joel.Sommeria (A) legi.cnrs.fr
30%
31%     This file is part of the toolbox UVMAT.
32%
33%     UVMAT is free software; you can redistribute it and/or modify
34%     it under the terms of the GNU General Public License as published
35%     by the Free Software Foundation; either version 2 of the license,
36%     or (at your option) any later version.
37%
38%     UVMAT is distributed in the hope that it will be useful,
39%     but WITHOUT ANY WARRANTY; without even the implied warranty of
40%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
41%     GNU General Public License (see LICENSE.txt) for more details.
42%=======================================================================
43
44function varargout = get_field(varargin)
45
46% Last Modified by GUIDE v2.5 18-Feb-2015 23:42:12
47
48% Begin initialization code - DO NOT EDIT
49gui_Singleton = 1;
50gui_State = struct('gui_Name',       mfilename, ...
51                   'gui_Singleton',  gui_Singleton, ...
52                   'gui_OpeningFcn', @get_field_OpeningFcn, ...
53                   'gui_OutputFcn',  @get_field_OutputFcn, ...
54                   'gui_LayoutFcn',  [] , ...
55                   'gui_Callback',   []);
56if nargin && ischar(varargin{1})&& ~isempty(regexp(varargin{1},'_Callback','once'))
57    gui_State.gui_Callback = str2func(varargin{1});
58end
59
60if nargout
61    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
62else
63    gui_mainfcn(gui_State, varargin{:});
64end
65% End initialization code - DO NOT EDIT
66     
67%------------------------------------------------------------------------
68% --- Executes just before get_field is made visible.
69%------------------------------------------------------------------------
70function get_field_OpeningFcn(hObject, eventdata, handles,filename,ParamIn)
71
72%% GUI settings
73handles.output = 'Cancel';
74guidata(hObject, handles);
75set(hObject,'WindowButtonDownFcn',{'mouse_down'}) % allows mouse action with right button (zoom for uicontrol display)
76set(hObject,'CloseRequestFcn',{@closefcn,handles})
77
78%% enter input data
79if ischar(filename) % input file name
80    set(handles.inputfile,'String',filename)% fill the input file name
81    [Field,tild,tild,errormsg]=nc2struct(filename,[]);% reads the  field structure, without the variables
82else
83    msgbox_uvmat('ERROR','get_field requires a file name as input')% display error message for input file reading
84    return
85end
86if ~isempty(errormsg)
87    msgbox_uvmat('ERROR',['get_field/nc2struct/' errormsg])% display error message for input file reading
88    return
89end
90if ~isfield(Field,'ListVarName')
91    msgbox_uvmat('ERROR',['no variable found in ' filename])% display error message for input file reading
92    return
93end
94if ~exist('ParamIn','var')
95    ParamIn.Coord_z='';
96end
97
98%% look at singletons and variables with a single dimension
99Field.Display=Field;
100Field.Check0D=zeros(size(Field.ListVarName));% =1 for arrays with a single value
101NbVar=numel(Field.VarDimName);%nbre of variables in the input data
102for ilist=1:NbVar
103    if ischar(Field.VarDimName{ilist})
104        Field.VarDimName{ilist}={Field.VarDimName{ilist}}; %transform string into cell
105    end
106    NbDim=numel(Field.VarDimName{ilist});
107    check_singleton=false(1,NbDim);%  check singleton, false by default
108    for idim=1:NbDim
109        dim_index=strcmp(Field.VarDimName{ilist}{idim},Field.ListDimName);%index in the list of dimensions
110        check_singleton(idim)=isequal(Field.DimValue(dim_index),1);%check_singleton=1 for singleton
111    end
112    Field.Check0D(ilist)=(isequal(check_singleton,ones(1,NbDim)))||(~isequal(Field.VarType(ilist),4)&&~isequal(Field.VarType(ilist),5)&&~isequal(Field.VarType(ilist),6));% =1 if the variable reduces to a single value
113    if ~Field.Check0D(ilist)
114    Field.Display.VarDimName{ilist}=Field.VarDimName{ilist}(~check_singleton);% eliminate singletons in the list of variable dimensions
115    end
116end
117if ~isfield(Field,'VarAttribute')
118    Field.VarAttribute={};
119end
120if numel(Field.VarAttribute)<NbVar% complement VarAttribute by blanjs if neded
121    Field.VarAttribute(numel(Field.VarAttribute)+1:NbVar)=cell(1,NbVar-numel(Field.VarAttribute));
122end
123% Field.Display = list of variables and corresponding properties obtained after removal of variables with a single value and singleton dimensions
124Field.Display.ListVarName=Field.ListVarName(~Field.Check0D); %list of variables available for plots, after eliminating variables with a single value
125Field.Display.VarAttribute=Field.VarAttribute(~Field.Check0D);
126Field.Display.VarDimName=Field.Display.VarDimName(~Field.Check0D);
127Field.Display.ListDimName=Field.ListDimName(Field.DimValue~=1);% list of non singleton dimension names
128Field.Display.DimValue=Field.DimValue(Field.DimValue~=1);% corresponding list of non singleton dimension values
129
130
131%% analyse the input field cells
132[CellInfo,NbDim,errormsg]=find_field_cells(Field.Display);
133if ~isempty(errormsg)
134    msgbox_uvmat('ERROR',['get_field / Field_input / find_field_cells: ' errormsg])
135    return
136end
137[Field.MaxDim,imax]=max(NbDim);
138
139%% set time mode
140ListSwitchVarIndexTime={'file index'};% default setting: the time is the file index
141% look at global attributes with numerical values
142check_numvalue=false(1,numel(Field.ListGlobalAttribute));
143for ilist=1:numel(Field.ListGlobalAttribute)
144    Value=Field.(Field.ListGlobalAttribute{ilist});
145    check_numvalue(ilist)=isnumeric(Value);
146end
147Field.Display.ListGlobalAttribute=Field.ListGlobalAttribute(check_numvalue);% select the attributes with float numerical value
148if ~isempty(Field.Display.ListGlobalAttribute)
149    ListSwitchVarIndexTime=[ListSwitchVarIndexTime; {'attribute'}];% the time can be chosen as a global attribute
150end
151if Field.MaxDim>=2
152    ListSwitchVarIndexTime=[ListSwitchVarIndexTime;{'variable'};{'matrix index'}];% the time can be chosen as a dim index
153end
154
155%% select the Time attribute from input
156if isfield(ParamIn,'TimeAttrName')
157    time_index=find(strcmp(ParamIn.TimeAttrName,Field.Display.ListGlobalAttribute),1);
158else
159    time_index=find(~cellfun('isempty',regexp(Field.Display.ListGlobalAttribute,'Time')),1);% look for global attribute containing name 'Time'
160end
161if isempty(time_index)
162    set(handles.SwitchVarIndexTime,'Value',1);
163else
164    set(handles.SwitchVarIndexTime,'Value',2);
165    set(handles.TimeName,'UserData',time_index)
166end
167set(handles.SwitchVarIndexTime,'String',ListSwitchVarIndexTime)
168set(handles.SwitchVarIndexTime,'UserData',ListSwitchVarIndexTime); % keep string in memory for check3D
169set(handles.get_field,'UserData',Field);% record the finput field structure
170SwitchVarIndexTime_Callback([], [], handles)
171
172%% set vector menu (priority) if detected or scalar menu for space dim >=2, or usual (x,y) plot for 1D fields
173set(handles.vector_x,'String',Field.Display.ListVarName)% fill the menu of x vector components
174set(handles.vector_y,'String',Field.Display.ListVarName)% fill the menu of y vector components
175set(handles.vector_z,'String',[{''} Field.Display.ListVarName])% fill the menu of y vector components
176set(handles.vec_color,'String',[{''} Field.Display.ListVarName])% fill the menu of y vector components
177set(handles.scalar,'Value',1)% fill the menu of y vector components
178set(handles.scalar,'String',Field.Display.ListVarName)% fill the menu for scalar
179set(handles.ordinate,'Value',1)% fill the menu of y vector components
180set(handles.ordinate,'String',Field.Display.ListVarName)% fill the menu of y coordinate for 1D plots
181checkseries=0;
182if isfield(ParamIn,'SeriesInput') && ParamIn.SeriesInput% case of call by series
183    set(handles.FieldOption,'value',1)
184    if isfield(Field,'Conventions')&& strcmp(Field.Conventions,'uvmat/civdata')
185    set(handles.FieldOption,'String',{'scalar';'vectors';'civdata...'})
186    else
187       set(handles.FieldOption,'String',{'scalar';'vectors'})
188    end
189    checkseries=1;
190    set(handles.scalar,'Max',2)
191elseif isfield(Field,'Conventions')&& strcmp(Field.Conventions,'uvmat/civdata')
192    set(handles.FieldOption,'String',{'1D plot';'scalar';'vectors';'civdata...'})% provides the possibility to come back to civdata
193    set(handles.scalar,'Max',1)
194else
195    set(handles.FieldOption,'String',{'1D plot';'scalar';'vectors'})
196    set(handles.scalar,'Max',1)
197end
198
199%% set default field options
200checknbdim=cellfun('size',Field.Display.VarDimName,2);
201if max(checknbdim)<=1
202    Field.MaxDim=1;% only 1D fields, considered as a time series by default
203end
204if Field.MaxDim>=2 && ~checkseries% case of 2D (or 3D) fields
205    check_vec_input=0;
206    if isfield(ParamIn,'vector_x')&& isfield(ParamIn,'vector_y')
207        ichoice_x=find(strcmp(ParamIn.vector_x,Field.Display.ListVarName),1);
208        ichoice_y=find(strcmp(ParamIn.vector_y,Field.Display.ListVarName),1);
209        if ~isempty(ichoice_x)&&~isempty(ichoice_y)
210            set(handles.vector_x,'UserData',ichoice_x)
211            set(handles.vector_y,'UserData',ichoice_y)
212            check_vec_input=1;
213        end
214    end
215    if ~check_vec_input && isfield(CellInfo{imax},'VarIndex_vector_x') &&  isfield(CellInfo{imax},'VarIndex_vector_y')
216        set(handles.vector_x,'UserData',CellInfo{imax}.VarIndex_vector_x(1))
217        set(handles.vector_y,'UserData',CellInfo{imax}.VarIndex_vector_y(1))
218        check_vec_input=1;
219    end
220    if check_vec_input
221        set(handles.FieldOption,'Value',3)% set vector selection option
222    else
223       
224        set(handles.FieldOption,'Value',2)% set scalar selection option
225    end
226else % case of 1D fields
227    set(handles.FieldOption,'Value',1)
228end
229
230%% fill the general list of dimensions, variables, attributes
231if isfield(Field,'ListDimName')&&~isempty(Field.ListDimName)
232    Tabcell(:,1)=Field.ListDimName;
233    for iline=1:length(Field.ListDimName)
234        Tabcell{iline,2}=num2str(Field.DimValue(iline));
235    end
236    Tabchar=cell2tab(Tabcell,' = ');
237    set(handles.dimensions,'String',Tabchar)
238end
239
240%% fill menus for coordinates and time
241FieldOption_Callback(handles.variables,[], handles)% list the global attributes
242
243%% Make choices of coordinates from input
244if isfield(CellInfo{imax},'CoordIndex')
245    CoordIndex=CellInfo{imax}.CoordIndex;
246    if numel(CoordIndex)==2
247        if isfield(ParamIn,'Coord_x')&& isfield(ParamIn,'Coord_y')
248            YName=ParamIn.Coord_y;
249            XName=ParamIn.Coord_x;
250        else
251        YName=Field.ListVarName{CoordIndex(1)};
252        XName=Field.ListVarName{CoordIndex(2)};
253        end
254        ListCoord=get(handles.Coord_x,'String');
255        XIndex=find(strcmp(XName,ListCoord));
256        if ~isempty(XIndex)
257            set(handles.Coord_x,'Value',XIndex)
258        end
259        YIndex=find(strcmp(YName,ListCoord));
260        if ~isempty(YIndex)
261            set(handles.Coord_y,'Value',YIndex)
262        end
263    end
264end
265
266%% put the GUI on the lower right of the sceen
267set(hObject,'Unit','pixels')
268%pos_view_field=get(hObject,'Position');
269set(0,'Unit','pixels')
270ScreenSize=get(0,'ScreenSize');
271pos_view_field(3:4)=[955 648];
272pos_view_field(1)=ScreenSize(1)+ScreenSize(3)-pos_view_field(3);
273pos_view_field(2)=ScreenSize(2);
274set(hObject,'Position',pos_view_field)
275set(handles.get_field,'WindowStyle','modal')% Make the GUI modal
276if isfield(ParamIn,'Title')
277    set(hObject,'Name',ParamIn.Title)
278end
279
280%% set z coordinate menu if relevant
281if Field.MaxDim>=3 && prod(Field.DimValue)<10^8 && ~isempty(ParamIn.Coord_z); % 3D field (with memory content smaller than 400 Mo)
282    set(handles.Check3D,'Value',1)
283else
284    set(handles.Check3D,'Value',0)
285end
286Check3D_Callback(hObject, eventdata, handles)
287set(handles.variables,'Value',1)
288set(handles.variables,'String',[{'*'} Field.ListVarName])
289variables_Callback(handles.variables,[], handles)% list the global attributes
290drawnow
291uiwait(handles.get_field);
292
293% -----------------------------------------------------------------------
294% --- Activated by selection in the list of variables
295% ----------------------------------------------------------------------
296function variables_Callback(hObject, eventdata, handles)
297
298Tabchar={''};%default
299Tabcell=[];
300hselect_field=get(handles.variables,'parent');
301Field=get(handles.get_field,'UserData');
302index=get(handles.variables,'Value');%index in the list 'variables'
303
304%% list global TimeAttribute names and values if index=1 (blank TimeVariable display) is selected
305if isequal(index,1)
306    set(handles.attributes_txt,'String','global attributes')
307    if isfield(Field,'ListGlobalAttribute') && ~isempty(Field.ListGlobalAttribute)
308        for iline=1:length(Field.ListGlobalAttribute)
309            Tabcell{iline,1}=Field.ListGlobalAttribute{iline};
310            if isfield(Field, Field.ListGlobalAttribute{iline})
311                val=Field.(Field.ListGlobalAttribute{iline});
312                if ischar(val);% attribute value is char string
313                    Tabcell{iline,2}=val;
314                elseif size(val,1)==1 %attribute value is a number or matlab vector
315                    Tabcell{iline,2}=num2str(val);
316                end
317            end
318        end
319        Tabchar=cell2tab(Tabcell,'=');
320    end
321    %% list Attribute names and values associated to the Variable # index-1
322else
323    list_var=get(handles.variables,'String');
324    if index>numel(list_var)
325        return
326    end
327    var_select=list_var{index};
328    set(handles.attributes_txt,'String', ['attributes of ' var_select])
329    if isfield(Field,'VarAttribute')&& length(Field.VarAttribute)>=index-1
330        %         nbline=0;
331        VarAttr=Field.VarAttribute{index-1};
332        if isstruct(VarAttr)
333            attr_list=fieldnames(VarAttr);
334            for iline=1:length(attr_list)
335                Tabcell{iline,1}=attr_list{iline};
336                val=VarAttr.(attr_list{iline}) ;
337                if ischar(val);
338                    Tabcell{iline,2}=val;
339                else
340                    Tabcell{iline,2}=num2str(val);
341                end
342            end
343        end
344    end
345end
346if ~isempty(Tabcell)
347    Tabchar=cell2tab(Tabcell,'=');
348    %     Tabchar=[{''};Tabchar];
349end
350set(handles.attributes,'Value',1);% select the first item
351set(handles.attributes,'String',Tabchar);
352
353%% update dimensions;
354if isfield(Field,'ListDimName')
355    Tabdim={};%default
356    if isequal(index,1)%list all dimensions
357        dim_indices=1:length(Field.ListDimName);
358        set(handles.dimensions_txt,'String', 'dimensions')
359    else
360        DimCell=Field.VarDimName{index-1};
361        if ischar(DimCell)
362            DimCell={DimCell};
363        end
364        dim_indices=[];
365        for idim=1:length(DimCell)
366            dim_index=strcmp(DimCell{idim},Field.ListDimName);%vector with size of Field.ListDimName, =0
367            dim_index=find(dim_index,1);
368            dim_indices=[dim_indices dim_index];
369        end
370        set(handles.dimensions_txt,'String', ['dimensions of ' var_select])
371    end
372    for iline=1:length(dim_indices)
373        Tabdim{iline,1}=Field.ListDimName{dim_indices(iline)};
374        Tabdim{iline,2}=num2str(Field.DimValue(dim_indices(iline)));
375    end
376    Tabchar=cell2tab(Tabdim,' = ');
377    Tabchar=[{''} ;Tabchar];
378    set(handles.dimensions,'Value',1)
379    set(handles.dimensions,'String',Tabchar)
380end
381
382%------------------------------------------------------------------------
383% --- Executes on selection change in FieldOption.
384%------------------------------------------------------------------------
385function FieldOption_Callback(hObject, eventdata, handles)
386
387Field=get(handles.get_field,'UserData');
388FieldList=get(handles.FieldOption,'String');
389FieldOption=FieldList{get(handles.FieldOption,'Value')};
390switch FieldOption
391   
392    case '1D plot'
393        set(handles.Coordinates,'Visible','on')
394        set(handles.PanelOrdinate,'Visible','on')
395        pos=get(handles.PanelOrdinate,'Position');
396        pos(1)=2;
397        pos_coord=get(handles.Coordinates,'Position');
398        pos(2)=pos_coord(2)-pos(4)-2;
399        set(handles.PanelOrdinate,'Position',pos)
400        set(handles.PanelScalar,'Visible','off')
401        set(handles.PanelVectors,'Visible','off')
402        set(handles.Coord_y,'Visible','off')
403        set(handles.Y_title,'Visible','off')
404        set(handles.Coord_z,'Visible','off')
405        set(handles.Z_title,'Visible','off')
406        ordinate_Callback(hObject, eventdata, handles)
407       
408    case {'scalar'}
409        set(handles.Coordinates,'Visible','on')
410        set(handles.PanelOrdinate,'Visible','off')
411        set(handles.PanelScalar,'Visible','on')
412        set(handles.PanelVectors,'Visible','off')
413        pos=get(handles.PanelScalar,'Position');
414        pos(1)=2;
415        pos_coord=get(handles.Coordinates,'Position');
416        pos(2)=pos_coord(2)-pos(4)-2;
417        set(handles.PanelScalar,'Position',pos)
418        set(handles.Coord_y,'Visible','on')
419        set(handles.Y_title,'Visible','on')
420        %default scalar selection
421        test_coord=zeros(size(Field.Display.VarDimName)); %=1 when variable #ilist is eligible as structured coordiante
422        for ilist=1:numel(Field.Display.VarDimName)
423            if isfield(Field.Display,'VarAttribute') && numel(Field.Display.VarAttribute)>=ilist && isfield(Field.Display.VarAttribute{ilist},'Role')
424                Role=Field.Display.VarAttribute{ilist}.Role;
425                if strcmp(Role,'coord_x')||strcmp(Role,'coord_y')
426                    test_coord(ilist)=1;
427                end
428            end
429            dimnames=Field.Display.VarDimName{ilist}; %list of dimensions for variable #ilist
430            if numel(dimnames)==1 && strcmp(dimnames{1},Field.Display.ListVarName{ilist})%dimension variable
431                test_coord(ilist)=1;
432            end
433        end
434        scalar_index=find(~test_coord,1);%get the first variable not a coordinate
435        if isempty(scalar_index)
436            set(handles.scalar,'Value',1)
437        else
438            set(handles.scalar,'Value',scalar_index)
439        end       
440        scalar_Callback(hObject, eventdata, handles)
441             
442    case 'vectors'
443        set(handles.PanelVectors,'Visible','on')
444        set(handles.Coordinates,'Visible','on')
445        set(handles.PanelOrdinate,'Visible','off')
446        set(handles.PanelScalar,'Visible','off')
447        pos=get(handles.PanelVectors,'Position');
448        pos(1)=2;
449        pos_coord=get(handles.Coordinates,'Position');
450        pos(2)=pos_coord(2)-pos(4)-2;
451        set(handles.PanelVectors,'Position',pos)
452        set(handles.Coord_y,'Visible','on')
453        set(handles.Y_title,'Visible','on')
454        %default vector selection
455        vector_x_value=get(handles.vector_x,'UserData');
456        vector_y_value=get(handles.vector_y,'UserData');
457        if ~isempty(vector_x_value)&&~isempty(vector_y_value)
458            set(handles.vector_x,'Value',vector_x_value)
459            set(handles.vector_y,'Value',vector_y_value)
460        else
461            test_coord=zeros(size(Field.Display.VarDimName)); %=1 when variable #ilist is eligible as structured coordinate
462            for ilist=1:numel(Field.Display.VarDimName)
463                if isfield(Field.Display,'VarAttribute') && numel(Field.Display.VarAttribute)>=ilist && isfield(Field.Display.VarAttribute{ilist},'Role')
464                    Role=Field.Display.VarAttribute{ilist}.Role;
465                    if strcmp(Role,'coord_x')||strcmp(Role,'coord_y')
466                        test_coord(ilist)=1;
467                    end
468                end
469                dimnames=Field.Display.VarDimName{ilist}; %list of dimensions for variable #ilist
470                if numel(dimnames)==1 && strcmp(dimnames{1},Field.Display.ListVarName{ilist})%dimension variable
471                    test_coord(ilist)=1;
472                end
473            end
474            vector_index=find(~test_coord,2);%get the two first variables not a coordinate
475            if isempty(vector_index)
476                set(handles.vector_x,'Value',1)
477                set(handles.vector_y,'Value',2)
478            else
479                set(handles.vector_x,'Value',vector_index(1))
480                set(handles.vector_y,'Value',vector_index(2))
481            end
482        end
483        vector_Callback(handles)
484       
485    case 'civdata...'
486        set(handles.PanelOrdinate,'Visible','off')
487        set(handles.PanelScalar,'Visible','off')
488        set(handles.PanelVectors,'Visible','off')
489        set(handles.Coordinates,'Visible','off')
490end
491
492%------------------------------------------------------------------------
493function ordinate_Callback(hObject, eventdata, handles)
494%------------------------------------------------------------------------
495Field=get(handles.get_field,'UserData');
496y_index=get(handles.ordinate,'Value');
497y_menu=get(handles.ordinate,'String');
498if isempty(y_menu)
499    return
500else
501YName=y_menu{y_index};
502end
503
504%% set list of possible coordinates
505test_component=zeros(size(Field.Display.VarDimName));%=1 when variable #ilist is eligible as unstructured coordinate
506test_coord=zeros(size(Field.Display.VarDimName)); %=1 when variable #ilist is eligible as structured coordiante
507ListCoord={''};
508dim_var=Field.Display.VarDimName{y_index};%list of dimensions of the selected variable
509
510for ilist=1:numel(Field.Display.VarDimName)
511    dimnames=Field.Display.VarDimName{ilist}; %list of dimensions for variable #ilist
512    if isequal(dimnames,dim_var)
513        test_component(ilist)=1;
514    elseif numel(dimnames)==1 && ~isempty(find(strcmp(dimnames{1},dim_var)))%variable ilist is a 1D array which can be coordinate variable
515        test_coord(ilist)=1;
516    end
517end
518var_component=find(test_component);% list of variable indices elligible as unstructured coordinates
519var_coord=find(test_coord);% % list of variable indices elligible as structured coordinates
520ListCoord=Field.Display.ListVarName([var_component var_coord]);
521
522%% set default coord selection
523if numel(find(test_coord))>3
524     SwitchVarIndexTime=get(handles.SwitchVarIndexTime,'String');
525    if numel(SwitchVarIndexTime)<3
526        SwitchVarIndexTime=[SwitchVarIndexTime;'matrix_index'];
527        set(handles.SwitchVarIndexTime,'String',SwitchVarIndexTime)
528    end
529    set(handles.SwitchVarIndexTime,'Value',3)% the last dim must be considered as time
530    SwitchVarIndexTime_Callback([], [], handles)
531end
532if numel(var_component)<2
533    if numel(test_coord)<2
534        ListCoord={''};
535    else
536        set(handles.Coord_x,'Value',2)
537        set(handles.Coord_y,'Value',1)
538    end
539else
540    coord_val=1;
541    for ilist=1:numel(var_component)
542        ivar=var_component(ilist);
543        if isfield(Field.Display,'VarAttribute') && numel(Field.Display.VarAttribute)>=ivar && isfield(Field.Display.VarAttribute{ivar},'Role')
544            Role=Field.Display.VarAttribute{ivar}.Role;
545            if strcmp(Role,'coord_x')
546                coord_val=ilist;
547            end
548        end
549    end
550    set(handles.Coord_x,'Value',coord_val)
551end
552set(handles.Coord_x,'String',ListCoord)
553
554
555%% set list of time coordinates
556menu=get(handles.SwitchVarIndexTime,'String');
557TimeOption=menu{get(handles.SwitchVarIndexTime,'Value')};
558switch TimeOption
559    case 'variable'
560        if numel(find(test_coord))<3
561            ListTime={''};
562        else
563            ListTime=Field.Display.ListVarName(find(test_coord,end));
564        end
565        set(handles.TimeName,'Value',1)
566        set(handles.TimeName,'String',ListTime)
567    case 'matrix index'
568        if numel(find(test_coord))<3
569            ListTime={''};
570        else
571            ListTime=Field.Display.VarDimName{find(test_coord,end)};
572        end
573        set(handles.TimeName,'Value',1)
574        set(handles.TimeName,'String',ListTime)
575end 
576update_field(handles,YName)
577         
578%------------------------------------------------------------------------
579% --- Executes on selection change in scalar menu.
580%------------------------------------------------------------------------
581function scalar_Callback(hObject, eventdata, handles)
582
583Field=get(handles.get_field,'UserData');
584scalar_index=get(handles.scalar,'Value');
585scalar_menu=get(handles.scalar,'String');
586ScalarName=scalar_menu{scalar_index};
587
588%% set list of possible coordinates
589test_component=zeros(size(Field.Display.VarDimName));%=1 when variable #ilist is eligible as unstructured coordinate
590test_coord=zeros(size(Field.Display.VarDimName)); %=1 when variable #ilist is eligible as structured coordiante
591dim_var=Field.Display.VarDimName{scalar_index};%list of dimensions of the selected variable
592if ~get(handles.CheckDimensionX,'Value') 
593    %look for coordinate variables among the other variables
594    for ilist=1:numel(Field.Display.VarDimName)
595        dimnames=Field.Display.VarDimName{ilist}; %list of dimensions for variable #ilist
596        if isequal(dimnames,dim_var)
597            test_component(ilist)=1;% the listed variable has the same dimension as the selected scalar-> possibly chosen as unstructured coordinate
598        elseif numel(dimnames)==1 && ~isempty(find(strcmp(dimnames{1},dim_var), 1))%variable ilist is a 1D array which can be coordinate variable
599            test_coord(ilist)=1;
600        end
601    end
602end
603var_component=find(test_component);% list of variable indices elligible as unstructured coordinates
604var_coord=find(test_coord);% % list of variable indices elligible as structured coordinates
605var_coord(var_coord==scalar_index)=[];
606var_component(var_component==scalar_index)=[];
607ListCoord=Field.Display.ListVarName([var_coord var_component]);
608
609%% set default coord selection
610% if numel(find(test_coord))>3
611%     SwitchVarIndexTime=get(handles.SwitchVarIndexTime,'String');
612%     if numel(SwitchVarIndexTime)<3
613%         SwitchVarIndexTime=[SwitchVarIndexTime;'matrix_index'];
614%         set(handles.SwitchVarIndexTime,'String',SwitchVarIndexTime)
615%     end
616%     set(handles.SwitchVarIndexTime,'Value',3)% the last dim must be considered as time
617%     SwitchVarIndexTime_Callback([], [], handles)
618% end
619
620coord_val=[0 0];
621% look for labelled unstructured coordinates
622for ilist=1:numel(var_component)
623    ivar=var_component(ilist);
624    if isfield(Field.Display,'VarAttribute') && numel(Field.Display.VarAttribute)>=ivar && isfield(Field.Display.VarAttribute{ivar},'Role')
625        Role=Field.Display.VarAttribute{ivar}.Role;
626        if strcmp(Role,'coord_x')
627            coord_val(1)=ilist;
628        elseif strcmp(Role,'coord_y')
629            coord_val(2)=ilist;
630            elseif strcmp(Role,'coord_z')
631            coord_val(3)=ilist;
632        end
633    end
634end
635if numel(find(coord_val))<2
636    if numel(var_coord)>=3
637         coord_val=[3 2 1];
638    elseif numel(var_coord)>=2
639       % coord_val=[numel(var_component)+2 numel(var_component)+1];
640       coord_val=[2 1];
641    else
642        coord_val=[1 2];
643    end
644end
645if  get(handles.CheckDimensionX,'Value')
646    set(handles.Coord_x,'Value',2)
647    set(handles.Coord_x,'String',dim_var')
648else
649    set(handles.Coord_x,'Value',coord_val(1))
650    set(handles.Coord_x,'String',ListCoord)
651end
652if  get(handles.CheckDimensionX,'Value')
653    set(handles.Coord_y,'Value',1)
654    set(handles.Coord_y,'String',dim_var')
655else
656    set(handles.Coord_y,'Value',coord_val(2))
657    set(handles.Coord_y,'String',ListCoord)
658end
659if  get(handles.CheckDimensionX,'Value')
660    set(handles.Coord_z,'Value',1)
661    set(handles.Coord_z,'String',dim_var')
662else
663    set(handles.Coord_z,'Value',coord_val(2))
664    set(handles.Coord_z,'String',ListCoord)
665end
666
667%% set list of time coordinates
668menu=get(handles.SwitchVarIndexTime,'String');
669TimeOption=menu{get(handles.SwitchVarIndexTime,'Value')};
670switch TimeOption
671    case 'variable'
672        if numel(find(test_coord))<3
673            ListTime={''};
674        else
675            ListTime=Field.Display.ListVarName(find(test_coord,end));
676        end
677        set(handles.TimeName,'Value',1)
678        set(handles.TimeName,'String',ListTime)
679    case 'dim index'
680        if numel(find(test_coord))<3
681            ListTime={''};
682        else
683            ListTime=Field.Display.VarDimName{find(test_coord,end)};
684        end
685        set(handles.TimeName,'Value',1)
686        set(handles.TimeName,'String',ListTime)
687end 
688update_field(handles,ScalarName)
689
690% --- Executes on button press in check_rgb.
691function check_rgb_Callback(hObject, eventdata, handles)
692
693
694%------------------------------------------------------------------------
695% --- Executes on selection change in vector_x.
696%------------------------------------------------------------------------
697function vector_x_Callback(hObject, eventdata, handles)
698
699vector_x_menu=get(handles.vector_x,'String');
700vector_x_index=get(handles.vector_x,'Value');
701vector_x=vector_x_menu{vector_x_index};
702vector_Callback(handles)
703update_field(handles,vector_x)
704
705%------------------------------------------------------------------------
706% --- Executes on selection change in vector_x.
707function vector_y_Callback(hObject, eventdata, handles)
708%------------------------------------------------------------------------
709vector_y_menu=get(handles.vector_x,'String');
710vector_y_index=get(handles.vector_x,'Value');
711vector_y=vector_y_menu{vector_y_index};
712vector_Callback(handles)
713update_field(handles,vector_y)
714
715%------------------------------------------------------------------------
716% --- Executes on selection change in vector_z.
717function vector_z_Callback(hObject, eventdata, handles)
718%------------------------------------------------------------------------
719vector_z_menu=get(handles.vector_z,'String');
720vector_z_index=get(handles.vector_z,'Value');
721vector_z=vector_z_menu{vector_z_index};
722vector_Callback(handles)
723update_field(handles,vector_z)
724
725%------------------------------------------------------------------------
726% --- Executes on selection change in vec_color.
727function vec_color_Callback(hObject, eventdata, handles)
728%------------------------------------------------------------------------
729index=get(handles.vec_color,'Value');
730string=get(handles.vec_color,'String');
731VarName=string{index};
732vector_Callback(handles)
733update_field(handles,VarName)
734
735%------------------------------------------------------------------------
736% --- Executes on selection change in vector_x or vector_y
737function vector_Callback( handles)
738%------------------------------------------------------------------------
739Field=get(handles.get_field,'UserData');
740vector_x_index=get(handles.vector_x,'Value');
741vector_y_index=get(handles.vector_y,'Value');
742vec_color_index=get(handles.vec_color,'Value');
743
744%% set list of possible coordinates
745test_component=zeros(size(Field.Display.VarDimName));%=1 when variable #ilist is eligible as unstructured coordinate
746test_coord=zeros(size(Field.Display.VarDimName)); %=1 when variable #ilist is eligible as structured coordinate
747check_consistent=1;%check that the selected vector components (and possibly color var) have the same dimensiosn
748ListCoord={''};
749dim_var=Field.Display.VarDimName{vector_x_index};%list of dimensions of the selected variable
750if ~isequal(dim_var,Field.Display.VarDimName{vector_y_index})
751    check_consistent=0;
752elseif vec_color_index~=1 && ~isequal(dim_var,Field.Display.VarDimName{vec_color_index})
753    check_consistent=0;
754end
755% the two vector components have consistent dimensions
756if check_consistent
757    for ilist=1:numel(Field.Display.VarDimName)
758        dimnames=Field.Display.VarDimName{ilist}; %list of dimensions for variable #ilist
759        if isequal(dimnames,dim_var)
760            test_component(ilist)=1;
761        elseif numel(dimnames)==1 && ~isempty(find(strcmp(dimnames{1},dim_var)))%variable ilist is a 1D array which can be coordinate variable
762            test_coord(ilist)=1;
763        end
764    end
765    var_component=find(test_component);% list of variable indices elligible as unstructured coordinates
766    var_coord=find(test_coord);% % list of variable indices elligible as structured coordinates
767    var_component(var_component==vector_x_index|var_component==vector_y_index)=[];
768    var_coord(var_coord==vector_x_index|var_coord==vector_y_index)=[];% remove vector components form te possible list of coordinates
769    ListCoord=Field.Display.ListVarName([var_coord var_component]);
770   
771    %% set default coord selection
772    if numel(find(test_coord))>3
773        set(handles.SwitchVarIndexTime,'Value',3)% the last dim must be considered as time
774    end
775    if numel(var_component)<2
776        if numel(find(test_coord))<2
777            ListCoord={''};
778        else
779            if numel(find(test_coord))>=3
780                set(handles.Coord_x,'Value',3)
781                set(handles.Coord_y,'Value',2)
782                set(handles.Coord_z,'Value',1)
783            else
784                set(handles.Coord_x,'Value',2)
785                set(handles.Coord_y,'Value',1)
786            end
787        end
788    else
789        coord_val=[0 0 0];
790        for ilist=1:numel(var_component)
791            ivar=var_component(ilist);
792            if isfield(Field.Display,'VarAttribute') && numel(Field.Display.VarAttribute)>=ivar && isfield(Field.Display.VarAttribute{ivar},'Role')
793                Role=Field.Display.VarAttribute{ivar}.Role;
794                if strcmp(Role,'coord_x')
795                    coord_val(1)=ilist;
796                elseif strcmp(Role,'coord_y')
797                    coord_val(2)=ilist;
798                elseif strcmp(Role,'coord_z')
799                    coord_val(3)=ilist;
800                end
801            end
802        end
803        if isempty(find(coord_val))
804            coord_val=var_coord;% case of dimension coordinates
805        end
806        if numel(find(coord_val))<2
807            %coord_val=[numel(var_component)+2 numel(var_component)+1];
808            coord_val=[1 2 3];
809        end
810        set(handles.Coord_x,'Value',coord_val(1))
811        set(handles.Coord_y,'Value',coord_val(2))
812        if numel(coord_val)>=3
813            set(handles.Coord_z,'Value',coord_val(3))
814        end
815    end
816end
817set(handles.Coord_z,'String',ListCoord)
818set(handles.Coord_y,'String',ListCoord)
819set(handles.Coord_x,'String',ListCoord)
820
821
822%% set list of time coordinates
823menu=get(handles.SwitchVarIndexTime,'String');
824TimeOption=menu{get(handles.SwitchVarIndexTime,'Value')};
825switch TimeOption
826    case 'variable'
827        if numel(find(test_coord))<3
828            ListTime={''};
829        else
830            ListTime=Field.Display.ListVarName(find(test_coord,end));
831        end
832        set(handles.TimeName,'Value',1)
833        set(handles.TimeName,'String',ListTime)
834    case 'dim index'
835        if numel(find(test_coord))<3
836            ListTime={''};
837        else
838            ListTime=Field.Display.VarDimName{find(test_coord,end)};
839        end
840        set(handles.TimeName,'Value',1)
841        set(handles.TimeName,'String',ListTime)
842end 
843
844%------------------------------------------------------------------------
845% --- Executes on selection change in SwitchVarIndexX.
846%------------------------------------------------------------------------
847function SwitchVarIndexX_Callback(hObject, eventdata, handles)
848
849%------------------------------------------------------------------------
850% --- Executes on selection change in Coord_x.
851%------------------------------------------------------------------------
852function Coord_x_Callback(hObject, eventdata, handles)
853
854index=get(handles.Coord_x,'Value');
855string=get(handles.Coord_x,'String');
856VarName=string{index};
857update_field(handles,VarName)
858
859%------------------------------------------------------------------------
860% --- Executes on selection change in Coord_y.
861%------------------------------------------------------------------------
862function Coord_y_Callback(hObject, eventdata, handles)
863
864index=get(handles.Coord_y,'Value');
865string=get(handles.Coord_y,'String');
866VarName=string{index};
867update_field(handles,VarName)
868
869%------------------------------------------------------------------------
870% --- Executes on selection change in Coord_z.
871%------------------------------------------------------------------------
872function Coord_z_Callback(hObject, eventdata, handles)
873
874index=get(handles.Coord_z,'Value');
875string=get(handles.Coord_z,'String');
876VarName=string{index};
877update_field(handles,VarName)
878
879%------------------------------------------------------------------------
880% --- Executes on selection change in SwitchVarIndexTime.
881%------------------------------------------------------------------------
882
883function SwitchVarIndexTime_Callback(hObject, eventdata, handles)
884
885Field=get(handles.get_field,'UserData');
886menu=get(handles.SwitchVarIndexTime,'String');
887option=menu{get(handles.SwitchVarIndexTime,'Value')};
888
889switch option
890    case 'file index'
891        set(handles.TimeName, 'Visible','off')% the time is taken as the file index
892    case 'attribute'
893        set(handles.TimeName, 'Visible','on')% timeName menu represents the available attributes
894        time_index=get(handles.TimeName,'UserData');    %select the input data
895        if isempty(time_index)
896            PreviousList=get(handles.TimeName, 'String');
897            if ~isempty(PreviousList)
898                PreviousAttr=PreviousList{get(handles.TimeName, 'Value')};
899                index=find(strcmp(PreviousAttr,Field.Display.ListGlobalAttributes),1);
900            end
901        end
902        if isempty(time_index)
903            time_index=find(~cellfun('isempty',regexp(Field.Display.ListGlobalAttribute,'Time')),1);% index of the attributes containing the string 'Time'
904        end     
905        if ~isempty(time_index)
906            set(handles.TimeName,'Value',time_index)
907        else
908            set(handles.TimeName,'Value',1)
909        end
910        set(handles.TimeName, 'String',Field.Display.ListGlobalAttribute)
911
912    case 'variable'% TimeName menu represents the available variables
913        set(handles.TimeName, 'Visible','on')
914        VarNbDim=cellfun('length',Field.Display.VarDimName); % check the nbre of dimensions of each input variable
915        TimeVarName=Field.Display.ListVarName(VarNbDim==1);% list of variables with a single dimension (candidate for time)
916        List=get(handles.TimeName,'String');% list of names on the menu for time
917        if isempty(List)
918            ind=1;
919        else
920            option=List{get(handles.TimeName,'Value')};% previous selected option
921            ind=find(strcmp(option,TimeVarName)); %check whether the previous selection is available in the newlist
922            if isempty(ind)
923                ind=1;
924            end
925        end
926        if ~isempty(TimeVarName)
927            set(handles.TimeName, 'Value',ind);% select first value in the menu if the option is not found
928            set(handles.TimeName, 'String',TimeVarName)% update the menu for time name
929        end
930    case 'matrix index'% TimeName menu represents the available dimensions
931        set(handles.TimeName, 'Visible','on')     
932        set(handles.TimeName, 'Value',1);
933        set(handles.TimeName, 'String',Field.Display.ListDimName)
934end
935TimeName_Callback(hObject, [], handles)
936
937%-----------------------------------------------------------------------
938function update_field(handles,VarName)
939%-----------------------------------------------------------------------
940Field=get(handles.get_field,'UserData');
941index=name2index(VarName,Field.ListVarName);
942if ~isempty(index)
943    set(handles.variables,'Value',index+1)
944    variables_Callback(handles.variables, [], handles)
945end
946
947%------------------------------------------------------------------------
948% --- give index numbers of the strings str in the list ListvarName
949% -----------------------------------------------------------------------
950function VarIndex_y=name2index(cell_str,ListVarName)
951
952VarIndex_y=[];
953if ischar(cell_str)
954    for ivar=1:length(ListVarName)
955        varlist=ListVarName{ivar};
956        if isequal(varlist,cell_str)
957            VarIndex_y= ivar;
958            break
959        end
960    end
961elseif iscell(cell_str)
962    for isel=1:length(cell_str)
963        varsel=cell_str{isel};
964        for ivar=1:length(ListVarName)
965            varlist=ListVarName{ivar};
966            if isequal(varlist,varsel)
967                VarIndex_y=[VarIndex_y ivar];
968            end
969        end
970    end
971end
972
973% --- Executes on button press in CheckDimensionY.
974function CheckDimensionX_Callback(hObject, eventdata, handles)
975CheckDimensionX=get(handles.CheckDimensionX,'value')
976if CheckDimensionX
977    set(handles.Coordinates,'visible','off')
978else
979    set(handles.Coordinates,'visible','on')
980end
981% FieldList=get(handles.FieldOption,'String');
982% FieldOption=FieldList{get(handles.FieldOption,'Value')};
983% switch FieldOption
984%     case '1D plot'
985%         
986%     case {'scalar'}
987%        scalar_Callback(hObject, eventdata, handles)
988%     case 'vectors'
989% end
990
991% % --- Executes on button press in CheckDimensionY.
992% function CheckDimensionY_Callback(hObject, eventdata, handles)
993% FieldList=get(handles.FieldOption,'String');
994% FieldOption=FieldList{get(handles.FieldOption,'Value')};
995% switch FieldOption
996%     case '1D plot'
997%         
998%     case {'scalar','pick variables'}
999%        scalar_Callback(hObject, eventdata, handles)
1000%     case 'vectors'
1001% end
1002%
1003%
1004% % --- Executes on button press in CheckDimensionZ.
1005% function CheckDimensionZ_Callback(hObject, eventdata, handles)
1006% FieldList=get(handles.FieldOption,'String');
1007% FieldOption=FieldList{get(handles.FieldOption,'Value')};
1008% switch FieldOption
1009%     case '1D plot'
1010%         
1011%     case 'scalar'
1012%        scalar_Callback(hObject, eventdata, handles)
1013%     case 'vectors'
1014% end
1015
1016% --- Executes on selection change in TimeName.
1017function TimeName_Callback(hObject, eventdata, handles)
1018Field=get(handles.get_field,'UserData');
1019index=get(handles.SwitchVarIndexTime,'Value');
1020MenuIndex=get(handles.TimeName,'Value');
1021string=get(handles.TimeName,'String');
1022TimeName='';%default
1023if ~isempty(string)&&iscell(string)
1024TimeName=string{MenuIndex};
1025end
1026switch index
1027    case 1
1028        set(handles.num_TimeDimension,'String','')
1029        set(handles.TimeUnit,'String','index')
1030    case 2
1031        set(handles.num_TimeDimension,'String','')
1032        attr_index=find(strcmpi([TimeName 'Unit'],Field.ListGlobalAttribute));% look for time unit
1033        if ~isempty(attr_index)
1034            AttrName=Field.ListGlobalAttribute{attr_index};
1035            set(handles.TimeUnit,'String',Field.(AttrName))
1036        else
1037            set(handles.TimeUnit,'String','')
1038        end
1039    case {3 ,4}
1040        if index==3  % TimeName is used to chose a variable
1041            VarIndex=name2index(TimeName,Field.ListVarName);
1042            DimName=Field.VarDimName{VarIndex};
1043            DimIndex=name2index(DimName,Field.ListDimName);
1044            DimValue=Field.DimValue(DimIndex);
1045            set(handles.num_TimeDimension,'String',num2str(DimValue))
1046            unit='';
1047            if isfield(Field,'VarAttribute')&& isfield(Field.VarAttribute{VarIndex},'Unit')
1048                unit=Field.VarAttribute{VarIndex}.Unit;
1049            end
1050            set(handles.TimeUnit,'String',unit)
1051            update_field(handles,TimeName)
1052        elseif index==4% TimeName is used to chose a dimension
1053            DimName=string{MenuIndex};
1054            DimIndex=name2index(DimName,Field.ListDimName);
1055            DimValue=Field.DimValue(DimIndex);
1056            set(handles.num_TimeDimension,'String',num2str(DimValue))
1057            set(handles.TimeUnit,'String','index')
1058        end
1059end
1060
1061
1062% --- Executes on button press in Check3D.
1063function Check3D_Callback(hObject, eventdata, handles)
1064if get(handles.Check3D,'Value')% 3D fields
1065    status='on';
1066else% fields studied as 2D
1067    status='off';
1068end
1069
1070set(handles.Coord_z,'Visible',status)
1071% set(handles.CheckDimensionZ,'Visible',status)
1072set(handles.Z_title,'Visible',status)
1073set(handles.vector_z,'Visible',status)
1074set(handles.W_title,'Visible',status)
1075if strcmp(status,'on')% ask for 3D input   
1076    Field=get(handles.get_field,'UserData');
1077    if Field.MaxDim>3% for 4D fields, propose to use the fourth variable as time
1078        %set(handles.Time,'Visible','on')
1079        menu=get(handles.SwitchVarIndexTime,'String');
1080        val=find(strcmp('variable',menu));
1081        if ~isempty(val)
1082            set(handles.SwitchVarIndexTime,'Value',val)
1083        end
1084    else
1085        set(handles.SwitchVarIndexTime,'Value',1)
1086        set(handles.SwitchVarIndexTime,'String',{'file index'})
1087    end
1088else
1089   set(handles.SwitchVarIndexTime,'String',get(handles.SwitchVarIndexTime,'UserData'))
1090end
1091SwitchVarIndexTime_Callback(handles.SwitchVarIndexTime,[], handles)
1092
1093%------------------------------------------------------------------------
1094% --- Executes on button press in OK.
1095%------------------------------------------------------------------------
1096function OK_Callback(hObject, eventdata, handles)
1097handles.output=read_GUI(handles.get_field);
1098guidata(hObject, handles);% Update handles structure
1099uiresume(handles.get_field);
1100drawnow
1101% this function then activate get_field_OutputFcn
1102
1103%------------------------------------------------------------------------
1104% --- Executes when the GUI is closed by the mouse on upper right corner.
1105%------------------------------------------------------------------------
1106function closefcn(hObject, eventdata, handles)
1107handles.output=[];
1108guidata(hObject, handles);% Update handles structure
1109uiresume(handles.get_field);
1110drawnow
1111
1112%------------------------------------------------------------------------
1113% --- Outputs from this function are returned to the command line.
1114%------------------------------------------------------------------------
1115function varargout = get_field_OutputFcn(hObject, eventdata, handles)
1116
1117varargout{1} =handles.output;
1118delete(handles.get_field)
Note: See TracBrowser for help on using the repository browser.