#!/usr/bin/env python3

import cf
import cfplot as cfp
import numpy as np
import os
import sys
import argparse
import matplotlib.pyplot as plt
import matplotlib
from PyQt5.QtWidgets import QApplication, QLabel, QCheckBox, QFileDialog, QDialog, QRadioButton
from PyQt5.QtWidgets import QComboBox, QListWidget, QListWidgetItem, QHBoxLayout, QVBoxLayout, QWidget, QPushButton
from PyQt5.QtWidgets import QLineEdit, QTextEdit, QSlider, QMenu, QAction, QFontDialog, QMenuBar
from PyQt5.QtWidgets import QMainWindow, QFrame, QSizePolicy, QScrollBar, QScrollArea, QFormLayout, QGroupBox, QTableWidget
from PyQt5.QtWidgets import QTableWidgetItem, QTableView, QSlider, QAbstractScrollArea
from PyQt5.QtCore import Qt, QObject, pyqtSignal, QAbstractTableModel, QVariant, QCoreApplication
from PyQt5.QtGui import QFont, QPalette, QColor, QTextDocument, QPixmap, QStandardItemModel, QFontDatabase, QFontMetrics
from copy import deepcopy
from functools import partial



# Initiate the pvars class
# This is used for storing plotting variables in cfp.plotvars
class pvars(object):
    def __init__(self, **kwargs):
        '''Initialize a new Pvars instance'''
        for attr, value in kwargs.items():
            setattr(self, attr, value)

    def __str__(self):
        '''x.__str__() <==> str(x)'''
        a = None
        v = None
        out = ['%s = %s' % (a, repr(v))]
        for a, v in self.__dict__.items():
            return '\n'.join(out)

cols = ['#abb6d4', '#7085c4', '#ffffff', '#f1f4fd', '#000000', '#000000']

plotvars=pvars(pos=0, nplots=1, code='', plot_counter=0, title='', field_selected='',\
               file_selected=None, data=None, levs_automatic_set=True, levs_set=False,\
               levs_manual_set=False, levs_min='0', levs_max='0', levs_step='0',levs_manual='',\
               levs_extend_lower=True, levs_extend_upper=True, colorbar=True,\
               colorbar_orientation=None,\
               proj='cyl', lonmin='-180', lonmax='180', latmin='-90', latmax='90',\
               boundinglat='0', lon_0='0',
               resolution='c', continent_thickness='1.5', continent_color='black',\
               vect_ufield='', vect_auto_set=True, vect_length='10', vect_scale='100',\
               vect_stride='1', vect_pts='30', vect_stride_set=False,vect_pts_set=False,\
               cscales=None, cscale_automatic_set=True, cscale_reverse_set=False, cscale_white='',\
               cscale_ncols='', cscale_above='', cscale_below='',cscale='viridis',\
               invalid_input=False, index_number=0, fields=None,\
               field__widget_indicies=None, field_widget_names=None, field_widget_title=None,\
               field_widget_listing='index', plot_type = 'Contour', contour_type='x-y', \
               collapse_x='Off', collapse_y='Off', collapse_z='Off', collapse_t='Off',\
               nx_length=None, ny_length=None, nz_length=None, nt_length=None,\
               stored_dimensions=None, stored_collapses=None, stored_collapse_values=None,\
               stored_lock = False,\
               background_colour=cols[0], button_colour=cols[1], buttontext_colour=cols[2],\
               highlight_colour=cols[3], text_colour=cols[4], windowtext_colour=cols[5],\
               text_colour_insensitive = '#708090', font="DejaVu Sans", font_mono='DejaVu Sans Mono',\
               fontsize=15, fill=True, blockfill=False, lines=False, line_labels=False, titles=True,\
               write_defaults=False, collapse_types=None, line_colour = 'C0',\
               line_style='solid', line_xmin=None, line_xmax=None, line_ymin=None, line_ymax=None,\
               line_title='', line_width='1.0', line_marker = '', line_markersize='',\
               line_markeredgecolor='', line_markeredgewidth='', line_limits='automatic')


cscales=['viridis', 'magma', 'inferno', 'plasma', 'parula', 'gray', 'hotcold_18lev', 'hotcolr_19lev',
'mch_default', 'perc2_9lev', 'percent_11lev', 'precip2_15lev', 'precip2_17lev', 'precip3_16lev',
'precip4_11lev', 'precip4_diff_19lev', 'precip_11lev', 'precip_diff_12lev', 'precip_diff_1lev', 'rh_19lev',
'spread_15lev', 'amwg', 'amwg_blueyellowred', 'BlueDarkRed18', 'BlueDarkOrange18', 'BlueGreen14', 'BrownBlue12',
'Cat12', 'cmp_flux', 'cosam12', 'cosam', 'GHRSST_anomaly', 'GreenMagenta16',
'nrl_sirkes', 'nrl_sirkes_nowhite','prcp_1', 'prcp_2',
'prcp_3', 'radar', 'radar_1', 'seaice_1', 'seaice_2', 'so4_21',
'StepSeq25', 'sunshine_9lev', 'sunshine_diff_12lev', 'temp_19lev', 'temp_diff_18lev', 'temp_diff_1lev',
'topo_15lev', 'wgne15', 'wind_17lev', 'amwg256', 'BkBlAqGrYeOrReViWh200', 'BlAqGrYeOrRe', 'BlAqGrYeOrReVi200',
'BlGrYeOrReVi200', 'BlRe', 'BlueRed', 'BlueRedGray', 'BlueWhiteOrangeRed', 'BlueYellowRed', 'BlWhRe', 'cmp_b2r',
'cmp_haxby', 'detail', 'extrema', 'GrayWhiteGray', 'GreenYellow', 'helix', 'helix1', 'hotres', 'matlab_hot',
'matlab_hsv', 'matlab_jet', 'matlab_lines', 'ncl_default', 'ncview_default', 'OceanLakeLandSnow', 'rainbow',
'rainbow_white_gray', 'rainbow_white', 'rainbow_gray', 'tbr_240_300', 'tbr_stdev_0_30', 'tbr_var_0_500',
'tbrAvg1', 'tbrStd1', 'tbrVar1', 'thelix', 'ViBlGrWhYeOrRe', 'wh_bl_gr_ye_re', 'WhBlGrYeRe', 'WhBlReWh',
'WhiteBlue', 'WhiteBlueGreenYellowRed', 'WhiteGreen', 'WhiteYellowOrangeRed', 'WhViBlGrYeOrRe', 'WhViBlGrYeOrReWh',
'wxpEnIR', '3gauss', '3saw', 'posneg_2', 'posneg_1',
'os250kmetres', 'wiki_1_0_2', 'wiki_1_0_3', 'wiki_2_0',
'wiki_2_0_reduced', 'arctic', 'scale1', 'scale2', 'scale3', 'scale4', 'scale5', 'scale6', 'scale7', 'scale8',
'scale9', 'scale10', 'scale11', 'scale12', 'scale13', 'scale14', 'scale15', 'scale16', 'scale17' , 'scale18',
'scale19', 'scale20', 'scale21', 'scale22', 'scale23', 'scale24', 'scale25', 'scale26', 'scale27', 'scale28',
'scale29', 'scale30', 'scale31', 'scale32', 'scale33', 'scale34', 'scale35', 'scale36', 'scale37', 'scale38',
'scale39', 'scale40', 'scale41', 'scale42', 'scale43', 'scale44']

plotvars.cscales=cscales

plotvars.collapse_types = ['Off', 'mean', 'minimum', 'maximum', 'variance', 'standard_deviation']



class EmittingStream(QObject):

    textWritten = pyqtSignal(str)

    def write(self, text):
        self.textWritten.emit(str(text))

    def flush(self):
        pass


def my_excepthook(type, value, tback):
    # log the exception here

    # then call the default handler
    sys.__excepthook__(type, value, tback)

sys.excepthook = my_excepthook












class Cfview(QMainWindow):
    def __init__(self, filename, defaults, parent=None):
        super(Cfview, self).__init__()
        plotvars.file_selected = filename
        self.parent = self

        # Read in the defaults file if it exists
        full_path = os.path.expanduser(defaults)
        check = os.path.isfile(full_path) 

        if check:

            datafile = open(full_path, 'r')
            for line in datafile:
                vars = line.split(' ')
                if line[0] != '#' and len(vars) > 1:
                    var = vars[0]
                    value = ''
                    for i in np.arange(len(vars[1:])):
                        if i > 0:
                            value += ' ' 
                        value += vars[i+1]
                    value = value.replace("\n", "")

                    if value == 'True':
                        value = True
                    if value == 'False':
                        value = False
            
                    if var == 'fontsize':
                        value = int(value)

                    setattr(plotvars, var, value)
        else:
            if defaults != '~/.cfview_defaults':
                print("\nDefaults file " + defaults + " doesn't exist\n")


        self.initUI()


    def initUI(self):

        # Set standard out to go to EmittingStream
        #sys.stdout = EmittingStream(textWritten=self.output_terminal_written)

        QCoreApplication.setAttribute(Qt.AA_DontUseNativeDialogs)

        # Add a top menu bar
        bar = self.menuBar()
        # Turn off Mac bar relocation 
        bar.setNativeMenuBar(False)

        file = bar.addMenu("File")
        file.addAction("Open")
        file.addAction("Save")
        file.addAction("Exit")
        file.triggered.connect(self.file_menu)


        edit = bar.addMenu("Edit")
        edit.addAction("Copy field")
        edit.addAction("Delete selected fields")
        edit.addAction("Delete all fields")
        edit.triggered.connect(self.menu)


        setup = bar.addMenu("Setup")
        setup.addAction("cfview defaults")
        setup.addAction("contours")
        setup.addAction("lines")
        setup.addAction("vectors")
        setup.addAction("map")
        setup.addAction("colour scale")
        setup.addAction("contour levels")
        setup.triggered.connect(self.menu)

        view = bar.addMenu("View")
        view.addAction("code")
        view.addAction("data")
        view.addAction("names")
        view.addAction("transform")
        view.triggered.connect(self.menu)

        help = bar.addMenu("Help")
        help.addAction("cfview")
        help.addAction("about")
        help.triggered.connect(self.menu)


        # Set up some buttons
        plotButton = QPushButton("Plot")
        plotButton.clicked.connect(self.plot)

        reset_dimensionButton = QPushButton("Reset Dimensions")
        reset_dimensionButton.clicked.connect(lambda: self.dim_reset('reset'))


        # Plot type combobox
        plot_type_ComboBox = QComboBox()
        plot_type_ComboBox.addItem('Contour')
        plot_type_ComboBox.addItem('Vector')
        plot_type_ComboBox.addItem('Contour and vector')
        plot_type_ComboBox.addItem('Line')
        plot_type_ComboBox.activated[str].connect(self.plot_type)


        # Contour type drop down menu
        contour_type_ComboBox = QComboBox()
        contour_type_ComboBox.addItem('x-y')
        contour_type_ComboBox.addItem('x-z')
        contour_type_ComboBox.addItem('x-logz')
        contour_type_ComboBox.addItem('x-t')
        contour_type_ComboBox.addItem('y-z')
        contour_type_ComboBox.addItem('y-logz')
        contour_type_ComboBox.addItem('y-t')
        contour_type_ComboBox.addItem('t-x')
        contour_type_ComboBox.addItem('t-y')
        contour_type_ComboBox.addItem('t-z')
        contour_type_ComboBox.addItem('t-logz')
        contour_type_ComboBox.activated[str].connect(self.contour_type)

        # Line type drop down menu
        line_type_ComboBox = QComboBox()
        line_type_ComboBox.addItem('x')
        line_type_ComboBox.addItem('y')
        line_type_ComboBox.addItem('z')
        line_type_ComboBox.addItem('t')


        # Dimension selection
        dimLabel = QLabel('Select:')
        xRadioButton = QRadioButton("x")
        yRadioButton = QRadioButton("y")
        zRadioButton = QRadioButton("z")
        tRadioButton = QRadioButton("t")
        xRadioButton.clicked.connect(lambda: self.dim_view('x'))
        yRadioButton.clicked.connect(lambda: self.dim_view('y'))
        zRadioButton.clicked.connect(lambda: self.dim_view('z'))
        tRadioButton.clicked.connect(lambda: self.dim_view('t'))
        xRadioButton.setChecked(True)

        # Collapse labels and boxes
        collapse_areaLabel = QLabel('Area:')
        collapse_xLabel = QLabel('X:')
        collapse_yLabel = QLabel('Y:')
        collapse_zLabel = QLabel('Z:')
        collapse_tLabel = QLabel('T:')
        collapse_types = plotvars.collapse_types
        collapse_areaComboBox = QComboBox()
        collapse_xComboBox = QComboBox()
        collapse_yComboBox = QComboBox()
        collapse_zComboBox = QComboBox()
        collapse_tComboBox = QComboBox()
        for collapse in collapse_types:
            collapse_areaComboBox.addItem(collapse)
            collapse_xComboBox.addItem(collapse)
            collapse_yComboBox.addItem(collapse)
            collapse_zComboBox.addItem(collapse)
            collapse_tComboBox.addItem(collapse)
        #collapse_areaComboBox.activated.connect(lambda: self.collapse_area())
        collapse_areaComboBox.activated[str].connect(self.collapse_area)
        collapse_xComboBox.activated.connect(lambda: self.collapse_type('x'))
        collapse_yComboBox.activated.connect(lambda: self.collapse_type('y'))
        collapse_zComboBox.activated.connect(lambda: self.collapse_type('z'))
        collapse_tComboBox.activated.connect(lambda: self.collapse_type('t'))


        # Field selection widgets
        indexCheckBox = QCheckBox("index")
        indexCheckBox.setChecked(True)
        indexCheckBox.clicked.connect(lambda: self.field_widget_listing('index'))
        fieldCheckBox = QCheckBox("field name")
        fieldCheckBox.setChecked(False)
        fieldCheckBox.clicked.connect(lambda: self.field_widget_listing('field'))
        sort_byLabel = QLabel('Order by:')
        search_fieldsLabel = QLabel('Search:')
        search_fieldsTextbox = QLineEdit()
        search_fieldsTextbox.textChanged.connect(self.search_fields)


        fieldlist = QListWidget()
        fieldlist.setSelectionMode(QListWidget.ExtendedSelection)

        field_titles = QLabel('Index  nx  ny  nz  nt  field name')

        if plotvars.file_selected is not None:
            f = cf.read(plotvars.file_selected)
            plotvars.fields = f

            field_widget_names, field_widget_title = Cf_funcs.fields_list(fields=f, order=plotvars.field_widget_listing)
            field_titles = QLabel(field_widget_title)

            for i in np.arange(len(f)):
                #print('field_widget_names , i are ', field_widget_names[i], i) 
                QListWidgetItem(field_widget_names[i], fieldlist) 
            fieldlist.setCurrentRow(0)


        fieldlist.setCurrentRow(0)
        fieldlist.itemSelectionChanged.connect(self.fieldnumber)

        # Set fixed width font for field titles
        custom_font_fixed_width = QFont(plotvars.font_mono, plotvars.fontsize)
        field_titles.setFont(custom_font_fixed_width)
        fieldlist.setFont(custom_font_fixed_width)


        # Messages label
        messagesLabel = QLabel('Output messages')
        messagesLabel.setAlignment(Qt.AlignCenter)




        # Dimension lists
        dimension_titles = QLabel('Dimension view')
        if plotvars.file_selected is not None:
            nx, ny, nz, nt, x, y, z, t = Cf_funcs.field_dims(field=f[0])
            dims_field = [nx, ny, nz, nt, x, y, z, t]
            
        xlist = QListWidget()
        ylist = QListWidget() 
        zlist = QListWidget()
        tlist = QListWidget()

        dim_lists = [xlist, ylist, zlist, tlist]

        for i in np.arange(4):
            dim_lists[i].setSelectionMode(QListWidget.ExtendedSelection)
            dim_lists[i].setFont(custom_font_fixed_width)
            #dim_lists[i].setCurrentRow(0)
            #dim_lists[i].selectAll()
            #dim_lists[i].itemSelectionChanged.connect(self.reset_field_title)

            if plotvars.file_selected is not None:
                if dims_field[i] > 0:
                    for val in dims_field[i+4]:
                        QListWidgetItem(str(val), dim_lists[i])
                        dim_lists[i].selectAll()



        # Set the stored_dimensions and stored_collapses for each of the fields in the field list
        # -1 indicates that the dimension is unchanged by the user
        plotvars.stored_dimensions = {}
        plotvars.stored_collapses = {}
        plotvars.stored_collapse_values = {}
        if plotvars.file_selected is not None:
            for i in np.arange(len(f)):
                plotvars.stored_dimensions['f' + str(i)] = {'x': -1, 'y': -1, 'z': -1, 't': -1}
                plotvars.stored_collapses['f' + str(i)] = {'x': 'Off', 'y': 'Off', 'z': 'Off', 't': 'Off'}
                plotvars.stored_collapse_values['f' + str(i)] = {'x': False, 'y': False, 'z': False, 't': False}


        # Collapse lists - these will have just one value
        xlist_collapse = QListWidget()
        ylist_collapse = QListWidget()
        zlist_collapse = QListWidget()
        tlist_collapse = QListWidget()
        
        # Set font and selection mode
        collapse_lists = [xlist_collapse, ylist_collapse, zlist_collapse, tlist_collapse]
        for collapse_list in collapse_lists:
            collapse_list.setFont(custom_font_fixed_width)
            collapse_list.setSelectionMode(QListWidget.ExtendedSelection)



        # Vector and contour and vector hbox
        contour_vector_indexHbox = QHBoxLayout()
        contour_indexLabel = QLabel('Contour Index')
        contour_indexComboBox = QComboBox()
        vector_x_indexLabel = QLabel('Vector x Index')
        vector_x_indexComboBox = QComboBox()
        vector_y_indexLabel = QLabel('Vector y Index')
        vector_y_indexComboBox = QComboBox()
        contour_vector_indexHbox.addWidget(contour_indexLabel)
        contour_vector_indexHbox.addWidget(contour_indexComboBox)
        contour_vector_indexHbox.addWidget(vector_x_indexLabel)
        contour_vector_indexHbox.addWidget(vector_x_indexComboBox)
        contour_vector_indexHbox.addWidget(vector_y_indexLabel)
        contour_vector_indexHbox.addWidget(vector_y_indexComboBox)

        objs = [contour_indexLabel, contour_indexComboBox,
        vector_x_indexLabel, vector_x_indexComboBox,
        vector_y_indexLabel, vector_y_indexComboBox]

        for obj in objs:
            obj.setVisible(False)




        # Output window
        output_terminal_textEdit = QTextEdit()

        # Define the top level containers to put the widgets in
        outerLayout = QHBoxLayout()
        leftLayout = QVBoxLayout()
        rightLayout = QVBoxLayout()

        # Define the left layout widget boxes
        leftHbox0 = QHBoxLayout()
        leftHbox1 = QHBoxLayout()
        leftHbox2 = QHBoxLayout()
        leftHbox3 = QHBoxLayout()
        leftHbox4 = QHBoxLayout()
        leftHbox5 = QHBoxLayout()

        # Define the right layout widget boxes
        rightHbox1 = QHBoxLayout()
        rightHbox2 = QHBoxLayout()
        rightHbox3 = QHBoxLayout()
        rightHbox4 = QHBoxLayout()

        # containers for field and dimension lists
        field_container = QVBoxLayout()
        field_container1 = QVBoxLayout()
        field_container1.setContentsMargins(2,0,0,0)
        field_container2 = QVBoxLayout()
        dimension_container = QVBoxLayout()

        # Assemble the layout boxes
        leftLayout.addLayout(leftHbox1)
        leftLayout.addLayout(leftHbox2)
        leftLayout.addLayout(leftHbox3)
        leftLayout.addLayout(leftHbox4)
        leftLayout.addLayout(leftHbox5)

        rightLayout.addLayout(rightHbox1)
        rightLayout.addLayout(contour_vector_indexHbox)
        rightLayout.addLayout(rightHbox2)
        rightLayout.addLayout(rightHbox3)
        rightLayout.addLayout(rightHbox4)

        outerLayout.addLayout(leftLayout)
        outerLayout.addLayout(rightLayout)

        # Add widgets to the appropriate boxes
        rightHbox1.addWidget(plot_type_ComboBox)
        rightHbox1.addWidget(contour_type_ComboBox)
        rightHbox1.addWidget(line_type_ComboBox)
        line_type_ComboBox.setVisible(False)

        rightHbox1.addWidget(plotButton)

        leftHbox2.addLayout(field_container)

        field_container.addLayout(field_container1)
        field_container.addLayout(field_container2)
        field_container1.addWidget(field_titles)
        field_container2.addWidget(fieldlist)


        rightHbox2.addLayout(dimension_container)
        dimension_container.addWidget(dimension_titles)
        dimension_container.addWidget(xlist)
        dimension_container.addWidget(ylist)
        dimension_container.addWidget(zlist)
        dimension_container.addWidget(tlist)
        dimension_container.addWidget(xlist_collapse)
        dimension_container.addWidget(ylist_collapse)
        dimension_container.addWidget(zlist_collapse)
        dimension_container.addWidget(tlist_collapse)



        rightHbox3.addWidget(dimLabel)
        rightHbox3.addWidget(xRadioButton)
        rightHbox3.addWidget(yRadioButton)
        rightHbox3.addWidget(zRadioButton)
        rightHbox3.addWidget(tRadioButton)
        rightHbox3.addWidget(reset_dimensionButton)




        leftHbox3.addWidget(sort_byLabel)
        leftHbox3.addWidget(indexCheckBox)
        leftHbox3.addWidget(fieldCheckBox)
        leftHbox3.addWidget(search_fieldsLabel)
        leftHbox3.addWidget(search_fieldsTextbox)
        leftHbox4.addWidget(messagesLabel)
        leftHbox5.addWidget(output_terminal_textEdit)
        

        widget = QWidget()
        widget.setLayout(outerLayout)
        self.setCentralWidget(widget)

       


        self.field_titles = field_titles
        self.fieldlist = fieldlist
        self.xlist = xlist
        self.ylist = ylist
        self.zlist = zlist
        self.tlist = tlist
        self.xlist_collapse = xlist_collapse
        self.ylist_collapse = ylist_collapse
        self.zlist_collapse = zlist_collapse
        self.tlist_collapse = tlist_collapse
        self.collapse_areaComboBox = collapse_areaComboBox
        self.collapse_areaLabel = collapse_areaLabel
        self.collapse_xLabel = collapse_xLabel
        self.collapse_yLabel = collapse_yLabel
        self.collapse_zLabel = collapse_zLabel
        self.collapse_tLabel = collapse_tLabel
        self.contour_type_ComboBox = contour_type_ComboBox
        self.line_type_ComboBox = line_type_ComboBox

        self.ylist.setVisible(False)
        self.zlist.setVisible(False)
        self.tlist.setVisible(False)
        self.xlist_collapse.setVisible(False)
        self.ylist_collapse.setVisible(False)
        self.zlist_collapse.setVisible(False)
        self.tlist_collapse.setVisible(False)


        self.xRadioButton = xRadioButton
        self.yRadioButton = yRadioButton
        self.zRadioButton = zRadioButton
        self.tRadioButton = tRadioButton

        self.collapse_xComboBox = collapse_xComboBox
        self.collapse_yComboBox = collapse_yComboBox
        self.collapse_zComboBox = collapse_zComboBox
        self.collapse_tComboBox = collapse_tComboBox

        self.contour_vector_indexHbox = contour_vector_indexHbox
        self.contour_indexLabel = contour_indexLabel
        self.contour_indexComboBox = contour_indexComboBox
        self.vector_x_indexLabel = vector_x_indexLabel
        self.vector_x_indexComboBox = vector_x_indexComboBox
        self.vector_y_indexLabel = vector_y_indexLabel
        self.vector_y_indexComboBox = vector_y_indexComboBox

        self.indexCheckBox = indexCheckBox
        self.fieldCheckBox = fieldCheckBox
        self.search_fieldsTextbox = search_fieldsTextbox
        self.reset_dimensionButton = reset_dimensionButton

        self.cfview_defaults = None  # No external window yet.
        self.contour_window = None  # No external window yet.
        self.contour_levels = None  # No external window yet.
        self.line_window = None  # No external window yet.
        self.colour_scale = None  # No external window yet.
        self.map_window = None  # No external window yet.
        self.data_window = None  # No external window yet.
        self.names_window = None  # No external window yet.
        self.transform_window = None  # No external window yet.
        self.about_window = None  # No external window yet.
        self.cfview_window = None  # No external window yet.

        self.output_terminal_textEdit = output_terminal_textEdit


        palette = QPalette()    
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))    
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))    
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        self.setPalette(palette)


        # Set main font
        db = QFontDatabase()
        fonts = QFontDatabase().families()
        test_fonts = ['Times', 'Helvetica', 'Arial', deepcopy(plotvars.font)]
        for font in test_fonts:
            if font in fonts:
                plotvars.font = font

        custom_font = QFont(plotvars.font, plotvars.fontsize)
        self.window().setFont(custom_font)
        file.setFont(custom_font)
        edit.setFont(custom_font)
        setup.setFont(custom_font)
        view.setFont(custom_font)
        help.setFont(custom_font)

        # Set mono font for field titles and field list
        test_fonts = ['Times', 'Helvetica', 'Courier', 'Menlo', 'Monaco', deepcopy(plotvars.font_mono)]
        for font in test_fonts:
            if font in fonts:
                plotvars.font_mono = font

        custom_font_mono = QFont(plotvars.font_mono, plotvars.fontsize)
        self.field_titles.setFont(custom_font_mono)
        self.fieldlist.setFont(custom_font_mono)

        # Set standard out to go to EmittingStream
        sys.stdout = EmittingStream(textWritten=self.output_terminal_written)


        # Set window size and show the window
        self.setGeometry(0, 0, 1280, 1060)
        self.setWindowTitle('cfview')

        self.show()


    def open_file(self, s):
 
        dialog = QFileDialog()
        dialog.setOption(QFileDialog.DontUseNativeDialog, True)
        #dialog.setOption(QCoreApplication.AA_DontUseNativeDialogs, True)
        dialog.setAcceptMode(QFileDialog.AcceptOpen)
        dialog.setNameFilters(["netCDF Files (*.nc)", "Met Office PP Files (*.pp)", "All Files (*.*)"])
        dialog.setFileMode(QFileDialog.ExistingFiles)

 
        palette = QPalette()    
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))    
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))    
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        dialog.setPalette(palette)

        custom_font = QFont(plotvars.font, plotvars.fontsize)
        dialog.setFont(custom_font)

        path =  ''
        if dialog.exec_() == QDialog.Accepted:
            path =  dialog.selectedFiles()


        try:
            if path != '':
                f = cf.read(path)

                plotvars.file_selected = path

                self.fieldlist.clear()
                self.search_fieldsTextbox.clear()
                plotvars.index_number = 0
                plotvars.fields = f
                plotvars.field_widget_indicies = None

                field_widget_names, field_widget_title = Cf_funcs.fields_list(fields=f, order=plotvars.field_widget_listing)

                # Set the stored_dimensions
                # -1 indicates that the dimension is unchanged
                plotvars.stored_dimensions = {}
                plotvars.stored_collapses = {}
                if plotvars.file_selected is not None:
                    for i in np.arange(len(f)):
                        plotvars.stored_dimensions['f' + str(i)] = {'x': -1, 'y': -1, 'z': -1, 't': -1}
                        plotvars.stored_collapses['f' + str(i)] = {'x': 'Off', 'y': 'Off', 'z': 'Off', 't': 'Off'}
                        plotvars.stored_collapse_values['f' + str(i)] = {'x': False, 'y': False, 'z': False, 't': False}

                for i in np.arange(len(f)):
                    QListWidgetItem(field_widget_names[i], self.fieldlist) 
                self.fieldlist.setCurrentRow(0) 

                self.field_titles.setText(field_widget_title)

                # Reset the dimension lists
                self.xlist.clear()
                self.xlist_collapse.clear()
                if f[0].has_construct('X'):
                    xvals = f[0].coord('X').array
                    for xval in xvals:
                        QListWidgetItem(str(xval), self.xlist) 
                    self.xlist.selectAll()

                self.ylist.clear()
                self.ylist_collapse.clear()
                if f[0].has_construct('Y'):
                    yvals = f[0].coord('Y').array
                    for yval in yvals:
                        QListWidgetItem(str(yval), self.ylist) 
                    self.ylist.selectAll()

                self.zlist.clear()
                self.zlist_collapse.clear()
                if f[0].has_construct('Z'):
                    zvals = f[0].coord('Z').array
                    for zval in zvals:
                        QListWidgetItem(str(zval), self.zlist) 
                    self.zlist.selectAll()

                self.tlist.clear()
                self.tlist_collapse.clear()
                if f[0].has_construct('T'):
                    tvals = f[0].coord('T').dtarray
                    for tval in tvals:
                        QListWidgetItem(str(tval), self.tlist) 
                    self.tlist.selectAll()


                # Reset lists and check boxes
                self.dim_reset('reset')

                # Print which file has been opened in the messages window
                print('File read: ' + str(path))

        except ValueError:
            print('file not a valid, netCDF, PP or fields file')




    def save_file(self, s):

        dialog = QFileDialog()

        dialog.setAcceptMode(QFileDialog.AcceptSave)
        dialog.setNameFilters(["netCDF Files (*.nc)", "All Files (*.*)"])
        dialog.setOption(QFileDialog.DontUseNativeDialog, True)
        #dialog.setOption(QCoreApplication.DontUseNativeDialogs, True)
        #dialog.setOption(QFileDialog.AA_DontUseNativeDialogs, True)
 
        palette = QPalette()    
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))    
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))    
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        dialog.setPalette(palette)

        custom_font = QFont(plotvars.font, plotvars.fontsize)
        dialog.setFont(custom_font)

        path =  ''
        if dialog.exec_() == QDialog.Accepted:
            path =  dialog.selectedFiles()[0]

        # Return if no file specified or if cancel has been pressed
        if len(path) == 0:
            return


        # Assemble cf-python code to write the file
        com = 'import cf\n'
      
        com += "f = cf.read('"+ plotvars.file_selected + "')\n"
        com += 'write_fields = []\n'

        # Assemble the selected field indicies from the field titles
        selected = self.fieldlist.selectedItems()
        indicies = []
        for i in np.arange(len(selected)):
            field_title = selected[i].text()
            indicies.append(int(field_title.split()[0]))
        print('selected indicies are ', indicies)

        dims = ['X', 'Y', 'Z', 'T']

        write_fields = []

        # Set the data file
        f = plotvars.fields

        # Loop over the selected fields
        for index in np.arange(len(indicies)):

            # Form the subspace dictionary
            stored = plotvars.stored_dimensions['f' + str(indicies[index])]

            subspace_args = {}

            # Find the original nx, ny, nz, nt for this field
            field = f[indicies[index]]
            com += 'field = f[' + str(indicies[index]) + ']\n'
            nx, ny, nz, nt, x, y, z, t = Cf_funcs.field_dims(field=field)
            orig_vals = [nx, ny, nz, nt]

            for i in np.arange(4):
                # dim_indicies = -1 means no user change to this dimension
                dim_indicies = stored[dims[i].lower()]
                if i <= 2:
                    dim_vals = field.coord(dims[i]).array
                else:
                    dim_vals = field.coord(dims[i]).dtarray


                if dim_indicies != -1:
                    if len(dim_indicies) == 1:
                        subspace_args[dims[i]] = dim_vals[dim_indicies[0]]
                        com += 'field = field.subspace(' + dims[i] + '=' + str(dim_vals[dim_indicies[0]]) + ')\n'
                    else:

                        # Check for contiguous data selection
                        contig = True
                        if max(dim_indicies) - min(dim_indicies) != len(dim_indicies) - 1:
                            contig = False

                        valmin = dim_vals[min(dim_indicies)]
                        valmax = dim_vals[max(dim_indicies)]

                        # cf-python needs ascending values for cf.wi
                        if valmax < valmin:
                            valmin, valmax = valmax, valmin

                        if contig:
                            subspace_args[dims[i]] = cf.wi(valmin, valmax)
                            com += 'field = field.subspace(' + dims[i] + ' = cf.wi('
                            com +=  str(valmin) + ', ' + str(valmax) + '))\n'
                        else:
                            subspace_args[dims[i]] = sorted(dim_indicies)
                            com += 'field = field.subspace(' + dims[i] + '= ['
                            for ind in np.arange(len((dim_indicies))):
                                com += str(sorted(dim_indicies)[ind]) 
                                if ind < len(dim_indicies) - 1:
                                    com += ', ' 
                            com += '])\n'


            # Form the collapse string
            collapse_str = ''
            stored = plotvars.stored_collapses['f' + str(indicies[index])] 
            for i in np.arange(4):
                 if stored[dims[i].lower()] != 'Off':
                     collapse_str += dims[i] + ': ' + stored[dims[i].lower()] + ' '
            if len(collapse_str) > 0:
                if collapse_str[-1] == ' ':
                    collapse_str = collapse_str[:-1]


            # Subspace and collapse the data if required
            if len(subspace_args) > 0:
                field = field.subspace(**subspace_args)

            if len(collapse_str) > 0:
                field = field.collapse(collapse_str)
                write_fields.append(field)
                com += "field = field.collapse('" + collapse_str + "')\n" 

            write_fields.append(field)
            com += 'write_fields.append(field)\n' 



        # Write the netCDF file
        cf.write(write_fields, path)

        # Show the cf-python code
        com += "cf.write(write_fields, '" + path + "')"
        print('cf-python code to write file is:', com)


        


    def plot(self, s):
        # Make a plot

        index = plotvars.index_number

        # Return if no field
        if index == -1:
            return

        # Make a copy of the field for plotting
        f = deepcopy(plotvars.fields[index])


        # Check data and subspace if necessary
        subspace_args = {}
        con_args = {}
        dims = ['X', 'Y', 'Z', 'T']


        if plotvars.plot_type == 'Contour':

            # Check selected data has enough items to be a contour plot
            nx, ny, nz, nt = Cf_funcs.selected_dims(self.parent)
            dim_sizes = [nx, ny, nz, nt]

            for i in np.arange(4):
                if any(dim == dims[i].lower() for dim in plotvars.contour_type):
                    if dim_sizes[i] < 2:

                        errstr = '\nContour error - not enough data to make requested '
                        errstr += plotvars.contour_type + ' contour plot\n'
                        errstr += 'Need a minimum of two values per contour plot dimension\n'
                        errstr += 'Field dimensions are\n'
                        errstr += 'nx = ' + str(nx) + '\n'
                        errstr += 'ny = ' + str(ny) + '\n'
                        errstr += 'nz = ' + str(nz) + '\n'
                        errstr += 'nt = ' + str(nt) + '\n'
                        print(errstr)
                        return



            # Form the subspace dictionary
            subspace_args = Cf_funcs.subspace_args(self.parent)


            # Form the contour dictionary

            if plotvars.fill and not plotvars.lines:
                con_args['lines'] = False
            if not plotvars.fill and plotvars.lines:
                con_args['fill'] = False
                con_args['lines'] = True

            if plotvars.blockfill and not plotvars.lines:
                con_args['blockfill'] = True
                con_args['lines'] = False

            if plotvars.blockfill and plotvars.lines:
                con_args['blockfill'] = True
                con_args['lines'] = True

            if plotvars.lines and not plotvars.line_labels:
                con_args['line_labels'] = False

            if plotvars.colorbar is False:
                con_args['colorbar'] = False
            else:
                if plotvars.colorbar_orientation == 'horizontal':
                    con_args['colorbar_orientation'] = 'horizontal'
                if plotvars.colorbar_orientation == 'vertical':
                    con_args['colorbar_orientation'] = 'vertical'

            if 'log' in plotvars.contour_type:
                con_args['ylog'] = True

            if plotvars.title == '':
                con_args['titles'] = True
            else:
                con_args['title'] = plotvars.title

            if plotvars.contour_type[0] == 't':
                con_args['swap_axes'] = True 


            # Set the map
            if plotvars.contour_type == 'x-y':
                cfp.mapset(proj=plotvars.proj)


            # Get the subspace and collapse commands
            com_subspace, com_collapse = Cf_funcs.com_subspace_collapse(subspace_args)



            # generate the code to read the data and apply subspace and collapse args
            variable_names = ['f', 'g', 'h']
            com_con, i = Cf_funcs.generate_code(com_subspace, com_collapse)



            # Add contour levels if specified
            if plotvars.levs_set:
                vals = [plotvars.levs_min, plotvars.levs_max, plotvars.levs_step]

                # Check all values are numbers
                vals_okay, errstr = Data_check.test_numbers(vals)
                if not vals_okay:
                    print('Error in evenly spaced contour levels\n' + errstr)
                    return

                # Check min < max
                vals_okay, errstr = Data_check.test_val0_lt_val1([vals[0], vals[1]])
                if not vals_okay:
                    print('contour level error\n' + errstr)
                return
    
                # Check step > 0
                vals_okay, errstr = Data_check.test_val_gt_zero(vals[2])
                if not vals_okay:
                    print('contour level step must be greater than zero\n')
                    return

                # Test for ints or floats
                all_ints, errstr = Data_check.test_integers(vals)
          

                # Set up levels and add to the com_con code
                if all_ints:
                    cfp.levs(min=int(vals[0]), max=int(vals[1]), step=int(vals[2]))
                else:
                    cfp.levs(min=float(vals[0]), max=float(vals[1]), step=float(vals[2]))
                com_con += 'cfp.levs(min=' + vals[0] + ', max=' + vals[1] + ', step=' + vals[2] + ')\n'

            elif plotvars.levs_manual_set:
                # Check inputs are numbers
                vals = plotvars.levs_manual.split(' ')
                vals_okay, errstr = Data_check.test_numbers(vals)
                if not vals_okay:
                    print('Error in manual contour levels\n' + errstr)
                    return


                # Check inputs are ascending
                vals_okay, errstr = Data_check.test_ascending(vals)
                if not vals_okay:
                    print('Error in manual contour levels\n' + errstr)
                    return

                # Check if all values are integers
                myint, errstr = Data_check.test_integers(vals)


                # Set up levels as a integer or float array
                levels = []
                for j in np.arange(np.size(vals)):
                    if myint:
                        levels.append(int(vals[j]))
                    else:
                        levels.append(float(vals[j]))

                # Set up levels as a string array
                levels_str = '['
                for j in np.arange(np.size(vals)):
                    levels_str += vals[j]
                    if j < np.size(vals)-1:
                        levels_str += ', '
                levels_str += ']'

                # Convert array to integer or float as appropriate
                if myint:
                    levels = np.array(levels).astype(int)
                else:
                    levels = np.array(levels).astype(float)


                cfp.levs(manual=levels)
                com_con += 'cfp.levs(manual=' + levels_str + ')\n'


            elif plotvars.levs_automatic_set:
                cfp.levs()



            # Colour scale settings
            if plotvars.cscale_automatic_set is False:
            
                # Check any inputs are integers
                if plotvars.cscale_ncols != '':
                    vals_okay, errstr = Data_check.test_integers(plotvars.cscale_ncols)
                    if not vals_okay:
                        print('Error in colour scale numbers\n' + errstr)
                        return

                if plotvars.cscale_above != '':
                    vals_okay, errstr = Data_check.test_integers(plotvars.cscale_above)
                    if not vals_okay:
                        print('Error in colour scale numbers\n' + errstr)
                        return

                if plotvars.cscale_below != '':
                    vals_okay, errstr = Data_check.test_integers(plotvars.cscale_below)
                    if not vals_okay:
                        print('Error in colour scale numbers\n' + errstr)
                        return


                # Check white are numbers if specified
                errstr = 'Error in colour white values\n'
                white_vals = plotvars.cscale_white.split(' ')
                if plotvars.cscale_white != '' and len(white_vals) > 0:
                    vals_okay, errstr = Data_check.test_integers(white_vals)
                    if not vals_okay:
                        print('Error in colour scale white numbers\n' + errstr)
                        return

                    white_vals = [int(i) for i in white_vals]
                    if len(white_vals) == 1:
                        white_vals = white_vals[0]
    



                # Assemble the cscale command
                # Reset cscale
                cfp.cscale()

                cscale_args = {}
                if plotvars.cscale != 'viridis':
                    cscale_args['scale'] = plotvars.cscale
                if plotvars.cscale_ncols != '':
                    cscale_args['ncols'] = int(plotvars.cscale_ncols)
                if plotvars.cscale_above != '':
                    cscale_args['above'] = int(plotvars.cscale_above)
                if plotvars.cscale_below != '':
                    cscale_args['below'] = int(plotvars.cscale_below)
                if plotvars.cscale_white != '':
                    cscale_args['white'] = white_vals
                if plotvars.cscale_reverse_set:
                    cscale_args['reverse'] = True

                if len(cscale_args) > 0:
                    cfp.cscale(**cscale_args)
                    com_cscale = 'cfp.cscale('
                    for key in cscale_args:
                        if key == 'scale':
                            com_cscale += "cscale='" + str(cscale_args[key]) + "',"
                        else: 
                            com_cscale += str(key) + '=' + str(cscale_args[key]) + ','
                    com_cscale = com_cscale[:-1] + ')\n'
                    com_con += com_cscale
            


            # Map settings
            # Reset map
            cfp.mapset()

            if plotvars.proj == 'cyl':
                # Check inputs are numbers
                vals = [plotvars.lonmin, plotvars.lonmax, plotvars.latmin, plotvars.latmax]
                vals_okay, errstr = Data_check.test_numbers(vals)
                if not vals_okay:
                    print('Error in cylindrical projection limits\n' + errstr)
                    return

                # Check lonmin < lonmax
                vals = [plotvars.lonmin, plotvars.lonmax]
                vals_okay, errstr = Data_check.test_ascending(vals)
                if not vals_okay:
                    myerr = 'Error in cylindrical projection longitude limits\n'
                    myerr += 'lonmax must be > lonmin\n'
                    print(myerr)
                    return

                # Check latmin < latmax
                vals = [plotvars.latmin, plotvars.latmax]
                vals_okay, errstr = Data_check.test_ascending(vals)
                if not vals_okay:
                    myerr = 'Error in cylindrical projection latitude limits\n'
                    myerr += 'latmax must be > latmin\n'
                    print(myerr)
                    return


                if float(plotvars.lonmin) != -180.0 or float(plotvars.lonmax) != 180 or \
                   float(plotvars.latmin) != -90.0 or float(plotvars.latmax) != 90:
                    com_con += 'cfp.mapset(lonmin=' + str(plotvars.lonmin) + ', '
                    com_con += 'lonmax=' + str(plotvars.lonmax) + ', '
                    com_con += 'latmin=' + str(plotvars.latmin) + ', '
                    com_con += 'latmax=' + str(plotvars.latmax) + ')\n'
                    cfp.mapset(float(plotvars.lonmin), float(plotvars.lonmax), \
                               float(plotvars.latmin), float(plotvars.latmax))



            if plotvars.proj == 'spstere' or plotvars.proj == 'npstere':
                # Check inputs are numbers
                vals = [plotvars.boundinglat]
                vals_okay, errstr = Data_check.test_numbers(vals)
                if not vals_okay:
                    print('Error in bounding latitude\n' + errstr)
                    return

                vals = [plotvars.lon_0]
                vals_okay, errstr = Data_check.test_numbers(vals)
                if not vals_okay:
                    print('Error in longitude centre of map domain\n' + errstr)
                    return






                cfp.mapset(proj=plotvars.proj, boundinglat=float(plotvars.boundinglat),\
                           lon_0 = float(plotvars.lon_0))

                com_con += 'cfp.mapset(proj=' + plotvars.proj
                if str(plotvars.boundinglat) != '0':
                    com_con += ', boundinglat=' + str(plotvars.boundinglat)
                if str(plotvars.lon_0) != '0':
                    com_con += ', lon_0=' + plotvars.lon_0
                com_con += ')\n'


            if plotvars.proj in ['EuroPP', 'lcc', 'merc', 'ortho', 'OSGB', 'robin', 'UKCP']:
                cfp.mapset(proj=plotvars.proj)
                com_con += 'cfp.mapset(proj=' + plotvars.proj + ')\n'


            # Set continent properties if changed
            if plotvars.continent_thickness != '1.5' or plotvars.continent_color != 'black':
                cfp.setvars(continent_thickness=float(plotvars.continent_thickness),\
                            continent_color=plotvars.continent_color)
                continent_opts = 0
                com_con += 'cfp.setvars('
                if plotvars.continent_thickness != '1.5':
                    com_con += 'continent_thickness=' + plotvars.continent_thickness
                    continent_opts += 1
                if plotvars.continent_color != 'black':
                    if continent_opts != 0:
                        com_con += ', '
                    com_con += 'continent_color=' + plotvars.continent_color

                com_con += ')\n'
 


            com_con += 'cfp.con(' + variable_names[i] 

           
            if len(con_args) > 0:
                for arg in con_args:
                    com_con += ', ' + arg + '=' + str(con_args[arg])
    
            com_con += ')'
    

            if len(subspace_args) > 0:
                f = f.subspace(**subspace_args)


            if com_collapse != '':
                f = f.collapse(com_collapse.strip("'"), weights=True)




            print('### Code for plot is ###')
            print(com_con)

            cfp.con(f, **con_args)
    
        if plotvars.plot_type == 'Line':
            # Make a line plot

            # Check selected data has enough items to make a line plot
            mydim = str(self.line_type_ComboBox.currentText())
            dims = ['x', 'y', 'z', 't']
            index = dims.index(mydim)
            nx, ny, nz, nt = Cf_funcs.selected_dims(self.parent)
            dimvals = [nx, ny, nz, nt]

            if dimvals[index] < 2:
                errstr = '\nLine plot error - not enough data to make requested '
                errstr += mydim + ' line plot\n'
                errstr += 'Need a minimum of two values along this dimension\n'
                errstr += 'Field dimensions are\n'
                errstr += 'nx = ' + str(nx) + '\n'
                errstr += 'ny = ' + str(ny) + '\n'
                errstr += 'nz = ' + str(nz) + '\n'
                errstr += 'nt = ' + str(nt) + '\n'
                print(errstr)
                return


            # Assemble the line arguments
            line_args = {}
            if plotvars.line_colour != 'C0':
                line_args['color'] =  plotvars.line_colour
            if plotvars.line_width != '1.0':
                line_args['linewidth'] =  plotvars.line_width
            if plotvars.line_style != 'solid':
                line_args['linestyle'] =  plotvars.line_style

            if plotvars.line_marker != '':
                line_args['marker'] =  plotvars.line_marker
            if plotvars.line_markersize != '':
                line_args['markersize'] =  plotvars.line_markersize
            if plotvars.line_markeredgecolor != '':
                line_args['markeredgecolor'] =  plotvars.line_markeredgecolor
            if plotvars.line_markeredgewidth != '':
                line_args['markeredgewidth'] =  plotvars.line_markeredgewidth

            if plotvars.line_title != '':
                line_args['title'] =  plotvars.line_title
            else:
                line_args['titles'] =  True


            # Form the subspace dictionary
            subspace_args = Cf_funcs.subspace_args(self.parent)

            print('subspace_args are', subspace_args)

            # Get the subspace and collapse commands
            com_subspace, com_collapse = Cf_funcs.com_subspace_collapse(subspace_args)


            print('com_subspace is ', com_subspace)

            print('com_collapse is ', com_collapse)


            # Form the cf-python / cf-plot code to generate the plot
            
            #line_con = Cf_funcs.generate_cf_code()

            # generate the code to read the data and apply subspace and collapse args
            variable_names = ['f', 'g', 'h']
            com_line, i = Cf_funcs.generate_code(com_subspace, com_collapse)
            print('com_line is ', com_line)
            print('i is ', i)


            # Set data limits if requested
            cfp.gset()
            if plotvars.line_limits == 'user':
                print('setting user data limits')
                # Check data is numbers

                cfp.gset(float(plotvars.line_xmin), float(plotvars.line_xmax), float(plotvars.line_ymin), float(plotvars.line_ymax))

                com_line += 'cfp.gset(xmin=' + plotvars.line_xmin + ', '
                com_line += 'xmax=' + plotvars.line_xmax + ', '
                com_line += 'ymin=' + plotvars.line_ymin + ', '

                com_line += 'ymax=' + plotvars.line_ymax + ')\n'

              
            # Make the line plot
            if len(subspace_args) > 0:
                f = f.subspace(**subspace_args)

            if com_collapse != '':
                f = f.collapse(com_collapse.strip("'"), weights=True)

            cfp.lineplot(f, **line_args)

            # Show the commands to make this line plot
            com_line += 'cfp.lineplot(' + variable_names[i] 

            if len(line_args) > 0:
                for arg in line_args:
                    if arg == 'thickness':
                        com_line += ', thickness =' + str(line_args[arg])
                    else:
                        com_line += ', ' + arg + "='" + str(line_args[arg]) + "'"



            com_line += ')'

            print('### Code to make plot is ### \n', com_line)
            

        if plotvars.plot_type == 'Vector':
            print('plotting vectors')
            index_x = self.vector_x_indexComboBox.currentIndex()

            index_y = self.vector_y_indexComboBox.currentIndex()

            # Check selected data has enough items to be a vector plot
            # First the x component
            nx, ny, nz, nt = Cf_funcs.selected_dims2(index_x)
            dim_sizes = [nx, ny, nz, nt]

            for i in np.arange(4):
                if any(dim == dims[i].lower() for dim in plotvars.contour_type):
                    if dim_sizes[i] < 2:

                        errstr = '\nVector error - not enough data to make requested '
                        errstr += plotvars.contour_type + ' vector plot\n'
                        errstr += 'Need a minimum of two values per vector plot dimension\n'
                        errstr += 'Field dimensions are\n'
                        errstr += 'nx = ' + str(nx) + '\n'
                        errstr += 'ny = ' + str(ny) + '\n'
                        errstr += 'nz = ' + str(nz) + '\n'
                        errstr += 'nt = ' + str(nt) + '\n'
                        print(errstr)
                        return


            # Then the y component
            nx, ny, nz, nt = Cf_funcs.selected_dims2(index_y)
            dim_sizes = [nx, ny, nz, nt]

            for i in np.arange(4):
                if any(dim == dims[i].lower() for dim in plotvars.contour_type):
                    if dim_sizes[i] < 2:

                        errstr = '\nVector error - not enough data to make requested '
                        errstr += plotvars.contour_type + ' vector plot\n'
                        errstr += 'Need a minimum of two values per vector plot dimension\n'
                        errstr += 'Field dimensions are\n'
                        errstr += 'nx = ' + str(nx) + '\n'
                        errstr += 'ny = ' + str(ny) + '\n'
                        errstr += 'nz = ' + str(nz) + '\n'
                        errstr += 'nt = ' + str(nt) + '\n'
                        print(errstr)
                        return




            # Form the subspace dictionaries
            u_subspace_args = Cf_funcs.subspace_args2(index_x)
            v_subspace_args = Cf_funcs.subspace_args2(index_y)

            print('u_subspace_args', u_subspace_args)

            print('v_subspace_args', v_subspace_args)


            # Set the map
            if plotvars.contour_type == 'x-y':
                cfp.mapset(proj=plotvars.proj)


            u = deepcopy(plotvars.fields[index_x])
            if len(u_subspace_args) > 0:
                u = u.subspace(**u_subspace_args)

            v = deepcopy(plotvars.fields[index_y])
            if len(v_subspace_args) > 0:
                v = v.subspace(**v_subspace_args)

            print('u is ', u)

            print('v is ', v)



            cfp.vect(u=u, v=v, key_length=10, scale=100, stride=5)






            # Get the subspace and collapse commands
            ucom_subspace, ucom_collapse = Cf_funcs.com_subspace_collapse(u_subspace_args)

            print('ucom_subspace, ucom_collapse are', ucom_subspace, ucom_collapse)


            vcom_subspace, vcom_collapse = Cf_funcs.com_subspace_collapse(v_subspace_args)

            print('vcom_subspace, vcom_collapse are', vcom_subspace, vcom_collapse)



            # generate the code to read the data and apply subspace and collapse args
            variable_names = ['f', 'g', 'h']
            com_u, i = Cf_funcs.generate_code(ucom_subspace, ucom_collapse)
            print('com_u is ', com_u)

            com_v, i = Cf_funcs.generate_code(vcom_subspace, vcom_collapse)
            print('com_v is ', com_v)


            print('i is ', i)












    def fieldnumber(self):
        
        # Find out which fields are selected.
        # If multiple fields then select the first.
        selected = self.fieldlist.selectedItems()
        if len(selected) == 0:
            return

        s = int(selected[0].text().split(' ')[0])

        plotvars.index_number = s
        f = plotvars.fields[s]

        # Lock changes to stored variables while the new lists are made
        plotvars.stored_lock = True


        # Clear the dimension and collapse lists
        lists_dim = [self.xlist, self.ylist, self.zlist, self.tlist]
        lists_collapse = [self.xlist_collapse, self.ylist_collapse,\
                          self.zlist_collapse, self.tlist_collapse]
        for i in np.arange(4):
            lists_dim[i].clear()
            lists_collapse[i].clear()


        # Set the lists based on the field dimensions
        nx, ny, nz, nt, x, y, z, t = Cf_funcs.field_dims(field=f)
        dims_field = [nx, ny, nz, nt, x, y, z, t]
        dims = ['X', 'Y', 'Z', 'T']
        dims_small = ['x', 'y', 'z', 't']
        for i in np.arange(4):
            vals = dims_field[i + 4]
            if len(vals) > 0:
                for val in vals:
                    QListWidgetItem(str(val), lists_dim[i]) 



        # Set selected dimensions based on stored values
        for i in np.arange(4):
            if plotvars.stored_dimensions['f' + str(s)][dims_small[i]] == -1:
                lists_dim[i].selectAll()
            else:
                vals = plotvars.stored_dimensions['f' + str(s)][dims_small[i]]

                for j in np.arange(len(vals)):
                    lists_dim[i].item(vals[j]).setSelected(True)



        # Set collapse methods from stored_collapses
        collapses = [plotvars.collapse_x, plotvars.collapse_y,\
                    plotvars.collapse_z, plotvars.collapse_t]
        collapse_combos = [self.collapse_xComboBox, self.collapse_yComboBox,\
                           self.collapse_zComboBox, self.collapse_tComboBox]
        collapse_types = plotvars.collapse_types

        for i in np.arange(4):
            val = plotvars.stored_collapses['f' + str(s)][dims_small[i]]
            index = collapse_types.index(val)
            collapse_combos[i].setCurrentIndex(index)
            collapses[i] = val

            lists_collapse[i].clear()
            val = plotvars.stored_collapse_values['f' + str(s)][dims_small[i]]
            if val:
                QListWidgetItem(str(val), lists_collapse[i]) 
                lists_collapse[i].selectAll()


        # Restore access to changing stored variables
        plotvars.stored_lock = False


        # Reset the field titles
        self.reset_field_title()


    def dim_reset(self, option):

        # Clear the dimension lists and reset the collapse combos to be 'Off'
        f = deepcopy(plotvars.fields[plotvars.index_number])
        lists_dim = [self.xlist, self.ylist, self.zlist, self.tlist]
        lists_collapse = [self.xlist_collapse, self.ylist_collapse,\
                          self.zlist_collapse, self.tlist_collapse]
        collapse_combos = [self.collapse_xComboBox, self.collapse_yComboBox,\
                  self.collapse_zComboBox, self.collapse_tComboBox]
        dims = ['X', 'Y', 'Z', 'T']
        dims_small = ['x', 'y', 'z', 't']

        for i in np.arange(4):
            lists_dim[i].clear()
            collapse_combos[i].setCurrentIndex(0)
            field_var = 'f' + str(plotvars.index_number)
            plotvars.stored_collapses[field_var][dims_small[i]] = 'Off'
            plotvars.stored_collapse_values[field_var][dims_small[i]] = False

        self.collapse_areaComboBox.setCurrentIndex(0)

        self.collapse_xComboBox.setEnabled(True)
        self.collapse_yComboBox.setEnabled(True)
        color = plotvars.text_colour
        pal = QPalette(self.collapse_xLabel.palette())
        pal.setColor(QPalette.WindowText, QColor(color))
        self.collapse_xLabel.setPalette(pal)
        self.collapse_yLabel.setPalette(pal)

        # Repopulate the dimension lists
        for i in np.arange(4):
            if f.has_construct(dims[i]):
                if i <3:
                    vals = f.coord(dims[i]).array
                else:
                    vals = f.coord(dims[i]).dtarray
                for val in vals:
                    QListWidgetItem(str(val), lists_dim[i]) 
        self.xlist.selectAll()
        self.ylist.selectAll()
        self.zlist.selectAll()
        self.tlist.selectAll()


        # reset the plotvars collapse settings
        plotvars.collapse_x = 'Off'
        plotvars.collapse_y = 'Off'
        plotvars.collapse_z = 'Off'
        plotvars.collapse_t = 'Off'

        # Reset the widget visibility and dimension check boxes
        self.xlist.setVisible(True)
        self.ylist.setVisible(False)
        self.zlist.setVisible(False)
        self.tlist.setVisible(False)
        self.xlist_collapse.setVisible(False)
        self.ylist_collapse.setVisible(False)
        self.zlist_collapse.setVisible(False)
        self.tlist_collapse.setVisible(False)

        self.xRadioButton.setChecked(True)
        self.yRadioButton.setChecked(False)
        self.zRadioButton.setChecked(False)
        self.tRadioButton.setChecked(False)

        # Reset the field title
        self.reset_field_title()

    def contour_type(self, text):
        # Set the contour plot type 
        plotvars.contour_type = text


    def plot_type(self, text):
        # Set the contour plot type
        plotvars.plot_type = text

        objs = [self.contour_indexLabel, self.contour_indexComboBox,
        self.vector_x_indexLabel, self.vector_x_indexComboBox,
        self.vector_y_indexLabel, self.vector_y_indexComboBox]

        # Clear vector comboboxes and repopulate
        self.vector_x_indexComboBox.clear()
        self.vector_y_indexComboBox.clear()
        self.vector_y_indexComboBox.clear()

        for i in np.arange(len(plotvars.fields)):
            self.contour_indexComboBox.addItem(str(i))
            self.vector_x_indexComboBox.addItem(str(i))
            self.vector_y_indexComboBox.addItem(str(i))

        if text == 'Contour':
            self.contour_type_ComboBox.setVisible(True)
            self.line_type_ComboBox.setVisible(False)
            for obj in objs:
                obj.setVisible(False)

        if text == 'Vector':
            print('in plot_type vector code')
            self.contour_type_ComboBox.setVisible(True)
            self.line_type_ComboBox.setVisible(False)

            # Set vector indexes to be visible
            for obj in objs:
                obj.setVisible(True)
            objs[0].setVisible(False)
            objs[1].setVisible(False)




        if text == 'Contour and vector':
            print('Contours and vectors not implemented yet')
            self.contour_type_ComboBox.setVisible(True)
            self.line_type_ComboBox.setVisible(False)
            for obj in objs:
                obj.setVisible(True)

        if text == 'Line':
            self.contour_type_ComboBox.setVisible(False)
            self.line_type_ComboBox.setVisible(True)
            for obj in objs:
                obj.setVisible(False)


    def collapse_type(self, dim):

        # Set the collapse widget states in plotvars
        plotvars.collapse_x = self.collapse_xComboBox.currentText()
        plotvars.collapse_y = self.collapse_yComboBox.currentText()
        plotvars.collapse_z = self.collapse_zComboBox.currentText()
        plotvars.collapse_t = self.collapse_tComboBox.currentText()


        # Change the dimension lists
        f = plotvars.fields[plotvars.index_number]
        
        dims = ['x', 'y', 'z', 't']
        dims_upper = ['X', 'Y', 'Z', 'T']
        lists_dim = [self.xlist, self.ylist, self.zlist, self.tlist]
        lists_collapse = [self.xlist_collapse, self.ylist_collapse,\
                          self.zlist_collapse, self.tlist_collapse]
        combos = [self.collapse_xComboBox, self.collapse_yComboBox,\
                  self.collapse_zComboBox, self.collapse_tComboBox]
        collapses = [plotvars.collapse_x, plotvars.collapse_y,\
                    plotvars.collapse_z, plotvars.collapse_t]


        idim = dims.index(dim)
        coord = f.construct(dims_upper[idim])
        collapse = collapses[idim]
        field_key = 'f' + str(plotvars.index_number)

        #  Extract the selected list
        selected = lists_dim[idim].selectedItems()
        mylist = []
        for j in np.arange(len(selected)):
            mylist.append(str(selected[j].text()))


        # Reject collapse if the dimension has just one selected item
        if len(mylist) == 1:
            print('\nWarning: Cannot collapse a dimension with just one selected item\n')
            combos[idim].setCurrentIndex(0)
            return

        indicies = [i.row() for i in lists_dim[idim].selectedIndexes()]
        mymin = min(indicies)
        mymax = max(indicies)

        # Code for bounds calculation
        if coord.has_bounds() is False:
            bounds = coord.create_bounds()
            coord.set_bounds(bounds)

        if idim <= 2:
            # Code for data value calculation
            #val_min = np.min(np.array(mylist).astype(np.float))
            #val_max = np.max(np.array(mylist).astype(np.float))
            #vals = [(val_max - val_min) / 2.0 + val_min]

            # Code for bounds calculation
            mybounds = coord.bounds.array[mymin:mymax+1, :]
            vals = [(np.max(mybounds) - np.min(mybounds))/2.0 + np.min(mybounds)]
        else:
            ref_time = coord.units
            ref_calendar = coord.calendar
            time_units = cf.Units(ref_time, ref_calendar)

            # Code for data value calculation
            #times = [min(mylist), max(mylist)]
            #tmin = cf.Data(times[0], units=time_units)
            #tmax = cf.Data(times[1], units=time_units)
            #midpt = (float(tmax.array) - float(tmin.array)) / 2.0 + float(tmin.array)
            #vals = [str(cf.cftime.num2date(midpt, ref_time, ref_calendar))]

            # Code for bounds calculation
            mybounds = coord.bounds.array[mymin:mymax+1, :]
            midpt = (np.max(mybounds) - np.min(mybounds)) / 2.0 + np.min(mybounds)
            vals = [str(cf.cftime.num2date(midpt, ref_time, ref_calendar))]


        # Set collapse in the stored_collapses
        ## print('collapse_type idim and collapse are ', dims[idim], collapse)
        plotvars.stored_collapses[field_key][dims[idim]] = collapse

        ## print('idim is ', idim)

        lists_collapse[idim].clear()
        for val in vals:
            ## print('adding val to idim list', val, idim)
            QListWidgetItem(str(val), lists_collapse[idim]) 
            lists_collapse[idim].selectAll()

        plotvars.stored_collapse_values[field_key][dims[idim]] = vals[0]


        lists_dim[idim].setVisible(False)
        lists_collapse[idim].setVisible(True)

        # Set the viewable dimension and collapse data
        list_vis = [False, False, False, False]
        list_collapse_vis = [False, False, False, False]
        list_objs = [self.xlist, self.ylist, self.zlist, self.tlist]
        list_collapse_objs = [self.xlist_collapse, self.ylist_collapse, self.zlist_collapse, self.tlist_collapse]

        if self.xRadioButton.isChecked():
            if plotvars.collapse_x == 'Off':
                list_vis[0] = True
            else:
                list_collapse_vis[0] = True

        if self.yRadioButton.isChecked():
            if plotvars.collapse_y == 'Off':
                list_vis[1] = True
            else:
                list_collapse_vis[1] = True

        if self.zRadioButton.isChecked():
            if plotvars.collapse_z == 'Off':
                list_vis[2] = True
            else:
                list_collapse_vis[2] = True

        if self.tRadioButton.isChecked():
            if plotvars.collapse_t == 'Off':
                list_vis[3] = True
            else:
                list_collapse_vis[3] = True

        for i in np.arange(4):
            list_objs[i].setVisible(list_vis[i])
            list_collapse_objs[i].setVisible(list_collapse_vis[i])



        # Reset the field title
        self.reset_field_title()


    def collapse_area(self, text):

        nx = len(self.xlist.selectedItems())
        ny = len(self.ylist.selectedItems())

        enabled = True
        index = 0

        if nx < 2 or ny < 2:
            print('Error - cannot collapse to an area')
            print('Need more than 1 item for x and y')
            print('nx = ' + str(nx))
            print('ny = ' + str(ny))
        else:
            if text != 'Off':
                enabled = False
                index = plotvars.collapse_types.index(text)

        self.collapse_xComboBox.setCurrentIndex(index)
        self.collapse_yComboBox.setCurrentIndex(index)

        self.collapse_xComboBox.setEnabled(enabled)
        self.collapse_yComboBox.setEnabled(enabled)

        color = plotvars.text_colour_insensitive
        if enabled:
            color = plotvars.text_colour
        pal = QPalette(self.collapse_xLabel.palette())
        pal.setColor(QPalette.WindowText, QColor(color))
        self.collapse_xLabel.setPalette(pal)
        self.collapse_yLabel.setPalette(pal)

        # Reset the collapses
        self.collapse_type('x')
        self.collapse_type('y')


    def dim_view(self, dim):
        # Set the visible state of the dimension lists and lists_collapse 

        dims = ['x', 'y', 'z', 't']
        state = [False, False, False, False]
        loc = dims.index(dim)
        state[loc] = True
        lists = [self.xlist, self.ylist, self.zlist, self.tlist]
        lists_collapse = [self.xlist_collapse, self.ylist_collapse,\
                          self.zlist_collapse, self.tlist_collapse]
        collapses = [plotvars.collapse_x, plotvars.collapse_y,\
                    plotvars.collapse_z, plotvars.collapse_t]


        self.xRadioButton.setChecked(state[0])
        self.yRadioButton.setChecked(state[1])
        self.zRadioButton.setChecked(state[2])
        self.tRadioButton.setChecked(state[3])

        for i in np.arange(4):
            if state[i]:
                if collapses[i] == 'Off':
                    lists[i].setVisible(True)
                    lists_collapse[i].setVisible(False)
                else:
                    lists[i].setVisible(False)
                    lists_collapse[i].setVisible(True)
            else:
                    lists[i].setVisible(False)
                    lists_collapse[i].setVisible(False)



    def field_widget_listing(self, listing):

        plotvars.field_widget_listing = listing

        listings = ['index', 'field']
        ticked_state = [False, False]
        loc = listings.index(listing)
        ticked_state[loc] = True

        self.indexCheckBox.setChecked(ticked_state[0])
        self.fieldCheckBox.setChecked(ticked_state[1])
        self.fieldlist.clear()

        field_widget_names, field_widget_title = Cf_funcs.fields_list(order=plotvars.field_widget_listing,
                                                order_changed=True)

        for i in np.arange(len(field_widget_names)):
            QListWidgetItem(field_widget_names[i], self.fieldlist) 
        self.fieldlist.setCurrentRow(0)
        self.field_titles.setText(field_widget_title)


    def search_fields(self, text):
        field_widget_names, field_widget_title = Cf_funcs.fields_list(order=plotvars.field_widget_listing,
                                                 order_changed=True, search=text)

        self.fieldlist.clear()
        for i in np.arange(len(field_widget_names)):
            QListWidgetItem(field_widget_names[i], self.fieldlist) 
        self.fieldlist.setCurrentRow(0)
        self.field_titles.setText(field_widget_title)



    def output_terminal_written(self, text):
        self.output_terminal_textEdit.append(text)
        #print('text is ', text)


    def reset_field_title(self):


        # Reset the dimension sizes in the field string 
        selected = self.fieldlist.selectedItems()

        if len(selected) == 1:
            index_length = plotvars.index_length
            nx_length = plotvars.nx_length
            ny_length = plotvars.ny_length
            nz_length = plotvars.nz_length
            nt_length = plotvars.nt_length

            mylen = 6 + nx_length + 1 + ny_length + 1 + nz_length + 1 + nt_length + 1
            field_title = selected[0].text()[mylen:]
            index = selected[0].text()[0:6]

            lists = [self.xlist, self.ylist, self.zlist, self.tlist] 
            dims = [0, 0, 0, 0]
            keys = ['x', 'y', 'z', 't']
            for i in np.arange(4):
                vals = [v.row() for v in lists[i].selectedIndexes()]
                dims[i] = len(vals)


                if plotvars.stored_lock is False:
                    # Reset plotvars.stored_dimensions dictionary
                    field_key = 'f' + str(plotvars.index_number)

                    if len(lists[i]) == len(vals) or len(vals) == 0:
                        plotvars.stored_dimensions[field_key][keys[i]] = -1
                    else:
                        plotvars.stored_dimensions[field_key][keys[i]] = vals

    
            collapses = [plotvars.collapse_x, plotvars.collapse_y, plotvars.collapse_z, plotvars.collapse_t]
            field_key = 'f' + str(plotvars.index_number)
 
            for i in np.arange(4):
                collapses[i] = plotvars.stored_collapses[field_key][keys[i]]

                if collapses[i] != 'Off':
                    dims[i] = 1

    
            new_title = index 
            new_title += str(dims[0]) +  (nx_length + 1 - len(str(dims[0]))) * ' '
            new_title += str(dims[1]) +  (ny_length + 1 - len(str(dims[1]))) * ' '
            new_title += str(dims[2]) +  (nz_length + 1 - len(str(dims[2]))) * ' '
            new_title += str(dims[3]) +  (nt_length + 1 - len(str(dims[3]))) * ' '
            new_title += field_title

            selected[0].setText(new_title)



    def menu(self, value):
        '''Pop up a window based on which defaults are required'''

        if value.text() == 'cfview defaults':
            if self.cfview_defaults is None:
                self.cfview_defaults = Cfview_defaults_window(self.parent)
            self.cfview_defaults.show()


        if value.text() == 'Copy field':

            selected = self.fieldlist.selectedItems()

            if len(selected) == 0:
                return

            # Only copy the first selected field
            selected = selected[0]
            index = plotvars.index_number
            next = len(plotvars.fields)
            new_name = selected.text()
            QListWidgetItem(deepcopy(new_name), self.fieldlist)
            plotvars.stored_dimensions['f' + str(next)] = deepcopy(plotvars.stored_dimensions['f' + str(index)])
            plotvars.stored_collapses['f' + str(next)] = deepcopy(plotvars.stored_collapses['f' + str(index)])
            plotvars.stored_collapse_values['f' + str(next)] = deepcopy(plotvars.stored_collapse_values['f' + str(index)])
            plotvars.fields.append(deepcopy(plotvars.fields[index]))

            # Set the new index number
            index_length = plotvars.index_length
            new_title = str(next) + (6 - len(str(next))) * ' ' + selected.text()[6:]

            self.fieldlist.item(next).setText(new_title)




        if value.text() == 'Delete selected fields':
            while len(self.fieldlist.selectedIndexes()) > 0:
                index = int(self.fieldlist.currentItem().text().split(' ')[0])
                print('index is ', index)
                plotvars.fields[index].standard_name = 'deleted'
                print('selected index test was ', self.fieldlist.currentItem().text())
                self.fieldlist.currentItem().setText('deleted')
                print('selected index test is now ', self.fieldlist.currentItem().text())
                self.fieldlist.takeItem(self.fieldlist.selectedIndexes()[0].row())

            


        if value.text() == 'Delete all fields':
            self.fieldlist.clear()
            plotvars.file_selected = None
            plotvars.index_number = -1

            self.search_fieldsTextbox.clear()
            plotvars.fields = None
            plotvars.field_widget_indicies = None

            plotvars.stored_dimensions = {}
            plotvars.stored_collapses = {}
            plotvars.stored_collapse_values = {}
            self.xlist.clear()
            self.ylist.clear()
            self.zlist.clear()
            self.tlist.clear()



        if value.text() == 'contour levels':
            if self.contour_levels is None:
                self.contour_levels = Contour_levels_window()
            self.contour_levels.show()

        if value.text() == 'colour scale':
            if self.colour_scale is None:
                self.colour_scale = Colour_scale_window()
            self.colour_scale.show()


        if value.text() == 'map':
            if self.map_window is None:
                self.map_window = Map_window()
            self.map_window.show()

        if value.text() == 'contours':
            if self.contour_window is None:
                self.contour_window = Contour_window()
            self.contour_window.show()

        if value.text() == 'lines':
            if self.line_window is None:
                self.line_window = Line_window()
            self.line_window.show()




        if value.text() == 'data':
            if self.data_window is None:
                self.data_window = Data_window(self.parent)
            self.data_window.show()

        if value.text() == 'names':
            if self.names_window is None:
                self.names_window = Names_window(self.parent)
            self.names_window.show()

        if value.text() == 'transform':
            if self.transform_window is None:
                self.transform_window = Transform_window(self.parent)
            self.transform_window.window.show()

        if value.text() == 'about':
            html = '<body><h2>About cfview</h2>'
            html += '<b>This is version 2.0.0</b><p>'
            html += 'cfview is a netCDF and Met Ofice file format data analysis and viewer for the atmospheric sciences '
            html += 'and is intended to be an xconv+ replacement.<p>'
            html += 'cfview uses:<br>'
            html += '<b>cf-python</b> - data I/O and manipulation<br>'
            html += 'https://ncas-cms.github.io/cf-python<p>'
            html += '<b>cf-plot</b> - plotting<br>'
            html += 'http://ajheaps.github.io/cf-plot<P>'
            html += '<b>PyQt5</b> - GUI toolkit<p>'
            html += 'Author: Andy Heaps andy.heaps@ncas.ac.uk<br>'
            html += '&#169; NCAS CMS 2021'
            self.about_help = Help(html)
            self.about_help.show()

        if value.text() == 'cfview':
            html = '<body><h2>Using cfview</h2>'
            html += 'cfview is available for the Unix and Mac platforms<p>'
            html += '<h4>Starting cfview</h4>'
            html += 'On the command line type<br><b>cfview</b><br>or<br><b>cfview datafile</b><p> At the moment cfview '
            html += 'accepts just one data file for input at a time - this will change in a future version. '
            html += 'Valid input formats match those of cf-python - netCDF, Met Office PP and fields files.<p>'
            html += '<h4>The main interface</h4>'
            html += 'The main interface has a list of fields on the top left with and an index number and the '
            html += 'number of x, y, z and t values for a field.  The fields can be ordered by index or field name '
            html += 'and a search function for when there are many fields in the dataset<p>'
            html += 'An output messages panel lies underneath the fields listing. '
            html += 'On the right hand side a dimension view panel has x, y, z and t radio buttons to allow showing of '
            html += 'the four dimension values'
            html += '<h4>Selecting dimension values</h4>'
            html += 'Use the left mouse to highlight a particular value or shift and left mouse to select a range. '
            html += 'On Linux control and left click will select multiple values and on a Mac this is Command and '
            html += 'left click.'
            html += '<h4>Contour plots</h4>'
            html += 'The initial setting is for cfview to make a x-y contour plot.  The axes used for the contour '
            html += 'plot can be changed using the dropdown menu above the dimension viewing panel. Contour, '
            html += 'contour level, maps and colour scales can be changed using the Setup menu item.  Once changed the '
            html += 'new settings are persistent until reset or changed again.<p>'  
            html += '<h4>Default settings</h4>'
            html += 'Default settings for fonts, font size and interface colour theme are changed in the Setup '
            html += '-> cfview defaults menu item. Contour settings are also save to the cfview defaults file with is '
            html += 'generally ~/.cfview_defaults.  To load in the new defaults start cfview again.  If the defaults file '
            html += 'is ~.cfview_defaults then no additional command line arguments are required.  For a different defaults '
            html += 'file use<br><b>cfview -d mydefaults.file datafile</b><p>'



            self.cfview_help = Help(html)
            self.cfview_help.show()

    def file_menu(self, value):

        if value.text() == 'Open':
            self.open_file(self)

        if value.text() == 'Save':
            self.save_file(self)

        if value.text() == 'Exit':
            sys.exit(0)




class Cfview_defaults_window(QWidget):
    '''popup window for editing cfview defaults'''

    def __init__(self, cfview_parent):
        super(Cfview_defaults_window, self).__init__()

        # Set the parent of cfview to this Window
        #self.cfview = cfview(filename='ggap2.nc', parent=self)

        self.cfview_parent = cfview_parent

        self.initUI()


    def initUI(self):

        # Set up some buttons
        resetButton = QPushButton("Reset")
        resetButton.clicked.connect(self.reset)
        helpButton = QPushButton("Help")
        helpButton.clicked.connect(self.help)
        saveButton = QPushButton("Save defaults to file:")
        saveButton.clicked.connect(self.save)
        quitButton = QPushButton("Quit")
        quitButton.clicked.connect(self.close)

        # Interface colour themes
        themeComboBox = QComboBox()
        themes = ['BlueMono', 'BluePurple', 'DarkBlue12', 'DarkGrey7',\
                  'DarkTeal11', 'GreenMono', 'LightBrown2', 'NeutralBlue',\
                  'SandyBeach', 'TealMono', 'SystemDefault', 'SystemDefault1', 'xconv']
    
        for theme in themes:
            themeComboBox.addItem(theme)
        themeComboBox.highlighted[str].connect(self.theme)

        # Font size slider
        font_Slider = QSlider(Qt.Horizontal)
        font_Slider.sliderMoved.connect(self.fontsize)
        font_Slider.setRange(2, 25)
        font_Slider.setValue(15)

        # Find available fonts
        db = QFontDatabase()
        fonts = QFontDatabase().families()

        # Main font
        fontComboBox = QComboBox()
        for font in fonts:
            fontComboBox.addItem(font)
        

        test_fonts = ['Times', 'Helvetica', 'Arial', 'DejaVu Sans', deepcopy(plotvars.font)]
        index = 0
        for font in test_fonts:
            if font in fonts:
                index = fonts.index(font)
            else:
                plotvars.font = font


        fontComboBox.setCurrentIndex(index)
        fontComboBox.highlighted[str].connect(self.font_main)


        # Mono font
        font_monoComboBox = QComboBox()
        for font in fonts:
            font_monoComboBox.addItem(font)

        test_fonts = ['Times', 'Helvetica', 'Courier', 'Menlo', 'Monaco', deepcopy(plotvars.font_mono)]
        index = 0
        for font in test_fonts:
            if font in fonts:
                index = fonts.index(font)
            else:
                plotvars.font = font

        font_monoComboBox.setCurrentIndex(index)
        font_monoComboBox.highlighted[str].connect(self.font_mono)


        # Create layout
        vbox = QVBoxLayout()

        hbox_font = QHBoxLayout()
        font_Label = QLabel('Main font:')
        hbox_font.addWidget(font_Label)
        hbox_font.addWidget(fontComboBox)
        vbox.addLayout(hbox_font)

        hbox_font_mono = QHBoxLayout()
        font_mono_Label = QLabel('Monospace font:')
        hbox_font_mono.addWidget(font_mono_Label)
        hbox_font_mono.addWidget(font_monoComboBox)
        vbox.addLayout(hbox_font_mono)

        hbox_font_size = QHBoxLayout()
        font_size_Label = QLabel('Font size: 15')
        hbox_font_size.addWidget(font_size_Label)
        hbox_font_size.addWidget(font_Slider)
        vbox.addLayout(hbox_font_size)

        hbox_theme = QHBoxLayout()
        themeLabel = QLabel('Interface colour theme:')
        hbox_theme.addWidget(themeLabel)
        hbox_theme.addWidget(themeComboBox)
        vbox.addLayout(hbox_theme)

        # Save text boxes
        saveTextBox = QLineEdit()
        saveTextBox.setText('~/.cfview_defaults')

        save_hbox = QHBoxLayout()
        vbox.addLayout(save_hbox)
        save_hbox.addWidget(saveButton)
        save_hbox.addWidget(saveTextBox)

        hbox_buttons = QHBoxLayout()
        vbox.addLayout(hbox_buttons)
        hbox_buttons.addWidget(resetButton)
        hbox_buttons.addWidget(helpButton)
        hbox_buttons.addWidget(quitButton)

        self.themeComboBox = themeComboBox
        self.font_size_Label = font_size_Label
        self.saveTextBox = saveTextBox
        self.font_Slider = font_Slider
        self.font_monoComboBox = font_monoComboBox
        self.fontComboBox = fontComboBox
        self.setWindowTitle('cfview defaults')

        self.setLayout(vbox)

        # Set the window theme
        palette = QPalette()    
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))    
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))    
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        self.setPalette(palette)

        # Set font 
        custom_font = QFont(plotvars.font, plotvars.fontsize)
        self.window().setFont(custom_font)

        self.defaults_help = None  # No external window yet.

        self.show()

    def theme(self, name):

        cols = ['#f5deb3', '#f5deb3', '#000000', '#bfdfff', '#000000', '#000000']

        if name == 'BlueMono':
            cols = ['#abb6d4', '#7085c4', '#ffffff', '#f1f4fd', '#000000', '#000000']

        if name == 'BluePurple':
            cols = ['#a5cadd', '#313852', '#ffffff', '#dff5ff', '#000000', '#7a2894']

        if name == 'DarkBlue12':
            cols = ['#324f7b', '#5067aa', '#ffffff', '#87a6df', '#dcf8cf', '#000000']

        if name == 'DarkGrey7':
            cols = ['#4c586e', '#434261', '#c7dfbd', '#574e6d', '#c7dfbd', '#c7dfbd']

        if name == 'DarkTeal11':
            cols = ['#40555a', '#69868c', '#ffffff', '#69868c', '#ffffff', '#ffffff']

        if name == 'GreenMono':
            cols = ['#a8c3b4', '#6e9e86', '#ffffff', '#e3e3e3', '#000000', '#000000']

        if name == 'LightBrown2':
            cols = ['#a7ad7f', '#5b8e7d', '#ffffff', '#e6d3a8', '#000000', '#000000']

        if name == 'NeutralBlue':
            cols = ['#92aa9d', '#d0dbbd', '#000000', '#fcfff6', '#000000', '#000000']

        if name == 'SandyBeach':
            cols = ['#efeccb', '#056484', '#ffffff', '#e6d3a8', '#002e30', '#00302b']

        if name == 'SystemDefault':
            cols = ['#f0f0f0', '#082567', '#ffffff', '#c8c8c8', '#000000', '#000000']

        if name == 'SystemDefault1':
            cols = ['#f0f0f0', '#f0efed', '#000000', '#c8c8c8', '#000000', '#000000']
    
        if name == 'TealMono':
            cols = ['#a9cede', '#18243f', '#ffffff', '#dfecf2', '#000000', '#000000']

        if name == 'xconv':
            cols = ['#f5deb3', '#f5deb3', '#000000', '#bfdfff', '#000000', '#000000']


        # assign colours and set them in plotvars
        background = cols[0]
        button = cols[1]
        buttontext = cols[2]
        highlight = cols[3]
        text = cols[4]
        windowtext=cols[5]

        plotvars.background_colour = background
        plotvars.button_colour = button
        plotvars.buttontext_colour = buttontext
        plotvars.highlight_colour = highlight
        plotvars.text_colour = text
        plotvars.windowtext_colour = windowtext



        palette = QPalette()    
        palette.setColor(QPalette.Window, QColor(background))
        palette.setColor(QPalette.Base, QColor(background))    
        palette.setColor(QPalette.Button, QColor(button))
        palette.setColor(QPalette.ButtonText, QColor(buttontext))
        palette.setColor(QPalette.Highlight, QColor(highlight))
        palette.setColor(QPalette.HighlightedText, QColor(text))
        palette.setColor(QPalette.Text,  QColor(text))    
        palette.setColor(QPalette.WindowText, QColor(windowtext))
        self.setPalette(palette)
        self.cfview_parent.window().setPalette(palette)


    def fontsize(self):

        value = self.font_Slider.value()
        font = QFont(plotvars.font, value)

        self.cfview_parent.window().setFont(font)
        plotvars.fontsize = value
        self.font_size_Label.setText('Font size: ' + str(value))

        font = QFont(plotvars.font_mono, plotvars.fontsize)
        self.cfview_parent.window().field_titles.setFont(font)
        self.cfview_parent.window().fieldlist.setFont(font)


    def font_main(self, value):

        plotvars.font = value
        font = QFont(plotvars.font, plotvars.fontsize)
        self.cfview_parent.window().setFont(font)


    def font_mono(self, value):

        plotvars.font_mono = value
        font = QFont(plotvars.font_mono, plotvars.fontsize)

        # Set mono font for field titles and field list
        self.cfview_parent.window().field_titles.setFont(font)
        self.cfview_parent.window().fieldlist.setFont(font)


    def reset(self):
        # Reset to defaults
        self.saveTextBox.setText('~/.cfview_defaults')
        plotvars.fontsize = 15
        self.font_Slider.setValue(15)
        self.font_size_Label.setText('Font size: 15')

        # Find available fonts
        db = QFontDatabase()
        fonts = QFontDatabase().families()

        # Main font
        test_fonts = ['Times', 'Helvetica', 'Arial', 'DejaVu Sans']
        for font in test_fonts:
            if font in fonts:
                index = fonts.index(font)
                self.fontComboBox.setCurrentIndex(index)
                plotvars.font = font
        #self.font_main(plotvars.font)
        font = QFont(plotvars.font, plotvars.fontsize)
        self.cfview_parent.window().setFont(font)


        # Mono font
        test_fonts = ['Times', 'Helvetica', 'Courier', 'Menlo', 'Monaco', 'DejaVu Sans Mono']
        for font in test_fonts:
            if font in fonts:
                index = fonts.index(font)
                plotvars.font_mono = font
                self.font_monoComboBox.setCurrentIndex(index)
        #self.font_mono(plotvars.font_mono)
        font = QFont(plotvars.font_mono, plotvars.fontsize)
        self.cfview_parent.window().field_titles.setFont(font)
        self.cfview_parent.window().fieldlist.setFont(font)

        # Reset the theme
        self.theme('BlueMono')
        self.themeComboBox.setCurrentIndex(0)


    def save(self):
        print('In save -  file is ', self.saveTextBox.text())


        # Ask to clobber existing file
        full_path = os.path.expanduser(self.saveTextBox.text())
        self.savefile = full_path
        check = os.path.isfile(full_path) 
        print('check is ', check)
        if check:
            html = ''
            html += '<body>The file ' + full_path + ' already exists'
            html += '<p>Okay to overwrite?</body>'


            self.clobber = Clobber_file(html, self.savefile)

            self.clobber.show()

        else:
            plotvars.write_defaults = True
            
        Save_defaults(self.savefile)





    def help(self):

        if self.defaults_help is None:

            html = ''
            html += '<body><h2>cfview default options</h2>'
            html += 'The defaults file for cfview is generally stored in the file ~/.cfview_defaults '
            html += 'which is read in when cfview starts up.  A different defaults file can be specified using '
            html += 'the -d parameter to the cfview command line i.e.<br>'
            html += '<b>cfview -d mydefaults.def file.nc</b><p>'
            html += 'The main font applies to all text in the cfview display apart from the field titles and '
            html += 'names where the monospace font applies.'
            html += 'Interface colour schemes can be altered by manually editing the ~/.cfview_defaults file '
            html += 'and replacing the six main colour definitions.<p>'
            html += 'Contour options for fill, blockfill, lines and line labels that are currently selected '
            html += 'are also saved into the ~/.cfview_defaults file.'

            self.defaults_help = Help(html)

        self.defaults_help.show()


class Clobber_file(QWidget):
    '''Popup window for clobbering a file'''

    def __init__(self, html, savefile):
        super(Clobber_file, self).__init__()
        self.html = html
        self.savefile = savefile
        self.initUI()


    def initUI(self):

        yesButton = QPushButton("Yes")
        yesButton.clicked.connect(self.clobber_yes)

        noButton = QPushButton("No")
        noButton.clicked.connect(self.clobber_no)

        helpTextbox = QTextEdit()
        helpTextbox.setReadOnly(True)


        doc = QTextDocument()

        doc.setHtml(self.html)
        helpTextbox.setDocument(doc)


        vbox = QVBoxLayout()
        vbox.addWidget(helpTextbox)

        hbox = QHBoxLayout()
        hbox.addWidget(yesButton)
        hbox.addWidget(noButton)
        vbox.addLayout(hbox)

        self.setLayout(vbox)
       

        palette = QPalette()    
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))    
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))    
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        self.setPalette(palette)

        # Set font 
        custom_font = QFont(plotvars.font, plotvars.fontsize)
        self.window().setFont(custom_font)

        self.setFixedWidth(600)

        self.show()


    def clobber_yes(self):
        plotvars.write_defaults = True
        #self.savefile()
        Save_defaults(self.savefile)
        self.close()

    def clobber_no(self):
        plotvars.write_defaults = False
        self.close()

     

class Save_defaults():

    def __init__(self, savefile):
        super(Save_defaults, self).__init__()
        self.savefile = savefile
        self.save()

    def save(self):
        if plotvars.write_defaults:
            print('writing file')
            plotvars.write_defaults = False

            datafile = open(self.savefile, 'w')

            datafile.write('### cfview defaults file ###\n\n')
            datafile.write('background_colour ' + plotvars.background_colour + '\n')
            datafile.write('button_colour ' + plotvars.button_colour + '\n')
            datafile.write('buttontext_colour ' + plotvars.buttontext_colour + '\n')
            datafile.write('highlight_colour ' + plotvars.highlight_colour + '\n')
            datafile.write('text_colour ' + plotvars.text_colour + '\n')
            datafile.write('windowtext_colour ' + plotvars.windowtext_colour + '\n')
            datafile.write('font ' + plotvars.font + '\n')
            datafile.write('font_mono ' + plotvars.font_mono + '\n')
            datafile.write('fontsize ' + str(plotvars.fontsize) + '\n')
            datafile.write('fill ' + str(plotvars.fill) + '\n')
            datafile.write('blockfill ' + str(plotvars.blockfill) + '\n')
            datafile.write('lines ' + str(plotvars.lines) + '\n')
            datafile.write('line_labels ' + str(plotvars.line_labels) + '\n')
            datafile.write('titles ' + str(plotvars.titles) + '\n')

            datafile.close()



class Contour_levels_window(QWidget):
    '''popup window for editing contour level defaults'''

    def __init__(self):
        super(Contour_levels_window, self).__init__()
        self.initUI()


    def initUI(self):

        # Set up some buttons
        resetButton = QPushButton("Reset")
        resetButton.clicked.connect(self.reset)

        helpButton = QPushButton("Help")
        helpButton.clicked.connect(self.help)

        quitButton = QPushButton("Quit")
        quitButton.clicked.connect(self.close)

        # Labels
        automatic_Label = QLabel('Automatic levels')

        min_Label = QLabel('Min:')
        min_Label.setEnabled(False)
        max_Label = QLabel('Max:')
        max_Label.setEnabled(False)
        step_Label = QLabel('Step:')
        step_Label.setEnabled(False)

        ascending_Label = QLabel('Ascending values separated by spaces')
        extensions_Label = QLabel('Colourbar extensions - extend contours to cover all the data')
        lower_Label = QLabel('Lower:')
        upper_Label = QLabel('Upper:')


        # Level type selection tick boxes
        automaticCheckBox = QCheckBox("Automatic levels")
        automaticCheckBox.setChecked(True)
        automaticCheckBox.clicked.connect(lambda: self.level_type('automatic'))

        evenCheckBox = QCheckBox("Evenly spaced levels")
        evenCheckBox.setChecked(False)
        evenCheckBox.clicked.connect(lambda: self.level_type('even'))

        manualCheckBox = QCheckBox("User spaced levels")
        manualCheckBox.setChecked(False)
        manualCheckBox.clicked.connect(lambda: self.level_type('manual'))



        # Extension type selection tick boxes
        extension_lowerCheckBox = QCheckBox("Lower")
        extension_lowerCheckBox.setChecked(True)
        extension_lowerCheckBox.clicked.connect(lambda: self.extension_type('lower'))
        extension_upperCheckBox = QCheckBox("Upper")
        extension_upperCheckBox.setChecked(True)
        extension_upperCheckBox.clicked.connect(lambda: self.extension_type('upper'))



        # Levels entry Labels and Boxes
        levs_minTextbox = QLineEdit()
        levs_minTextbox.textChanged.connect(self.levs_even_changed)
        levs_minTextbox.setEnabled(False)
        levs_maxTextbox = QLineEdit()
        levs_maxTextbox.textChanged.connect(self.levs_even_changed)
        levs_maxTextbox.setEnabled(True)
        levs_stepTextbox = QLineEdit()
        levs_stepTextbox.textChanged.connect(self.levs_even_changed)
        levs_stepTextbox.setEnabled(True)

        levs_manualTextbox = QLineEdit()
        levs_manualTextbox.textChanged.connect(self.levs_manual_changed)
        levs_manualTextbox.setEnabled(True)


        vbox = QVBoxLayout()
        hbox_even = QHBoxLayout()
        hbox_manual = QHBoxLayout()
        hbox_extensions = QHBoxLayout()
        hbox_buttons = QHBoxLayout()

        vbox.addWidget(automaticCheckBox)
        vbox.addWidget(HLine())

        vbox.addWidget(evenCheckBox)
        vbox.addLayout(hbox_even)
        hbox_even.addWidget(min_Label)
        hbox_even.addWidget(levs_minTextbox)
        hbox_even.addWidget(max_Label)
        hbox_even.addWidget(levs_maxTextbox)
        hbox_even.addWidget(step_Label)
        hbox_even.addWidget(levs_stepTextbox)

        vbox.addWidget(HLine())
        vbox.addWidget(manualCheckBox)
        vbox.addLayout(hbox_manual)
        hbox_manual.addWidget(ascending_Label)
        hbox_manual.addWidget(levs_manualTextbox)

        vbox.addWidget(HLine())
        vbox.addWidget(extensions_Label)
        vbox.addLayout(hbox_extensions)
        hbox_extensions.addWidget(extension_lowerCheckBox)
        hbox_extensions.addWidget(extension_upperCheckBox)

        vbox.addLayout(hbox_buttons)
        hbox_buttons.addWidget(resetButton)
        hbox_buttons.addWidget(helpButton)
        hbox_buttons.addWidget(quitButton)

   
        self.setWindowTitle('cfview contour levels')

        self.setLayout(vbox)


        self.automaticCheckBox = automaticCheckBox
        self.evenCheckBox = evenCheckBox
        self.levs_minTextbox = levs_minTextbox
        self.levs_maxTextbox = levs_maxTextbox
        self.levs_stepTextbox = levs_stepTextbox
        self.manualCheckBox = manualCheckBox
        self.levs_manualTextbox = levs_manualTextbox
        self.extension_lowerCheck = extension_lowerCheckBox
        self.extension_upperCheck = extension_upperCheckBox

        self.min_Label = min_Label
        self.max_Label = max_Label
        self.step_Label = step_Label
        self.ascending_Label = ascending_Label

        self.contour_levels_help = None  # No external window yet.


        palette = QPalette()    
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))    
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))    
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        self.setPalette(palette)

        # Set font 
        custom_font = QFont(plotvars.font, plotvars.fontsize)
        self.window().setFont(custom_font)



        # Set initial widget states
        self.level_type('automatic')

        self.show()


    def level_type(self, text):
 
        types = ['automatic', 'even', 'manual']
        vars = [plotvars.levs_automatic_set,  plotvars.levs_set, plotvars.levs_manual_set]
        checkboxes = [self.automaticCheckBox, self.evenCheckBox, self.manualCheckBox]
        state = [False, False, False]
        loc = types.index(text)
        state[loc] = True

        plotvars.levs_automatic_set = state[0]
        plotvars.levs_set = state[1]
        plotvars.levs_manual_set = state[2]

        for i in np.arange(3):
            checkboxes[i].setChecked(state[i])


        if plotvars.levs_automatic_set:
            color = plotvars.text_colour_insensitive
        else:
            color = plotvars.text_colour


        objs = [self.levs_minTextbox, self.levs_maxTextbox, self.levs_stepTextbox,\
                self.levs_manualTextbox, self.min_Label , self.max_Label,\
                self.step_Label, self.ascending_Label]

        if text == 'automatic':
            flags = [False, False, False, False, False, False, False, False]

        if text == 'even':
            flags = [True, True, True, False, True, True, True, False]

        if text == 'manual':
            flags = [False, False, False, True, False, False, False, True]

        for i in np.arange(len(objs)):
            obj = objs[i]
            color = plotvars.text_colour_insensitive
            if flags[i]:
                color = plotvars.text_colour
            obj.setEnabled(flags[i])
            pal = QPalette(obj.palette())
            pal.setColor(QPalette.WindowText, QColor(color))
            obj.setPalette(pal)


    def levs_even_changed(self):
        plotvars.levs_min = self.levs_minTextbox.text()
        plotvars.levs_max = self.levs_maxTextbox.text()
        plotvars.levs_step = self.levs_stepTextbox.text()


    def levs_manual_changed(self):
        plotvars.levs_manual = self.levs_manualTextbox.text()
        

    def reset(self):
        self.level_type('automatic')
        self.levs_minTextbox.setText('')
        self.levs_maxTextbox.setText('')
        self.levs_stepTextbox.setText('')
        self.levs_manualTextbox.setText('')
        plotvars.levs_set = False


    def help(self):
        if self.contour_levels_help is None:

            html = ''
            html += '<body><h2>Contour level options</h2>'
            html += 'Contour levels are initially set automatically based on the range of the field and '
            html += 'split into reasonable contour levels. If a region of the field is chosen for contouring '
            html += 'then the range of the full field is still used.'

            html += '<h3>Setting contour levels</h3>'
            html += 'When making plots that compare data click on the evenly or manually spaced levels tick '
            html += 'boxes and set them as appropriate. Manualy spaced levels must be separated by spaces and ascend in value.'

            html += '<h3>Colorbar extensions</h3>'
            html += 'Colorbar extensions are a way of extending the contours to cover all the data at the ends of the '
            html += 'contour range. Click on the colorbar extension tick boxes as appropriate if these are both required.</p></body>' 

            self.contour_levels_help = Help(html)

        self.contour_levels_help.show()


    def extension_type(self, text):

        plotvars.levs_extend_lower = self.extension_lowerCheck.isChecked()
        plotvars.levs_extend_upper = self.extension_upperCheck.isChecked()



class Help(QWidget):
    '''Popup window showing help text'''

    def __init__(self, html):
        super(Help, self).__init__()
        self.html = html
        self.initUI()


    def initUI(self):

        quitButton = QPushButton("Quit")
        quitButton.clicked.connect(self.close)


        helpTextbox = QTextEdit()
        helpTextbox.setReadOnly(True)



        doc = QTextDocument()

        doc.setHtml(self.html)
        helpTextbox.setDocument(doc)





        vbox = QVBoxLayout()
        vbox.addWidget(helpTextbox)
        vbox.addWidget(quitButton)

        self.setLayout(vbox)
       

        palette = QPalette()    
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))    
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))    
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        self.setPalette(palette)

        # Set font 
        custom_font = QFont(plotvars.font, plotvars.fontsize)
        self.window().setFont(custom_font)

        self.setMinimumSize(600, 600)

        self.show()



class HLine(QFrame):
    def __init__(self, parent=None, color=QColor(plotvars.text_colour)):

        super(HLine, self).__init__(parent)
        self.setFrameShape(QFrame.HLine)
        self.setFrameShadow(QFrame.Plain)
        self.setFixedHeight(40)
        self.setLineWidth(0)
        self.setMidLineWidth(3)
        self.setContentsMargins(0, 0, 0, 0)
        self.setColor(color)

    def setColor(self, color):
        pal = self.palette()
        pal.setColor(QPalette.WindowText, color)
        self.setPalette(pal)


class Colour_scale_window(QWidget):
    '''popup window for changing colour scale defaults'''

    def __init__(self):
        super(Colour_scale_window, self).__init__()
        self.initUI()


    def initUI(self):

        # Set up some buttons
        resetButton = QPushButton("Reset")
        resetButton.clicked.connect(self.reset)

        helpButton = QPushButton("Help")
        helpButton.clicked.connect(self.help)

        quitButton = QPushButton("Quit")
        quitButton.clicked.connect(self.close)



        # Scale selection tick boxes
        automaticCheckBox = QCheckBox("Automatic colour scale")
        automaticCheckBox.setChecked(True)
        automaticCheckBox.clicked.connect(self.automatic)

        reverseCheckBox = QCheckBox("Reverse colour scale")
        reverseCheckBox.setChecked(False)
        reverseCheckBox.clicked.connect(self.reverse)

        # Text box labels
        numberLabel = QLabel('Number of colours in the scale')
        whiteLabel = QLabel('Set these indicies to be white')
        aboveLabel = QLabel('Number of colours above the scale midpoint')
        belowLabel = QLabel('Number of colours below the scale midpoint')

        pal = QPalette(numberLabel.palette())
        pal.setColor(QPalette.WindowText, QColor('#708090'))
        numberLabel.setPalette(pal)

        # Text boxes
        numberTextBox = QLineEdit()
        numberTextBox.textChanged.connect(lambda: self.text_changed('number'))
        whiteTextBox = QLineEdit()
        whiteTextBox.textChanged.connect(lambda: self.text_changed('white'))
        aboveTextBox = QLineEdit()
        aboveTextBox.textChanged.connect(lambda: self.text_changed('above'))
        belowTextBox = QLineEdit()
        belowTextBox.textChanged.connect(lambda: self.text_changed('below'))


        # Set the layout
        vbox = QVBoxLayout()
        hbox_number = QHBoxLayout()
        hbox_white = QHBoxLayout()
        hbox_above = QHBoxLayout()
        hbox_below = QHBoxLayout()
        hbox_buttons = QHBoxLayout()

        vbox.addWidget(automaticCheckBox)
        vbox.addWidget(HLine())

        vbox.addLayout(hbox_number)
        hbox_number.addWidget(numberLabel)
        hbox_number.addWidget(numberTextBox)

        vbox.addLayout(hbox_white)
        hbox_white.addWidget(whiteLabel)
        hbox_white.addWidget(whiteTextBox)

        vbox.addLayout(hbox_above)
        hbox_above.addWidget(aboveLabel)
        hbox_above.addWidget(aboveTextBox)

        vbox.addLayout(hbox_below)
        hbox_below.addWidget(belowLabel)
        hbox_below.addWidget(belowTextBox)

        vbox.addWidget(reverseCheckBox)

        vbox.addWidget(HLine())

        # Make a scrollable area for the colour bars and check boxes
        vbox_scale = QVBoxLayout()
        vbox.addLayout(vbox_scale)

        formLayout = QFormLayout()
        groupBox = QGroupBox('Colour scales')
        checkboxlist = []
        scaleimagelist = []

        self.automaticCheckBox = automaticCheckBox
        self.reverseCheckBox = reverseCheckBox
        self.numberTextBox = numberTextBox
        self.whiteTextBox = whiteTextBox
        self.aboveTextBox = aboveTextBox
        self.belowTextBox = belowTextBox
        self.numberLabel = numberLabel
        self.aboveLabel = aboveLabel
        self.belowLabel = belowLabel
        self.whiteLabel = whiteLabel



        # Add the colours scale checkboxes and colour scales
        for i in np.arange(len(plotvars.cscales)):
            scale = plotvars.cscales[i]
            if scale == 'viridis':
                formLayout.addRow(QLabel('Perceptually neutral colour scales'))
            if scale == 'hotcold_18lev':
                formLayout.addRow(QLabel(''))
                formLayout.addRow(QLabel('NCAR Command Language - MeteoSwiss colour maps'))
            if scale == 'amwg':
                formLayout.addRow(QLabel(''))
                formLayout.addRow(QLabel('NCAR Command Language - small color maps (<50 colours)'))
            if scale == 'amwg256':
                formLayout.addRow(QLabel(''))
                formLayout.addRow(QLabel('NCAR Command Language - large color maps (>50 colours)'))
            if scale == 'StepSeq25':
                formLayout.addRow(QLabel(''))
                formLayout.addRow(QLabel('NCAR Command Language - Enhanced to help with colour blindness'))
            if scale == 'os250kmetres':
                formLayout.addRow(QLabel(''))
                formLayout.addRow(QLabel('Orography/bathymetry colour scales'))
            if scale == 'scale1':
                formLayout.addRow(QLabel(''))
                formLayout.addRow(QLabel('IDL guide scales'))

            setattr(self, scale + 'CheckBox', QCheckBox(scale))
            getattr(self, scale + 'CheckBox').setChecked(False)
            getattr(self, scale + 'CheckBox').clicked.connect(partial(self.scale_changed, plotvars.cscales[i]))

            image = QLabel()
            pixmap = QPixmap('colour_scales/' + scale + '.png')
            image.setPixmap(pixmap)

            formLayout.addRow(getattr(self, scale + 'CheckBox'), image)


        self.viridisCheckBox.setChecked(True)

        groupBox.setLayout(formLayout)
        #vbox_scale.setLayout(formLayout)
        scroll = QScrollArea()
        scroll.setWidget(groupBox)
        scroll.setWidgetResizable(True)
        scroll.setFixedHeight(400)
        vbox_scale.addWidget(scroll)





        vbox.addLayout(hbox_buttons)
        hbox_buttons.addWidget(resetButton)
        hbox_buttons.addWidget(helpButton)
        hbox_buttons.addWidget(quitButton)


        self.colour_scale_help = None  # No external window yet.

        self.setWindowTitle('cfview colour scales')
        self.setLayout(vbox)



        # Set theme and font
        palette = QPalette()
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        self.setPalette(palette)

        custom_font = QFont(plotvars.font, plotvars.fontsize)
        self.window().setFont(custom_font)

        # Initial set of widget sensitivity
        plotvars.cscale_automatic_set = self.automaticCheckBox.isChecked()
        self.set_sensitive()

        self.show()



    def text_changed(self, textbox):
        if textbox == 'number':
            plotvars.cscale_ncols = self.numberTextBox.text()
        if textbox == 'white':
            plotvars.cscale_white = self.whiteTextBox.text()
        if textbox == 'above':
            plotvars.cscale_above = self.aboveTextBox.text()
        if textbox == 'below':
            plotvars.cscale_below = self.belowTextBox.text()





    def automatic(self):
        # Toggle automatic colour scales
        if self.automaticCheckBox.isChecked():
            self.reset()
        else:
            plotvars.cscale_automatic_set = self.automaticCheckBox.isChecked()
            self.set_sensitive()


    def set_sensitive(self):
        # Set the sensitivity and color of the widgets

        if plotvars.cscale_automatic_set:
            color = plotvars.text_colour_insensitive
            enabled = False
        else:
            color = plotvars.text_colour
            enabled = True

        objs = [self.reverseCheckBox, self.numberTextBox, self.whiteTextBox, self.aboveTextBox, \
               self.belowTextBox, self.reverseCheckBox, self.numberLabel, self.aboveLabel,\
               self.belowLabel, self.whiteLabel]
        for scale in plotvars.cscales:
            objs.append(getattr(self, scale + 'CheckBox'))

        for obj in objs:
            obj.setEnabled(enabled)
            pal = QPalette(obj.palette())
            pal.setColor(QPalette.WindowText, QColor(color))
            obj.setPalette(pal)


    def reverse(self):
        plotvars.cscale_reverse_set = self.reverseCheckBox.isChecked()


    def scale_changed(self, myscale):
        for scale in plotvars.cscales:
            getattr(self, scale + 'CheckBox').setChecked(False)

        getattr(self, myscale + 'CheckBox').setChecked(True)
        plotvars.cscale = myscale


    def reset(self):

        self.automaticCheckBox.setChecked(True)
        plotvars.cscale_automatic_set = True
        self.reverseCheckBox.setChecked(False)
        self.numberTextBox.setText('')
        self.whiteTextBox.setText('')
        self.aboveTextBox.setText('')
        self.belowTextBox.setText('')
        
        for scale in plotvars.cscales:
            getattr(self, scale + 'CheckBox').setChecked(False)

        self.viridisCheckBox.setChecked(True)
        plotvars.cscale = 'viridis'
        plotvars.cscale_reverse_set = False
        plotvars.cscale_white = ''
        plotvars.cscale_ncols = ''
        plotvars.cscale_above = ''
        plotvars.cscale_below = ''
        print('In cscale reset')
        print(plotvars.cscale, plotvars.cscale_reverse_set, plotvars.cscale_white, plotvars.cscale_ncols, plotvars.cscale_above, plotvars.cscale_below)

        self.set_sensitive()

    def help(self):

        if self.colour_scale_help is None:

            html = ""
            html += "<body><h2>Colour scale options</h2>"
            html += "With the automatic colour scale option ticked cfview selects the colour scale depending "
            html += "on the data to be contoured:<p>"
            html += "viridis - fields that don\'t span zero - temperature in Kelvin etc.  This is a perceptually "
            html += "neutral colour scale that doesn\'t draw the eye to any part of the scale <p>"
            html += "scale1 - fields that span zero - zonal wind etc.  This is a blue - red scale suitable for "
            html += "contour plots of fields that have a zero in their contour levels.  The scale is automatically "
            html += "adjusted so that blue colours are below zero and red colours above.<p>"
            html += "<h3>Selecting a colour scale</h3>"
            html += "When a different colour scale is selected the scale will be automatically adjusted "
            html += "to fit the number of contour levels.<p>"
            html += "<h3>Selecting the number of colours</h3>"
            html += "Set the number of colours in the scale to gain more control over the colour scale. "
            html += "Once this is done then the white indicies and scale midpoint options become useful "
            html += "to allow more precise scale manipulation.  Set a number of white colour indicies by leaving "
            html += "a space between the indices required.<p>"

            self.colour_scale_help = Help(html)

        self.colour_scale_help.show()


class Map_window(QWidget):
    '''popup window for changing map defaults'''

    def __init__(self):
        super(Map_window, self).__init__()
        self.initUI()


    def initUI(self):

        # Set up some buttons
        resetButton = QPushButton("Reset")
        resetButton.clicked.connect(self.reset)

        helpButton = QPushButton("Help")
        helpButton.clicked.connect(self.help)

        quitButton = QPushButton("Quit")
        quitButton.clicked.connect(self.close)


        # Text box labels
        lonminLabel = QLabel('lonmin')
        lonmaxLabel = QLabel('lonmax')
        latminLabel = QLabel('latmin')
        latmaxLabel = QLabel('latmax')
        boundinglatLabel = QLabel('Bounding latitude')
        lon_0Label = QLabel('Longitude centre of map domain')
        other_map_typesLabel = QLabel('Other map types')
        continent_attributesLabel = QLabel('Continent Attributes')
        continent_thicknessLabel = QLabel('Thickness')
        continent_colorLabel = QLabel('Colour')

        # Text boxes
        lonminTextBox = QLineEdit()
        lonminTextBox.setText('-180')
        lonminTextBox.textChanged.connect(lambda: self.textbox_changed('lonmin'))
        lonmaxTextBox = QLineEdit()
        lonmaxTextBox.setText('180')
        lonmaxTextBox.textChanged.connect(lambda: self.textbox_changed('lonmax'))
        latminTextBox = QLineEdit()
        latminTextBox.setText('-90')
        latminTextBox.textChanged.connect(lambda: self.textbox_changed('latmin'))
        latmaxTextBox = QLineEdit()
        latmaxTextBox.setText('90')
        latmaxTextBox.textChanged.connect(lambda: self.textbox_changed('latmax'))
        boundinglatTextBox = QLineEdit()
        boundinglatTextBox.setText('0')
        boundinglatTextBox.textChanged.connect(lambda: self.textbox_changed('boundinglat'))
        lon_0TextBox = QLineEdit()
        lon_0TextBox.setText('0')
        lon_0TextBox.textChanged.connect(lambda: self.textbox_changed('lon_0'))
        continent_thicknessTextBox = QLineEdit()
        continent_thicknessTextBox.setText('1.5')
        continent_thicknessTextBox.textChanged.connect(lambda: self.textbox_changed('continent_thickness'))
        continent_colorTextBox = QLineEdit()
        continent_colorTextBox.setText('black')
        continent_colorTextBox.textChanged.connect(lambda: self.textbox_changed('continent_color'))

        # Map type check boxes
        maps = ['Cylindrical', 'EuroPP', 'LambertConformal', 'Mercator', 'Mollweide',\
                'NorthPoleStereographic', 'Orthographic', 'OSGB', 'Robinson',\
                'SouthPoleStereographic', 'UKCP']
        maps_short = ['cyl', 'EuroPP', 'lcc', 'merc', 'moll', 'npstere', 'ortho',\
                      'OSGB', 'robin', 'spstere', 'UKCP']

        for i in np.arange(len(maps)):
            setattr(self, maps[i] + 'CheckBox', QCheckBox(maps[i]))
            getattr(self, maps[i] + 'CheckBox').setChecked(False)
            getattr(self, maps[i] + 'CheckBox').clicked.connect(partial(self.map_type, maps_short[i]))

        self.CylindricalCheckBox.setChecked(True)




        self.lonminLabel = lonminLabel
        self.lonmaxLabel = lonmaxLabel
        self.latminLabel = latminLabel
        self.latmaxLabel = latmaxLabel
        self.boundinglatLabel = boundinglatLabel
        self.lon_0Label = lon_0Label
        self.other_map_typesLabel = other_map_typesLabel
        self.continent_attributesLabel = continent_attributesLabel
        self.continent_thicknessLabel = continent_thicknessLabel
        self.continent_colorLabel = continent_colorLabel

        self.lonminTextBox = lonminTextBox
        self.lonmaxTextBox = lonmaxTextBox
        self.latminTextBox = latminTextBox
        self.latmaxTextBox = latmaxTextBox
        self.boundinglatTextBox = boundinglatTextBox
        self.lon_0TextBox = lon_0TextBox
        self.continent_thicknessTextBox = continent_thicknessTextBox
        self.continent_colorTextBox = continent_colorTextBox

        # Set the layout
        vbox = QVBoxLayout()

        # Cylindrical options
        vbox.addWidget(self.CylindricalCheckBox)
        hbox_lons = QHBoxLayout()
        hbox_lons.addWidget(self.lonminLabel)
        hbox_lons.addWidget(self.lonminTextBox)
        hbox_lons.addWidget(self.lonmaxLabel)
        hbox_lons.addWidget(self.lonmaxTextBox)
        vbox.addLayout(hbox_lons)

        hbox_lats = QHBoxLayout()
        hbox_lats.addWidget(self.latminLabel)
        hbox_lats.addWidget(self.latminTextBox)
        hbox_lats.addWidget(self.latmaxLabel)
        hbox_lats.addWidget(self.latmaxTextBox)
        vbox.addLayout(hbox_lats)

        vbox.addWidget(HLine())

        # Polar options
        hbox_polar = QHBoxLayout()
        hbox_polar.addWidget(self.NorthPoleStereographicCheckBox)
        hbox_polar.addWidget(self.SouthPoleStereographicCheckBox)
        vbox.addLayout(hbox_polar)

        hbox_polar2 = QHBoxLayout()
        hbox_polar2.addWidget(self.boundinglatLabel)
        hbox_polar2.addWidget(self.boundinglatTextBox)
        vbox.addLayout(hbox_polar2)

        hbox_polar3 = QHBoxLayout()
        hbox_polar3.addWidget(self.lon_0Label)
        hbox_polar3.addWidget(self.lon_0TextBox)
        vbox.addLayout(hbox_polar3)

        vbox.addWidget(HLine())

        # Other maps
        vbox.addWidget(self.other_map_typesLabel)
        hbox_other1 = QHBoxLayout()
        hbox_other1.addWidget(self.EuroPPCheckBox)
        hbox_other1.addWidget(self.LambertConformalCheckBox)
        hbox_other1.addWidget(self.MercatorCheckBox)
        vbox.addLayout(hbox_other1)
        hbox_other2 = QHBoxLayout()
        hbox_other2.addWidget(self.OrthographicCheckBox)
        hbox_other2.addWidget(self.OSGBCheckBox)
        hbox_other2.addWidget(self.RobinsonCheckBox)
        hbox_other2.addWidget(self.UKCPCheckBox)
        vbox.addLayout(hbox_other2)
        vbox.addWidget(HLine())

        # Continent thickness and colour
        vbox.addWidget(self.continent_attributesLabel)
        hbox_thickness = QHBoxLayout()
        hbox_thickness.addWidget(self.continent_thicknessLabel)
        hbox_thickness.addWidget(self.continent_thicknessTextBox)
        hbox_thickness.addStretch(1)
        vbox.addLayout(hbox_thickness)
        hbox_color = QHBoxLayout()
        hbox_color.addWidget(self.continent_colorLabel)
        hbox_color.addWidget(self.continent_colorTextBox)
        hbox_color.addStretch(1)
        vbox.addLayout(hbox_color)


        # The buttons
        hbox_buttons = QHBoxLayout()
        vbox.addLayout(hbox_buttons)
        hbox_buttons.addWidget(resetButton)
        hbox_buttons.addWidget(helpButton)
        hbox_buttons.addWidget(quitButton)


        self.map_help = None  # No external window yet.

        self.setWindowTitle('cfview map settings')
        self.setLayout(vbox)

        # Set theme and font
        palette = QPalette()
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        self.setPalette(palette)

        custom_font = QFont(plotvars.font, plotvars.fontsize)
        self.window().setFont(custom_font)

        # Set sensitivity of widgets
        self.set_sensitive()

        self.show()


    def map_type(self, text):

        maps = ['Cylindrical', 'EuroPP', 'LambertConformal', 'Mercator', 'Mollweide',\
                'NorthPoleStereographic', 'Orthographic', 'OSGB', 'Robinson',\
                'SouthPoleStereographic', 'UKCP']
        maps_short = ['cyl', 'EuroPP', 'lcc', 'merc', 'moll', 'npstere', 'ortho', 'OSGB', 
                      'robin', 'spstere', 'UKCP']


        for i in np.arange(len(maps)):
            getattr(self, maps[i] + 'CheckBox').setChecked(False)


        index = maps_short.index(text)
        getattr(self, maps[index] + 'CheckBox').setChecked(True)
        
        plotvars.proj = text

        self.set_sensitive()


    def textbox_changed(self, text):

        textbox = getattr(self, text + 'TextBox') 
        setattr(plotvars, text, textbox.text()) 


    def set_sensitive(self):
        # Set sensivity of plot widgets

        objs = [self.lonminLabel, self.lonminTextBox, self.lonmaxLabel,\
                self.lonmaxTextBox, self.latminLabel, self.latminTextBox,\
                self.latmaxLabel, self.latmaxTextBox,\
                self.boundinglatLabel,\
                self.boundinglatTextBox, self.lon_0Label, self.lon_0TextBox]

        colors = [plotvars.text_colour] * 15
        enabled = [False] * 15

        if plotvars.proj in ['cyl', 'EuroPP', 'lcc', 'merc', 'ortho', 'OSGB',\
                             'robin', 'UKCP']:
            enabled[0:7] = [True] * 8
            colors[8:] = [plotvars.text_colour_insensitive] * 6
        else:
            colors[0:7] = [plotvars.text_colour_insensitive] * 8
            enabled[8:] = [True] * 6

        for i in np.arange(len(objs)):
            obj = objs[i]
            obj.setEnabled(enabled[i])
            pal = QPalette(obj.palette())
            pal.setColor(QPalette.WindowText, QColor(colors[i]))
            obj.setPalette(pal)


    def reset(self):
        plotvars.proj = 'cyl'
        maps = ['Cylindrical', 'EuroPP', 'LambertConformal', 'Mercator', 'Mollweide',\
                'NorthPoleStereographic', 'Orthographic', 'OSGB', 'Robinson',\
                'SouthPoleStereographic', 'UKCP']
        for i in np.arange(len(maps)):
            getattr(self, maps[i] + 'CheckBox').setChecked(False)

        self.CylindricalCheckBox.setChecked(True)
        self.set_sensitive()

        plotvars.lonmin = -180
        plotvars.lonmax = 190
        plotvars.latmin = -90
        plotvars.latmax = 90
        self.lonminTextBox.setText('-180')
        self.lonmaxTextBox.setText('180')
        self.latminTextBox.setText('-90')
        self.latmaxTextBox.setText('90')
        


        plotvars.boundinglat = 0
        plotvars.lon_0 = 0
        self.boundinglatTextBox.setText('0')
        self.lon_0TextBox.setText('0')
        self.continent_thicknessTextBox.setText('1.5')
        self.continent_colorTextBox.setText('black')



    def help(self):
        print('in help')

        if self.map_help is None:

            html = ""
            html += "<body><h2>Map options</h2>"
            html += "<h3>Cylindrical projection</h3>"
            html += "The default map projection is the cylindrical equidistant projection with "
            html += "the limits of -180 to 180 degrees in longitude and -90 to 90 degrees in "
            html += "latitude. Change these as appropriate to focus the plot onto the area of "
            html += "interest."
            html += "<h3>Polar stereographic plots</h3>"
            html += "Polar plots are focussed on either the north or south pole. The bounding "
            html += "latitude is the edge of the viewable latitudes and is set to the equator "
            html += "by default. The centre of the map domain is where the map is centred. By "
            html += "default this is 0 degrees which is the Greenwich meridian in the case of "
            html += "the north pole. For the South Pole plot this is usually changed to 180 "
            html += "degrees."
            html += "<h3>Map resolution</h3>"
            html += "The map resolution is set to a default of 110m. Higher resolutions such as "
            html += "50m and 10m take more time to plot.  50m means 1:50,000,000 and not 50 metre."

            html += "<h3>Continent color and thickness</h3>"
            html += "These default to 1.5 and black. Matplotlib "
            html += "named colors can be seen using the following Python code at the Python "
            html += "command prompt:<p>"

            html += "<b>import matplotlib<br>"
            html += "for name in matplotlib.colors.cnames: print(name)</b>"

            self.map_help = Help(html)

        self.map_help.show()


class Contour_window(QWidget):
    '''popup window for changing contour defaults'''

    def __init__(self):
        super(Contour_window, self).__init__()
        self.initUI()


    def initUI(self):

        # Set up some buttons
        resetButton = QPushButton("Reset")
        resetButton.clicked.connect(self.reset)

        helpButton = QPushButton("Help")
        helpButton.clicked.connect(self.help)

        quitButton = QPushButton("Quit")
        quitButton.clicked.connect(self.close)

        # Text box labels
        titleLabel = QLabel('title')
        zero_thickLabel = QLabel('zero_thick')

        # Text boxes
        titleTextBox = QLineEdit()
        titleTextBox.setText('')
        titleTextBox.textChanged.connect(lambda: self.textbox_changed('title'))
        zero_thickTextBox = QLineEdit()
        zero_thickTextBox.setText('')
        zero_thickTextBox.textChanged.connect(lambda: self.textbox_changed('zero_thick'))



        types = ['fill', 'blockfill', 'lines', 'line_labels', 'colorbar', 'automatic', 'horizontal', 'vertical']
        status = [True, False, False, False, True, True, False, False]
        for i in np.arange(len(types)):
            setattr(self, types[i] + 'CheckBox', QCheckBox(types[i]))
            getattr(self, types[i] + 'CheckBox').setChecked(status[i])
            getattr(self, types[i] + 'CheckBox').clicked.connect(partial(self.contour_type, types[i]))


        self.titleLabel = titleLabel
        self.zero_thickLabel = zero_thickLabel
        self.titleTextBox = titleTextBox
        self.zero_thickTextBox = zero_thickTextBox



        # Set the layout
        vbox = QVBoxLayout()

        hbox_types = QHBoxLayout()
        hbox_types.addWidget(self.fillCheckBox)
        hbox_types.addWidget(self.blockfillCheckBox)
        hbox_types.addWidget(self.linesCheckBox)
        hbox_types.addWidget(self.line_labelsCheckBox)
        vbox.addLayout(hbox_types)

        hbox_titles = QHBoxLayout()
        hbox_titles.addWidget(self.titleLabel)
        hbox_titles.addWidget(self.titleTextBox)
        vbox.addLayout(hbox_titles)

        hbox_colourbar = QHBoxLayout()
        hbox_colourbar.addWidget(self.colorbarCheckBox)
        hbox_colourbar.addWidget(self.automaticCheckBox)
        hbox_colourbar.addWidget(self.horizontalCheckBox)
        hbox_colourbar.addWidget(self.verticalCheckBox)
        vbox.addLayout(hbox_colourbar)


        # The buttons
        hbox_buttons = QHBoxLayout()
        vbox.addLayout(hbox_buttons)
        hbox_buttons.addWidget(resetButton)
        hbox_buttons.addWidget(helpButton)
        hbox_buttons.addWidget(quitButton)
        vbox.addLayout(hbox_buttons)


        self.contour_help = None  # No external window yet.

        self.setWindowTitle('cfview contour settings')
        self.setLayout(vbox)

        # Set theme and font
        palette = QPalette()
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        self.setPalette(palette)

        custom_font = QFont(plotvars.font, plotvars.fontsize)
        self.window().setFont(custom_font)


        self.show()


    def contour_type(self, text):
        cbox = getattr(self, text + 'CheckBox')
        val = cbox.isChecked()

        if text == 'fill' and val:
            plotvars.blockfill = False
            self.blockfillCheckBox.setChecked(False)

        if text == 'blockfill' and val:
            plotvars.fill = False
            self.fillCheckBox.setChecked(False)

        if text == 'lines' and not val:
            plotvars.line_labels = False
            self.line_labelsCheckBox.setChecked(False)

        if text == 'lines' and val:
            plotvars.line_labels = True
            self.line_labelsCheckBox.setChecked(True)

        if text == 'automatic':
            plotvars.colorbar_orientation = 'None'
            self.horizontalCheckBox.setChecked(False)
            self.verticalCheckBox.setChecked(False)

        if text == 'horizontal':
            plotvars.colorbar_orientation = 'horizontal'
            self.automaticCheckBox.setChecked(False)
            self.verticalCheckBox.setChecked(False)

        if text == 'vertical':
            plotvars.colorbar_orientation = 'vertical'
            self.automaticCheckBox.setChecked(False)
            self.horizontalCheckBox.setChecked(False)

        if self.colorbarCheckBox.isChecked():
            color = plotvars.text_colour
            enabled = True
        else:
            color = plotvars.text_colour_insensitive
            enabled = False

        objs = [self.automaticCheckBox, self.horizontalCheckBox, self.verticalCheckBox]
        for obj in objs:
            obj.setEnabled(enabled)
            pal = QPalette(obj.palette())
            pal.setColor(QPalette.WindowText, QColor(color))
            obj.setPalette(pal)


        setattr(plotvars, text, val) 


    def reset(self):
        # reset contour options
        self.fillCheckBox.setChecked(True)
        self.blockfillCheckBox.setChecked(False)
        self.linesCheckBox.setChecked(False)
        self.line_labelsCheckBox.setChecked(False)
        self.titleTextBox.setText('')

        self.automaticCheckBox.setChecked(True)
        self.horizontalCheckBox.setChecked(False)
        self.verticalCheckBox.setChecked(False)

        plotvars.fill = True
        plotvars.blockfill = False
        plotvars.lines = False
        plotvars.line_labels = False
        plotvars.text = ''
        plotvars.colorbar_orientation = None




    def help(self):

        if self.contour_help is None:

            html = '<body><h2>Contour options</h2>'
            html += 'Contour options of fill and blockfill are mutually exclusive.  If a '
            html += 'grid with lots of points in x and y is plotted then the blockfill '
            html += 'grid will not be readily visible until the plot is zoomed in'
            

            self.contour_help = Help(html)

        self.contour_help.show()


    def textbox_changed(self, text):

        textbox = getattr(self, text + 'TextBox') 
        setattr(plotvars, text, textbox.text()) 



class TableModel(QAbstractTableModel):

    def __init__(self, data, x, y, ndecs, datamin, datamax, datamin_colour, datamax_colour):
        super(TableModel, self).__init__()
        self._data = data
        self._x = x
        self._y = y
        self._ndecs = ndecs
        self._datamin = datamin
        self._datamax = datamax
        self._datamin_colour = datamin_colour
        self._datamax_colour = datamax_colour


    def data(self, index, role): 

        try:
            v = float(self._datamax)
            if role == Qt.BackgroundRole and  self._data[index.row(), index.column()] >= float(self._datamax):
                return QColor(self._datamax_colour)
        except:
            pass

        try:
            v = float(self._datamin)
            if role == Qt.BackgroundRole and  self._data[index.row(), index.column()] <= float(self._datamin):
                return QColor(self._datamin_colour)
        except:
            pass


        if role == Qt.DisplayRole:
            value = self._data[index.row(), index.column()]
            if self._ndecs == 0:
                return str(int(value))
            else:
                 return str(round(value, self._ndecs))

    def rowCount(self, index):
        return self._data.shape[0]

    def columnCount(self, index):
        return self._data.shape[1]

    def headerData(self, section, orientation, role):
        #if role != Qt.DisplayRole or orientation != Qt.Horizontal:
        #    return QVariant()

        if role != Qt.DisplayRole:
            return QVariant()

        if orientation == Qt.Horizontal:
            xlabels = []
            for ix in np.arange(len(self._x)):
                xlabels.append(str(self._x[ix]))
            return xlabels[section]

        if orientation == Qt.Vertical:
            ylabels = []
            for iy in np.arange(len(self._y)):
                ylabels.append(str(self._y[iy]))
            return ylabels[section]
 



class Data_window(QWidget):
    '''popup window for viewing data'''

    def __init__(self, cfview_parent):
        super(Data_window, self).__init__()
        self.cfview_parent = cfview_parent
        self.initUI()

    def initUI(self):

        # Set up some buttons
        resetButton = QPushButton("Reset")
        resetButton.clicked.connect(self.reset)

        plotButton = QPushButton("Plot selected cells")
        plotButton.clicked.connect(self.plot)

        helpButton = QPushButton("Help")
        helpButton.clicked.connect(self.help)

        quitButton = QPushButton("Quit")
        quitButton.clicked.connect(self.close)

        # Text box labels
        colouringLabel = QLabel('Data colouring:')
        ndecsLabel = QLabel('Number of decimal places: 2')
        text_sizeLabel = QLabel('Text size: ')
        dataminLabel = QLabel('Minimum')
        datamin_colourLabel = QLabel('Minimum Colour')
        datamaxLabel = QLabel('Maximum')
        datamax_colourLabel = QLabel('Maximum Colour')

        # Text boxes
        dataminTextBox = QLineEdit()
        dataminTextBox.setText('')
        dataminTextBox.textChanged.connect(self.value_changed)
        datamaxTextBox = QLineEdit()
        datamaxTextBox.setText('')
        datamaxTextBox.textChanged.connect(self.value_changed)
        datamin_colourTextBox = QLineEdit()
        datamin_colourTextBox.setText('blue')
        datamin_colourTextBox.textChanged.connect(self.value_changed)
        datamax_colourTextBox = QLineEdit()
        datamax_colourTextBox.setText('red')
        datamax_colourTextBox.textChanged.connect(self.value_changed)

        # ndecs and text size sliders
        ndecsSlider = QSlider(Qt.Horizontal)
        ndecsSlider.setMinimum(0)
        ndecsSlider.setMaximum(9)
        ndecsSlider.setValue(2)
        ndecsSlider.valueChanged.connect(self.value_changed)

        text_sizeSlider = QSlider(Qt.Horizontal)
        text_sizeSlider.setMinimum(1)
        text_sizeSlider.setMaximum(30)
        text_sizeSlider.setValue(plotvars.fontsize)
        text_sizeSlider.valueChanged.connect(self.value_changed)



        
        # Make a copy of the field
        index = plotvars.index_number
        f = deepcopy(plotvars.fields[index])
        data = f[0, 0, :, :].array.squeeze()
        print('shape of data is ', np.shape(data))
        x = f.coord('X').array         
        y = f.coord('Y').array         


        ndecs = 2

        table = QTableView()

        datamin = ''
        datamax = ''
        datamin_colour = ''
        datamax_colour = ''


        model = TableModel(data, x, y, ndecs, datamin, datamax, datamin_colour, datamax_colour)

        table.setModel(model)




        xlabels = []        
        for ix in np.arange(len(x)):
            xlabels.append(str(x[ix]))


        ylabels = []        
        for iy in np.arange(len(y)):
            ylabels.append(str(y[iy]))


        self.table = table
        self.ndecsLabel = ndecsLabel
        self.ndecsSlider = ndecsSlider

        self.text_sizeLabel = text_sizeLabel
        self.text_sizeSlider = text_sizeSlider

        self.dataminLabel = dataminLabel
        self.datamaxLabel = datamaxLabel
        self.datamin_colourLabel = datamin_colourLabel
        self.datamax_colourLabel = datamax_colourLabel

        self.dataminTextBox = dataminTextBox
        self.datamaxTextBox = datamaxTextBox
        self.datamin_colourTextBox = datamin_colourTextBox
        self.datamax_colourTextBox = datamax_colourTextBox

        self.data = data
        self.x = x
        self.y = y





        vbox = QVBoxLayout()

        vbox.addWidget(table)

        sliders_hbox = QHBoxLayout()
        sliders_hbox.addWidget(ndecsLabel)
        sliders_hbox.addWidget(ndecsSlider)
        sliders_hbox.addWidget(text_sizeLabel)
        sliders_hbox.addWidget(text_sizeSlider)
        vbox.addLayout(sliders_hbox)

        datacolours_hbox = QHBoxLayout()
        datacolours_hbox.addWidget(colouringLabel)
        datacolours_hbox.addWidget(dataminLabel)
        datacolours_hbox.addWidget(dataminTextBox)
        datacolours_hbox.addWidget(datamin_colourLabel)
        datacolours_hbox.addWidget(datamin_colourTextBox)
        datacolours_hbox.addWidget(datamaxLabel)
        datacolours_hbox.addWidget(datamaxTextBox)
        datacolours_hbox.addWidget(datamax_colourLabel)
        datacolours_hbox.addWidget(datamax_colourTextBox)
        vbox.addLayout(datacolours_hbox)

        # The buttons
        hbox_buttons = QHBoxLayout()
        vbox.addLayout(hbox_buttons)
        hbox_buttons.addWidget(resetButton)
        hbox_buttons.addWidget(plotButton)
        hbox_buttons.addWidget(helpButton)
        hbox_buttons.addWidget(quitButton)
        vbox.addLayout(hbox_buttons)


        self.data_help = None  # No external window yet.

        self.setWindowTitle('cfview view data')
        self.setLayout(vbox)

        # Set theme and font
        palette = QPalette()
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        self.setPalette(palette)

        custom_font = QFont(plotvars.font, plotvars.fontsize)
        self.window().setFont(custom_font)


        self.show()



    def help(self):

        if self.data_help is None:

            html = ""
            html += "<body><h2>Data viewing</h2>"
            html += "Describe window and options "

            self.contour_help = Help(html)

        self.contour_help.show()


    def plot(self):
        selected = self.table.selectionModel().selectedIndexes()

        if selected:
            xvals = []
            yvals = []
            for item in selected:
                 xvals.append(item.column())
                 yvals.append(item.row())

            minx = min(xvals)
            maxx = max(xvals)
            miny = min(yvals)
            maxy = max(yvals)

            # Form the subspace dictionary from the currently selected data'''
            index = plotvars.index_number
            f = deepcopy(plotvars.fields[index])


            # Form the subspace dictionary
            nx, ny, nz, nt, x, y, z, t = Cf_funcs.field_dims(field=f)
            dim_sizes = [nx, ny, nz, nt]
            dims = ['X', 'Y', 'Z', 'T']
            lists = [self.cfview_parent.xlist.selectedItems(), self.cfview_parent.ylist.selectedItems(),\
                     self.cfview_parent.zlist.selectedItems(), self.cfview_parent.tlist.selectedItems()]
            collapses = [plotvars.collapse_x, plotvars.collapse_y,\
                     plotvars.collapse_z, plotvars.collapse_t]
            subspace_args ={}

            for i in np.arange(4):
                vals = []
                for j in np.arange(len(lists[i])):
                    vals.append(str(lists[i][j].text()))

                if any(dim == dims[i].lower() for dim in plotvars.contour_type):
                    if np.size(vals) < 2:
                        con_okay = False
                else:
                    if collapses[i] == 'Off':
                        if dim_sizes[i] > 1:
                            vals = [vals[0]]

                if len(vals) != dim_sizes[i]:
                    if len(vals) == 1:

                        if collapses[i] == 'Off':
                            if dims[i] != 'T':
                                subspace_args[dims[i]] = float(vals[0])
                            else:
                                subspace_args[dims[i]] = cf.dt(vals[0])
                    else:
                        if dims[i] != 'T':
                            # cf.wi needs to go from min to max but the widget return
                            # goes in order of selection
                            val1 = np.min(np.array(vals).astype(np.float))
                            val2 = np.max(np.array(vals).astype(np.float))
                            subspace_args[dims[i]] = cf.wi(val1, val2)
                        else:
                            val1 = min(vals)
                            val2 = max(vals)
                            subspace_args[dims[i]] = cf.wi(cf.dt(val1), cf.dt(val2))

                
            print('in contour plot code 1')

            plot_type = 'single point selected'
            if maxx > minx and maxy > miny:
                print('in contour plot code 1')
                plot_type = 'contour'
                con_args ={}
                if plotvars.fill and not plotvars.lines:
                    con_args['lines'] = False
                if not plotvars.fill and plotvars.lines:
                    con_args['fill'] = False
                    con_args['lines'] = True

                if plotvars.blockfill and not plotvars.lines:
                    con_args['blockfill'] = True
                    con_args['lines'] = False

                if plotvars.blockfill and plotvars.lines:
                    con_args['blockfill'] = True
                    con_args['lines'] = True

                if plotvars.lines and not plotvars.line_labels:
                    con_args['line_labels'] = False

                if plotvars.titles:
                    con_args['titles'] = True

                if plotvars.contour_type[0] == 't':
                    con_args['swap_axes'] = True 

                cfp.con(f[0, 0, miny:maxy, minx:maxx], **con_args)

            if maxx > minx and miny == maxy:
                plot_type = 'line'
                cfp.lineplot(f[0, 0, miny, minx:maxx ])

            if maxx == minx and maxy > miny:
                plot_type = 'line'
                cfp.lineplot(f[0, 0, miny:maxy, minx])
            print('plot_type is ', plot_type)

        else:
            print('\n\nError - No data selected\n\n')

        if plot_type == 'single point selected':
            print('\n\nError - Only a single point selected\n\n')




    def reset(self):
        # Reset data viewing values

        self.ndecsSlider.setValue(2)
        self.text_sizeSlider.setValue(plotvars.fontsize)
        self.datamin_colourTextBox.setText('blue')
        self.datamax_colourTextBox.setText('red')
        self.dataminTextBox.setText('')
        self.datamaxTextBox.setText('')





    def value_changed(self, text):
        # reset the table based on the text boxes and ndecs slider

        datamin = self.dataminTextBox.text()
        datamax = self.datamaxTextBox.text()
        datamin_colour = self.datamin_colourTextBox.text()
        datamax_colour = self.datamax_colourTextBox.text()

        ndecs = int(self.ndecsSlider.value())
        self.ndecsLabel.setText('Number of decimal places: ' + str(ndecs))

        model = TableModel(self.data, self.x, self.y, ndecs, datamin, datamax, datamin_colour, datamax_colour)
        self.table.setModel(model)

        custom_font = QFont(plotvars.font, int(self.text_sizeSlider.value()))
        self.table.setFont(custom_font)

        #self.table.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
        #self.table.resizeColumnsToContents()  ## super slow resizing


        font_metrics = QFontMetrics(QFont(plotvars.font, int(self.text_sizeSlider.value())))
        data = np.round(self.data, ndecs)
        if ndecs == 0:
            data = data.astype(int)
        mymin = str(np.min(data))
        mymax = str(np.max(data))
        max_len = max(len(mymin), len(mymax))
        
        text_width = font_metrics.width('a' * max_len)

        #self.table.horizontalHeader().setDefaultSectionSize(text_width * 1.4)


class Names_window(QWidget):
    '''popup window for changing data name defaults'''

    def __init__(self, cfview_parent):
        super(Names_window, self).__init__()
        self.cfview_parent = cfview_parent
        self.initUI()

    def initUI(self):

        # Set up some buttons
        saveButton = QPushButton("Save")
        saveButton.clicked.connect(self.save)

        new_nameButton = QPushButton("New name")
        new_nameButton.clicked.connect(self.new_name)

        helpButton = QPushButton("Help")
        helpButton.clicked.connect(self.help)

        quitButton = QPushButton("Quit")
        quitButton.clicked.connect(self.close)


        # Set the layout
        vbox = QVBoxLayout()

        # Set the field
        field = plotvars.fields[plotvars.index_number]
        self.field = field

        # Make a copy in self for the reset
        self.field = deepcopy(field)

        # List of all variables
        self.vardict = {}

        formLayout = QFormLayout()
        groupBox = QGroupBox('Data names')


        names = sorted(field.properties())
        for name in names:
            print('processing', name)
            val = str(field.properties()[name])
            val_label = 'field_' + name
            label = name + ':'
            setattr(self, val_label + '_Label', QLabel(label))
            setattr(self, val_label , QLineEdit())
            getattr(self, val_label).setText(val)
            getattr(self, val_label).setCursorPosition(0)
            getattr(self, val_label).textChanged.connect(partial(self.textbox_changed, val_label))
            formLayout.addRow(getattr(self, val_label + '_Label'), getattr(self, val_label))
            self.vardict["field." + name] = val 

        dims = ['X', 'Y', 'Z', 'T']
        for dim in dims:
            if field.has_construct(dim):
                 nc = field.nc_get_variable(None)
                 #names = ['standard_name', 'long_name', 'units']
                 names = sorted(field.coord(dim).properties())
                 for name in names:
                     val = getattr(field.coord(dim), name, 'not set')
                     if val != 'not set':
                         val_label = 'coord_' + dim + '_' + name
                         label = dim.lower() + '-dimension ' + name + ':'
                         setattr(self, val_label + '_Label', QLabel(label))
                         setattr(self, val_label , QLineEdit())
                         getattr(self, val_label).setText(val)
                         getattr(self, val_label).setCursorPosition(0)
                         getattr(self, val_label).textChanged.connect(partial(self.textbox_changed, val_label))
                         formLayout.addRow(getattr(self, val_label + '_Label'), getattr(self, val_label))
                         self.vardict["coord.('"+ dim + "')." + name] = val 




        print('self.vardict is ', self.vardict)

        groupBox.setLayout(formLayout)
        scroll = QScrollArea()
        scroll.setWidget(groupBox)
        scroll.setWidgetResizable(True)
        #scroll.setFixedHeight(600)
        vbox.addWidget(scroll)

 

        # The buttons
        hbox_buttons = QHBoxLayout()
        vbox.addLayout(hbox_buttons)
        hbox_buttons.addWidget(saveButton)
        hbox_buttons.addWidget(new_nameButton)
        hbox_buttons.addWidget(helpButton)
        hbox_buttons.addWidget(quitButton)
        vbox.addLayout(hbox_buttons)

        self.formLayout = formLayout
        self.names_help = None  # No external window yet.

        self.setWindowTitle('cfview data names')
        self.setLayout(vbox)
        self.new_name_window = None  # No external window yet.

        # Set theme and font
        palette = QPalette()
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        self.setPalette(palette)

        custom_font = QFont(plotvars.font, plotvars.fontsize)
        self.window().setFont(custom_font)


        self.show()



    def save(self):
        # save variable data names

        print('in save')
        print('save self.vardict is ', self.vardict)

        for var in self.vardict:
            mytype = var[:6]

            myvar = var[6:]
            # Change value to int, float if appropriate
            val = Data_check.test_type(self.vardict[var])

            if mytype == 'field.':

                myvar = var[6:]
                # Change string value to int, float if appropriate
                val = Data_check.test_type(self.vardict[var])

                if val == 'not set':
                    pass
                elif val == 'DELETE':
                    plotvars.fields[plotvars.index_number].del_property(myvar)
                else:
                    plotvars.fields[plotvars.index_number].set_property(myvar, val)



            if mytype == 'coord.':
                myvar = var[12:]
                dim = var[8]


                # Change value to int, float if appropriate
                val = Data_check.test_type(self.vardict[var])

                if val == 'not set':
                    pass
                elif val == 'DELETE':
                    plotvars.fields[plotvars.index_number].coord(dim).del_property(myvar)
                else:
                    plotvars.fields[plotvars.index_number].coord(dim).set_property(myvar, val)


        # Reset the field title
        selected = self.cfview_parent.fieldlist.selectedItems()[0]
        title = selected.text()
        new_name = Cf_funcs.field_name(plotvars.fields[plotvars.index_number])
        title_new = title.replace(title.split(' ')[-1], '') + new_name
        selected.setText(title_new)



    def new_name(self):
        print('in new_name')
        # have a pop-up for a new name 

        if self.new_name_window is None:
            self.new_name_window = New_name_window(self)
            self.new_name_window.show()
 




    def help(self):

        if self.names_help is None:

            html = '<body><h2>Data names</h2>'
            html += 'Editable names for the selected field'
            html += 'To delete a name change the name value to DELETE'

            self.names_help = Help(html)

        self.names_help.show()


    def textbox_changed(self, text):

        if text[:6] == 'coord_':
            textbox = getattr(self, text) 
            mydict ="coord.('" + text[6] + "')." + text[8:]
            self.vardict[mydict] = textbox.text()

        if text[:6] == 'field_':
            textbox = getattr(self, text) 
            mydict ="field." + text[6:]
            self.vardict[mydict] = textbox.text()


class New_name_window(QWidget):
    '''Popup window for adding a new name'''

    def __init__(self, parent):
        super(New_name_window, self).__init__()
        self.parent = parent
        self.initUI()


    def initUI(self):

        applyButton = QPushButton("Apply")
        applyButton.clicked.connect(self.apply)
        helpButton = QPushButton("Help")
        helpButton.clicked.connect(self.help)
        quitButton = QPushButton("Quit")
        quitButton.clicked.connect(self.close)

        fieldRadioButton = QRadioButton("field")
        xRadioButton = QRadioButton("x")
        yRadioButton = QRadioButton("y")
        zRadioButton = QRadioButton("z")
        tRadioButton = QRadioButton("t")
        fieldRadioButton.clicked.connect(lambda: self.button_changed('field'))
        xRadioButton.clicked.connect(lambda: self.button_changed('x'))
        yRadioButton.clicked.connect(lambda: self.button_changed('y'))
        zRadioButton.clicked.connect(lambda: self.button_changed('z'))
        tRadioButton.clicked.connect(lambda: self.button_changed('t'))
        fieldRadioButton.setChecked(True)



        nameLabel = QLabel('New name')
        nameTextbox = QLineEdit()

        valueLabel = QLabel('Value')
        valueTextbox = QLineEdit()


        vbox = QVBoxLayout()

        hbox_name = QHBoxLayout()
        hbox_name.addWidget(nameLabel)
        hbox_name.addWidget(nameTextbox)
        vbox.addLayout(hbox_name)

        hbox_value = QHBoxLayout()
        hbox_value.addWidget(valueLabel)
        hbox_value.addWidget(valueTextbox)
        vbox.addLayout(hbox_value)

        hbox_radio_buttons = QHBoxLayout()
        hbox_radio_buttons.addWidget(fieldRadioButton)
        hbox_radio_buttons.addWidget(xRadioButton)
        hbox_radio_buttons.addWidget(yRadioButton)
        hbox_radio_buttons.addWidget(zRadioButton)
        hbox_radio_buttons.addWidget(tRadioButton)
        vbox.addLayout(hbox_radio_buttons)

        hbox_buttons = QHBoxLayout()
        hbox_buttons.addWidget(applyButton)
        hbox_buttons.addWidget(helpButton)
        hbox_buttons.addWidget(quitButton)

        vbox.addLayout(hbox_buttons)

        self.setLayout(vbox)
        self.nameTextbox = nameTextbox
        self.valueTextbox = valueTextbox
        self.fieldRadioButton = fieldRadioButton
        self.xRadioButton = xRadioButton
        self.yRadioButton = yRadioButton
        self.zRadioButton = zRadioButton
        self.tRadioButton = tRadioButton


        self.new_name_help =  None  # No external window yet.

        palette = QPalette()    
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))    
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))    
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        self.setPalette(palette)

        # Set font 
        custom_font = QFont(plotvars.font, plotvars.fontsize)
        self.window().setFont(custom_font)

        self.setFixedWidth(600)

        self.show()

    def apply(self):

        name = self.nameTextbox.text()
        val = self.valueTextbox.text()

        print('self.parent.vardict is ', self.parent.vardict)

        if self.fieldRadioButton.isChecked():
            if 'field.' + name in self.parent.vardict:
                print('Error - ' + name + ' already exists in the data')
                return

            val_label = 'field_' + name
            label = name + ':'
            setattr(self.parent, val_label + '_Label', QLabel(label))
            setattr(self.parent, val_label , QLineEdit())
            getattr(self.parent, val_label).setText(val)
            getattr(self.parent, val_label).setCursorPosition(0)
            getattr(self.parent, val_label).textChanged.connect(partial(self.parent.textbox_changed, val_label))
            self.parent.formLayout.addRow(getattr(self.parent, val_label + '_Label'), getattr(self.parent, val_label))
            self.parent.vardict["field." + name] = val 
            print('self.parent.vardict is ', self.parent.vardict)

        else:
            print('dimension name selected')

            dims = ['X', 'Y', 'Z', 'T']
            if self.xRadioButton.isChecked():
                dim = 'X'
            if self.yRadioButton.isChecked():
                dim = 'Y'
            if self.zRadioButton.isChecked():
                dim = 'Z'
            if self.tRadioButton.isChecked():
                dim = 'T'


            if self.parent.field.has_construct(dim):
                myname = "coord.('" + dim + "')." + name
                if myname in self.parent.vardict:
                    print('Error - ' + myname + ' already exists in the data')
                    return

                val_label = 'coord_' + dim + '_' + name
                label = dim.lower() + '-dimension ' + name + ':'
                setattr(self.parent, val_label + '_Label', QLabel(label))
                setattr(self.parent, val_label , QLineEdit())
                getattr(self.parent, val_label).setText(val)
                getattr(self.parent, val_label).setCursorPosition(0)
                getattr(self.parent, val_label).textChanged.connect(partial(self.parent.textbox_changed, val_label))
                self.parent.formLayout.addRow(getattr(self.parent, val_label + '_Label'), getattr(self.parent, val_label))
                self.parent.vardict["coord.('"+ dim + "')." + name] = val 
            else:
                print("field doesn't have " + dim + " dimension")

        print('self.parent.vardict is ', self.parent.vardict)




    def button_changed(self, text):


        field = False
        x = False
        y = False
        z = False
        t = False
         
        if self.fieldRadioButton.isChecked():
            field = True
        if self.xRadioButton.isChecked():
            x = True
        if self.yRadioButton.isChecked():
            y = True
        if self.zRadioButton.isChecked():
            z = True
        if self.tRadioButton.isChecked():
            t = True

        self.fieldRadioButton.setChecked(field)
        self.xRadioButton.setChecked(x)
        self.yRadioButton.setChecked(y)
        self.zRadioButton.setChecked(z)
        self.tRadioButton.setChecked(t)



    def help(self):

        if self.new_name_help is None:

            html = '<body><h2>New data name</h2>'
            html += 'Editable new name for the selected field'


            self.new_name_help = Help(html)

        self.new_name_help.show()




#class Transform_window(QWidget):
class Transform_window():
    '''popup window for transforming data'''

    def __init__(self, cfview_parent):
        super(Transform_window, self).__init__()
        self.cfview_parent = cfview_parent
        self.initUI()


    def initUI(self):


        self.window = QMainWindow()
        self.mainWidget = QWidget()
        self.window.setCentralWidget(self.mainWidget)
        self.vertical_layout_main = QVBoxLayout(self.mainWidget)       
        scroll = QScrollArea()

        content_widget = QWidget()
        scroll.setWidget(content_widget)
        scroll.setWidgetResizable(True)



        # Labels
        collapseLabel = QLabel('Dimension collapse methods')
        anchorLabel = QLabel('Anchor in longitude:')
        reverse_yLabel = QLabel('Reverse Y axis:')
        interpolationLabel = QLabel('Interpolation')
        interpolation_methodLabel = QLabel('Interpolation method:')
        lonminLabel = QLabel('lonmin:')
        lonmaxLabel = QLabel('lonmax:')
        lonstepLabel = QLabel('lonstep:')
        latminLabel = QLabel('latmin:')
        latmaxLabel = QLabel('latmax:')
        latstepLabel = QLabel('latstep:')
        sourceLabel = QLabel('source field index:')
        destinationLabel = QLabel('destination field index:')
        computationLabel1 = QLabel('Field computation')
        computationLabel2 = QLabel('Type in the new field calculation, for example, to difference two fields:')
        computationLabel3 = QLabel('f[4] - f[2]')
        computationLabel4 = QLabel('field index 1 is u and field index 2 is v')
        computationLabel5 = QLabel('to get the wind magnitude in a new field:')
        computationLabel6 = QLabel('(f[1]**2 + f[2]**2) ** 0.5')

        # Text boxes
        anchorTextBox = QLineEdit()
        reverse_yTextBox = QLineEdit()
        lonminTextBox = QLineEdit()
        lonmaxTextBox = QLineEdit()
        lonstepTextBox = QLineEdit()
        latminTextBox = QLineEdit()
        latmaxTextBox = QLineEdit()
        latstepTextBox = QLineEdit()
        computationTextBox = QLineEdit()


        # Check boxes
        reverse_yCheckBox = QCheckBox("Reverse Y axis")
        reverse_yCheckBox.setChecked(False)
        interp_regularCheckBox = QCheckBox("Regular grid")
        interp_regularCheckBox.setChecked(False)
        interp_regularCheckBox.clicked.connect(lambda: self.checkbox_changed('regular'))
        interp_to_anotherCheckBox = QCheckBox("One field to another")
        interp_to_anotherCheckBox.setChecked(False)
        interp_to_anotherCheckBox.clicked.connect(lambda: self.checkbox_changed('to_another'))
        computationCheckBox = QCheckBox("New field computation")
        computationCheckBox.setChecked(False)
        computationCheckBox.clicked.connect(lambda: self.checkbox_changed('computation'))


        # Interpolation combobox
        types = ['linear', 'conservative_1st', 'conservative_2nd',\
                 'patch', 'nearest_stod', 'nearest_dtos']
        interpolation_ComboBox = QComboBox()
        for type in types:
            interpolation_ComboBox.addItem(type)


        # Source and destination comboboxes
        source_ComboBox = QComboBox()
        destination_ComboBox = QComboBox()
        for i in np.arange(len(plotvars.fields)):
            source_ComboBox.addItem(str(i))
            destination_ComboBox.addItem(str(i))


        # Buttons
        applyButton = QPushButton("Apply")
        applyButton.clicked.connect(self.apply)

        resetButton = QPushButton("Reset")
        resetButton.clicked.connect(self.reset)

        helpButton = QPushButton("Help")
        helpButton.clicked.connect(self.help)

        quitButton = QPushButton("Quit")
        quitButton.clicked.connect(self.window.close)

        self.anchorTextBox = anchorTextBox
        self.reverse_yCheckBox = reverse_yCheckBox
        self.lonminTextBox = lonminTextBox
        self.lonmaxTextBox = lonmaxTextBox
        self.lonstepTextBox = lonstepTextBox
        self.latminTextBox = latminTextBox
        self.latmaxTextBox = latmaxTextBox
        self.latstepTextBox = latstepTextBox
        self.interpolation_ComboBox = interpolation_ComboBox
        self.source_ComboBox = source_ComboBox
        self.destination_ComboBox = destination_ComboBox
        self.lonminLabel = lonminLabel
        self.lonmaxLabel = lonmaxLabel
        self.lonstepLabel = lonstepLabel
        self.latminLabel = latminLabel
        self.latmaxLabel = latmaxLabel
        self.latstepLabel = latstepLabel
        self.sourceLabel = sourceLabel
        self.destinationLabel = destinationLabel
        self.computationTextBox = computationTextBox
        self.interp_regularCheckBox = interp_regularCheckBox
        self.interp_to_anotherCheckBox = interp_to_anotherCheckBox
        self.source_ComboBox = source_ComboBox
        self.destination_ComboBox = destination_ComboBox

        # Set the layout

        vbox = QVBoxLayout(content_widget)

        vbox.addWidget(collapseLabel)

        hbox_area_collapse = QHBoxLayout()
        hbox_area_collapse.addWidget(self.cfview_parent.collapse_areaLabel)
        hbox_area_collapse.addWidget(self.cfview_parent.collapse_areaComboBox)
        vbox.addLayout(hbox_area_collapse)

        hbox_x_collapse = QHBoxLayout()
        hbox_x_collapse.addWidget(self.cfview_parent.collapse_xLabel)
        hbox_x_collapse.addWidget(self.cfview_parent.collapse_xComboBox)
        vbox.addLayout(hbox_x_collapse)

        hbox_y_collapse = QHBoxLayout()
        hbox_y_collapse.addWidget(self.cfview_parent.collapse_yLabel)
        hbox_y_collapse.addWidget(self.cfview_parent.collapse_yComboBox)
        vbox.addLayout(hbox_y_collapse)

        hbox_z_collapse = QHBoxLayout()
        hbox_z_collapse.addWidget(self.cfview_parent.collapse_zLabel)
        hbox_z_collapse.addWidget(self.cfview_parent.collapse_zComboBox)
        vbox.addLayout(hbox_z_collapse)

        hbox_t_collapse = QHBoxLayout()
        hbox_t_collapse.addWidget(self.cfview_parent.collapse_tLabel)
        hbox_t_collapse.addWidget(self.cfview_parent.collapse_tComboBox)
        vbox.addLayout(hbox_t_collapse)
        vbox.addWidget(HLine())

        # Anchor box
        hbox_anchor = QHBoxLayout()
        hbox_anchor.addWidget(anchorLabel)
        hbox_anchor.addWidget(anchorTextBox)
        vbox.addLayout(hbox_anchor)
        vbox.addWidget(HLine())

        # Reverse y
        vbox.addWidget(reverse_yCheckBox)
        vbox.addWidget(HLine())

        # Interpolation boxes
        vbox.addWidget(interpolationLabel)
        hbox_interp = QHBoxLayout()
        hbox_interp.addWidget(interpolation_methodLabel)
        hbox_interp.addWidget(interpolation_ComboBox)
        vbox.addLayout(hbox_interp)
        vbox.addWidget(interp_regularCheckBox)
        hbox_lons = QHBoxLayout()
        hbox_lons.addWidget(lonminLabel)
        hbox_lons.addWidget(lonminTextBox)
        hbox_lons.addWidget(lonmaxLabel)
        hbox_lons.addWidget(lonmaxTextBox)
        hbox_lons.addWidget(lonstepLabel)
        hbox_lons.addWidget(lonstepTextBox)
        vbox.addLayout(hbox_lons)

        hbox_lats = QHBoxLayout()
        hbox_lats.addWidget(latminLabel)
        hbox_lats.addWidget(latminTextBox)
        hbox_lats.addWidget(latmaxLabel)
        hbox_lats.addWidget(latmaxTextBox)
        hbox_lats.addWidget(latstepLabel)
        hbox_lats.addWidget(latstepTextBox)
        vbox.addLayout(hbox_lats)

        vbox.addWidget(interp_to_anotherCheckBox)
        hbox_interp_to_another = QHBoxLayout()
        hbox_interp_to_another.addWidget(sourceLabel)
        hbox_interp_to_another.addWidget(source_ComboBox)
        hbox_interp_to_another.addWidget(destinationLabel)
        hbox_interp_to_another.addWidget(destination_ComboBox)
        hbox_interp_to_another.addStretch(1)
        vbox.addLayout(hbox_interp_to_another)
        vbox.addWidget(HLine())

        vbox.addWidget(computationLabel1)
        vbox.addWidget(computationLabel2)
        vbox.addWidget(computationLabel3)
        vbox.addWidget(computationLabel4)
        vbox.addWidget(computationLabel5)
        vbox.addWidget(computationLabel6)

        vbox.addWidget(computationTextBox)

        hbox_buttons = QHBoxLayout()
        hbox_buttons.addWidget(applyButton)
        hbox_buttons.addWidget(resetButton)
        hbox_buttons.addWidget(helpButton)
        hbox_buttons.addWidget(quitButton)
        vbox.addLayout(hbox_buttons)

        self.transform_help = None  # No external window yet.

        self.window.setWindowTitle('cfview transform settings')



        # Set theme and font
        palette = QPalette()
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        self.window.setPalette(palette)

        custom_font = QFont(plotvars.font, plotvars.fontsize)
        self.window.setFont(custom_font)

        self.interp_regular('Off')
        self.interp_one_to_another('Off')

        self.vertical_layout_main.addWidget(scroll)
        self.window.show()



    def interp_regular(self, text):
        # Turn sensitvity of interpolation boxes on and off

        objs = [self.lonminTextBox, self.lonmaxTextBox, self.lonstepTextBox, \
                self.latminTextBox, self.latmaxTextBox, self.latstepTextBox, \
                self.lonminLabel, self.lonmaxLabel, self.lonstepLabel, \
                self.latminLabel, self.latmaxLabel, self.latstepLabel]

        if text == 'Off':
            flags = [False] * 12
        else:
            flags = [True] * 12

        for i in np.arange(len(objs)):
            obj = objs[i]
            color = plotvars.text_colour_insensitive
            if flags[i]:
                color = plotvars.text_colour
            obj.setEnabled(flags[i])
            pal = QPalette(obj.palette())
            pal.setColor(QPalette.WindowText, QColor(color))
            obj.setPalette(pal)


    def interp_one_to_another(self, text):
        # Turn sensitvity of interpolation boxes on and off

        objs = [self.source_ComboBox, self.destination_ComboBox, \
                self.sourceLabel, self.destinationLabel]

        if text == 'Off':
            flags = [False] * 4
        else:
            flags = [True] * 4

        for i in np.arange(len(objs)):
            obj = objs[i]
            color = plotvars.text_colour_insensitive
            if flags[i]:
                color = plotvars.text_colour
            obj.setEnabled(flags[i])
            pal = QPalette(obj.palette())
            pal.setColor(QPalette.WindowText, QColor(color))
            obj.setPalette(pal)



    def checkbox_changed(self, text):
 
        if text == 'regular':
            if self.interp_regularCheckBox.isChecked():
                self.interp_to_anotherCheckBox.setChecked(False)
                self.interp_regular('On')
                self.interp_one_to_another('Off')
            else:
                self.interp_regular('Off')


        if text == 'to_another':
            if self.interp_to_anotherCheckBox.isChecked():
                self.interp_regularCheckBox.setChecked(False)
                self.interp_regular('Off')
                self.interp_one_to_another('On')
            else:
                self.interp_one_to_another('Off')



    def apply(self):

        com_interp = 'import cf\n'
        com_interp += "f = cf.read('" + plotvars.file_selected 
        com_interp += "')[" + str(plotvars.index_number) + "]\n"
        com_okay = True

        if self.anchorTextBox.text() != '':

            # Make a copy of the field
            f = deepcopy(plotvars.fields[plotvars.index_number])

            # Check data has an X dimension
            if f.has_construct('X'):
                if f.iscyclic('X') is False:
                    f.cyclic('X', period=360)
                    com_interp += "f.cyclic('X', period=360)\n"
                f = f.anchor('X', float(self.anchorTextBox.text()))
                com_interp += "f.anchor('X', " + str(float(self.anchorTextBox.text())) + ")\n"
                plotvars.fields[plotvars.index_number] = f
                self.cfview_parent.fieldnumber()
            else:
                print('Cannot anchor as X does not exist')
                com_okay = False


        if self.reverse_yCheckBox.isChecked():

            # Make a copy of the field
            f = deepcopy(plotvars.fields[plotvars.index_number])

            if f.has_construct('Y'):
                f = f.flip('Y')
                com_interp += "f = f.flip('Y')\n"
                plotvars.fields[plotvars.index_number] = f
                self.cfview_parent.fieldnumber()
            else:
                print('Y axis not present so reverse not possible')
                com_okay = False


        method = str(self.interpolation_ComboBox.currentText())


        if self.interp_regularCheckBox.isChecked() or self.interp_to_anotherCheckBox.isChecked():
            # Check ESMF is installed
            try:
                import ESMF
            except:
                print('Interpolation package esmpy needs to be installed:')
                print('conda install -c conda-forge mpich esmpy')
                return

            # Check data has X and Y coords
            f = deepcopy(plotvars.fields[plotvars.index_number])
            data_okay = True
            data_error = 'Data error\n'
            if f.has_construct('X') is False:
                data_okay = False
                data_error += 'missing X coordinate\n'

            if f.has_construct('Y') is False:
                data_okay = False
                data_error += 'missing Y coordinate\n'

            if data_okay is False:
                print(data_error)
                return


            # If method is not linear check and add bounds if necessary
            if method != 'linear':
                if f.construct('X').has_bounds() is False:
                    f.construct('X').set_bounds(f.construct('X').create_bounds())
                    com_interp += "\n# Create longitude bounds\n"
                    com_interp += "f.construct('X').set_bounds(f.construct('X').create_bounds())\n"

                if f.construct('Y').has_bounds() is False:
                    f.construct('Y').set_bounds(f.construct('Y').create_bounds(min=-90, max=90))
                    com_interp += "\n# Create latitude bounds\n"
                    com_interp += "f.construct('Y').set_bounds(f.construct('Y')"
                    com_interp += ".create_bounds(min=-90, max=90))\n"

            # Regular user supplied grid
            if self.interp_regularCheckBox.isChecked():
                # Extract values from the interface
                lonmin = float(self.lonminTextBox.text())
                lonmax = float(self.lonmaxTextBox.text())
                lonstep = float(self.lonstepTextBox.text()) 
                lonmax = lonmax + lonstep
                latmin = float(self.latminTextBox.text())
                latmax = float(self.latmaxTextBox.text())
                latstep = float(self.latstepTextBox.text())
                latmax = latmax + latstep

                # Form the destination longitude coordinate
                lons = cf.DimensionCoordinate(data=cf.Data(np.arange(lonmin, lonmax, lonstep), 'degrees_east'))
                lons.standard_name = 'longitude'
                lon_bounds = lons.create_bounds()
                lons.set_bounds(lon_bounds)

                com_interp += '\nimport numpy as np\n'
                com_interp += "\nlons = cf.DimensionCoordinate(data=cf.Data(np.arange(" + str(lonmin) +", "
                com_interp += str(lonmax) + ", " + str(lonstep) + "), 'degrees_east'))\n"
                com_interp += "lons.standard_name = 'longitude'\n"
                com_interp += "lon_bounds = lons.create_bounds()\n"
                com_interp += "lons.set_bounds(lon_bounds)\n"
                com_interp += "lons.cyclic('X'\n"

                # Form the latitude destination coordinate
                lats = cf.DimensionCoordinate(data=cf.Data(np.arange(latmin, latmax, latstep), 'degrees_north'))
                lats.standard_name = 'latitude'
                lat_bounds = lats.create_bounds(min=-90, max=90)
                lats.set_bounds(lat_bounds)

                com_interp += "\nlats = cf.DimensionCoordinate(data=cf.Data(np.arange(" + str(latmin) +", "
                com_interp += str(latmax) + ", " + str(latstep) + "), 'degrees_north'))\n"
                com_interp += "lats.standard_name = 'latitude'\n"
                com_interp += "lat_bounds = lats.create_bounds(min=-90, max=90)\n"
                com_interp += "lats.set_bounds(lat_bounds)\n"


                # Regrid data
                g = f.regrids({'longitude': lons, 'latitude': lats}, method=method)
                com_interp += "g = f.regrids({'longitude': lons, 'latitude': lats}, method='" + method + "')\n"
                print(com_interp)

                # Set longitudes to be cyclic
                g.cyclic('X')
                com_interp += "g.cyclic('X')\n"

                plotvars.fields[plotvars.index_number] = g
                self.cfview_parent.fieldnumber()


            # Regular user supplied grid
            if self.interp_to_anotherCheckBox.isChecked():
                print('regridding one to another')
                f = deepcopy(plotvars.fields)

                source = f[self.source_ComboBox.currentIndex()]
                destination = f[self.destination_ComboBox.currentIndex()]

                g =  source.regrids(destination, method=method)
                print(g)

                next = len(plotvars.stored_dimensions)

                field_widget_names, field_widget_title = Cf_funcs.fields_list(fields=[g], order=plotvars.field_widget_listing)
                title = field_widget_names[0]
                title = str(next) + (6 - len(str(next))) * ' ' + title[6:]
                print('new title is ', title)

                QListWidgetItem(title, self.cfview_parent.fieldlist) 
                plotvars.stored_dimensions['f' + str(next)] = {'x': -1, 'y': -1, 'z': -1, 't': -1}
                plotvars.stored_collapses['f' + str(next)] = {'x': 'Off', 'y': 'Off', 'z': 'Off', 't': 'Off'}
                plotvars.stored_collapse_values['f' + str(next)] = {'x': False, 'y': False, 'z': False, 't': False}
                plotvars.fields.append(g)



        if self.computationTextBox.text() != '':

            computation = self.computationTextBox.text()
            print('computation is', computation)

            # Check for valid characters otherwise reject
            valid = 'f0123456789.()[]+-*/ '


            okay = True
            invalid_str = ''
            for char in computation:
                if char not in valid:
                    okay = False 
                    invalid_str += char

            f = deepcopy(plotvars.fields)

            if okay:
                g = eval(computation)

                next = len(plotvars.stored_dimensions)
                field_widget_names, field_widget_title = Cf_funcs.fields_list(fields=[g], order=plotvars.field_widget_listing)
                title = field_widget_names[0]
                title = str(next) + (6 - len(str(next))) * ' ' + title[6:]
                print('new title is ', title)

                QListWidgetItem(title, self.cfview_parent.fieldlist) 
                plotvars.stored_dimensions['f' + str(next)] = {'x': -1, 'y': -1, 'z': -1, 't': -1}
                plotvars.stored_collapses['f' + str(next)] = {'x': 'Off', 'y': 'Off', 'z': 'Off', 't': 'Off'}
                plotvars.stored_collapse_values['f' + str(next)] = {'x': False, 'y': False, 'z': False, 't': False}
                plotvars.fields.append(g)

                com_interp = 'import cf\n'
                com_interp += "f = cf.read('" + plotvars.file_selected + "')\n"
                com_interp += "g = " + computation + "\n"
            else:
                print('Field computation code is restricted to the characters ' + valid)
                print('Found an invalid character in the input ',  invalid_str)
                return



        if com_okay: 
            print('Transform code is ', com_interp)



            




    def reset(self):
        # Reset widget values
        self.lonminTextBox.setText('')
        self.lonmaxTextBox.setText('')
        self.lonstepTextBox.setText('')
        self.latminTextBox.setText('')
        self.latmaxTextBox.setText('')
        self.latstepTextBox.setText('')
        self.anchorTextBox.setText('')
        self.reverse_yCheckBox.setChecked(False)
        self.interpolation_ComboBox.setCurrentIndex(0)
        self.interp_regular('Off')
        self.interp_one_to_another('Off')
        self.source_ComboBox.setCurrentIndex(0)
        self.destination_ComboBox.setCurrentIndex(0)
        self.interp_regularCheckBox.setChecked(False)
        self.interp_to_anotherCheckBox.setChecked(False)
        self.cfview_parent.collapse_areaComboBox.setCurrentIndex(0)
        self.cfview_parent.collapse_xComboBox.setEnabled(True)
        self.cfview_parent.collapse_yComboBox.setEnabled(True)
        self.cfview_parent.collapse_areaComboBox.setCurrentIndex(0)
        self.cfview_parent.collapse_xComboBox.setCurrentIndex(0)
        self.cfview_parent.collapse_yComboBox.setCurrentIndex(0)
        self.cfview_parent.collapse_zComboBox.setCurrentIndex(0)
        self.cfview_parent.collapse_tComboBox.setCurrentIndex(0)
        color = plotvars.text_colour
        pal = QPalette(self.cfview_parent.collapse_xLabel.palette())
        pal.setColor(QPalette.WindowText, QColor(color))
        self.cfview_parent.collapse_xLabel.setPalette(pal)
        self.cfview_parent.collapse_yLabel.setPalette(pal)
        

        # reset the plotvars collapse settings
        plotvars.collapse_x = 'Off'
        plotvars.collapse_y = 'Off'
        plotvars.collapse_z = 'Off'
        plotvars.collapse_t = 'Off'
        dims_small = ['x', 'y', 'z', 't']
        field_var = 'f' + str(plotvars.index_number)
        for i in np.arange(4):
            plotvars.stored_collapses[field_var][dims_small[i]] = 'Off'
            plotvars.stored_collapse_values[field_var][dims_small[i]] = False

        # Switch back to the appropriate dimension view
        if self.cfview_parent.xRadioButton.isChecked():  
            self.cfview_parent.xlist_collapse.setVisible(False)
            self.cfview_parent.xlist.setVisible(True)
        if self.cfview_parent.yRadioButton.isChecked():  
            self.cfview_parent.ylist_collapse.setVisible(False)
            self.cfview_parent.ylist.setVisible(True)
        if self.cfview_parent.zRadioButton.isChecked():  
            self.cfview_parent.zlist_collapse.setVisible(False)
            self.cfview_parent.zlist.setVisible(True)
        if self.cfview_parent.tRadioButton.isChecked():  
            self.cfview_parent.tlist_collapse.setVisible(False)
            self.cfview_parent.tlist.setVisible(True)


        # Reset the field
        f = cf.read(plotvars.file_selected)[plotvars.index_number]
        plotvars.fields[plotvars.index_number] = f
        self.cfview_parent.fieldnumber()


    def help(self):

        if self.transform_help is None:

            html = '<body><h2>Transform help</h2>'
            html += '<h3>Collapse options</h3>'
            html += 'Collapse the field along a dimension with one of the following methods: <br>' 
            html += 'mean, minimumn maximum, variance, standard deviation'

            html += '<h3>Anchor in longitude</h3>'
            html += 'If a longitude axis exists roll the axis so that the given value lies in the first coordinate cell.'
            html += 'If the data not cyclic it will be made so'

            html += '<h3>Reverse the Y axis</h3>'
            html += 'Reverse the Y axis can be used to flip the Y axis values in cases where the data starts at the north pole.'
            html += 'Either direction is plotted corrrectly in cf-plot.'

            html += '<h3>Interpolation options</h3>'
            html += '<b>linear</b> Bilinear interpolation<br>'
            html += '<b>conservative_1st</b> First order conservative interpolation.<br>'
            html += '<b>conservative_2nd</b> Second-order conservative interpolation.<br>'
            html += '<b>patch</b> Higher-order patch recovery interpolation.<br>'
            html += '<b>nearest_stod</b> Nearest neighbour interpolation for which each destination point is mapped to the closest source point. '
            html += 'Useful for extrapolation of categorical data.<br>'
            html += '<b>nearest_dtos</b> Nearest neighbour interpolation for which each source point is mapped to the destination point. '
            html += 'Useful for extrapolation of categorical data.<br>'
            html += 'Further information at https://ncas-cms.github.io/cf-python/method/cf.Field.regrids.html?highlight=regrids#cf.Field.regrids'
            html += '<p>'

            html += '<h3>Regular grid interpolation</h3>'  
            html += 'Fill in the longitude and latitude minimum, maximum and step to calculate a regridded field.<p>'

            html += '<h3>Regrid from one field to another</h3>'  
            html += 'Select the source and destination field indicies to regrid one field to another.<p>'

            html += '<h3>Field computation</h3>'  
            html += 'Type in the new field calculation, for example:<p>'
            html += 'difference two fields:<br>' 
            html += 'f[4] - f[2]<p>'
            html += 'field index 1 is u and field index 2 is v<br>'
            html += 'to get the wind magnitude in a new field:<br>'
            html += '(f[1]**2 + f[2]**2) ** 0.5'

          

            self.transform_help = Help(html)

        self.transform_help.show()




class Data_check():

    def __init__(self):
        pass
        
    def test_type(val):  
        # Test if input string is a string, integer or float
        # Need to match the data to the value

        try:
            a = float(val)
            if int(val)/val == 1:
                return int(val)
            if abs(val) > 1:
                if val/int(val) > 1:
                    if plotvars.fields[plotvars.index_number].dtype == 'float32':
                        return np.float32(val)
                    if plotvars.fields[plotvars.index_number].dtype == 'float64':
                        return np.float64(val)

            else:
                return val
        except ValueError:
            return str(val)

    def test_numbers(vals):  
        # Check inputs are numbers
        vals_okay = True
        errstr = ''
        for val in vals:
            try:
                float(val)
            except:
                vals_okay = False
                errstr += str(val) + ' is not a number\n'
        return vals_okay, errstr

    def test_integers(vals):  
        # Check if all values are integers
        vals_okay = True
        errstr = ''
        for val in vals:
            val_check = val
            if val_check[0] == '-':
                val_check = val_check[1:]
            if not val_check.isdigit():
                vals_okay = False
                errstr += str(val) + ' is not an integer\n'
        return vals_okay, errstr

    def test_ascending(vals):  
        # Check inputs are ascending
        vals_okay = True
        errstr = ''
        for j in np.arange(np.size(vals) - 1):
            if float(vals[j+1]) <= float(vals[j]):
                vals_okay = False
                errstr += 'inputs are not ascending\n'
        return vals_okay, errstr

    def test_val0_lt_val1(vals):  
        # Check min < max
        vals_okay = True
        errstr = ''
        if float(vals[0]) >= float(vals[1]):
            vals_okay = False
            errstr += 'minimum must be less than the maximum\n'
        return vals_okay, errstr

    def test_val_gt_zero(val):  
        # Check step > 0
        vals_okay = True
        errstr = ''
        if float(val) <= 0:
            vals_okay = False
            errstr += 'step must be greater than zero\n'
        return vals_okay, errstr



class Cf_funcs():

    def __init__(self):
        pass


    def field_name(field=None):
        '''Work out the field name'''

        name = 'No'
        if field is None:
            return name
        nc = field.nc_get_variable(None)
        if nc:
            name = field.nc_get_variable()
        if hasattr(field, 'short_name'):
            name = field.short_name
        if hasattr(field, 'long_name'):
            name = field.long_name
        if hasattr(field, 'standard_name'):
            name = field.standard_name
        return name



    def field_dims(field=None):
        '''Work out the field dimensions on the original field'''

        x = None
        y = None
        z = None
        t = None

        # Extract coordinate data if a matching CF standard_name or axis is found
        for mydim in list(field.dimension_coordinates()):
            sn = getattr(field.construct(mydim), 'standard_name', 'NoName')
            an = field.construct(mydim).get_property('axis', 'NoName')

            standard_name_x = ['longitude']
            if (sn in standard_name_x or an == 'X'):
                x = field.construct(mydim).array

            standard_name_y = ['latitude']
            if (sn in standard_name_y or an == 'Y'):
                y = field.construct(mydim).array

            standard_name_z = ['pressure', 'air_pressure', 'height', 'depth']
            if (sn in standard_name_z or an == 'Z'):
                z = field.construct(mydim).array

            standard_name_t = ['time']
            if (sn in standard_name_t or an == 'T'):
                t = field.construct(mydim).dtarray

        # CF defined units
        lon_units = ['degrees_east', 'degree_east', 'degree_E',
                     'degrees_E', 'degreeE', 'degreesE']
        lat_units = ['degrees_north', 'degree_north', 'degree_N',
                     'degrees_N', 'degreeN', 'degreesN']

        height_units = ['mb', 'mbar', 'millibar', 'decibar', 'atmosphere',
                        'atm', 'pascal', 'Pa', 'hPa']

        time_units = ['day', 'days', 'd', 'hour', 'hours', 'hr', 'h', 'minute',
                      'minutes', 'min', 'mins', 'second', 'seconds', 'sec',
                      'secs', 's']

        # Extract coordinate data if a matching CF set of units is found
        for mydim in list(field.dimension_coordinates()):
            units = getattr(field.construct(mydim), 'units', False)
            if units in lon_units:
                if x is None:
                    x = field.construct(mydim).array
            if units in lat_units:
                if y is None:
                    y = field.construct(mydim).array
            if units in height_units:
                if z is None:
                    z = field.construct(mydim).array
            if units in time_units:
                if t is None:
                    t = field.construct(mydim).dtarray

        # Extract coordinate data from variable name if not already assigned
        for mydim in list(field.dimension_coordinates()):
            name = Cf_funcs.cf_var_name(field=field, dim=mydim)[0]

            #print('name is ', name)

            if name[0:3] == 'lon':
                if x is None:
                    x = field.construct(mydim).array

            if name[0:3] == 'lat':
                if y is None:
                    y = field.construct(mydim).array

            if (name[0:5] == 'theta' or name == 'p' or name == 'air_pressure'):
                if z is None:
                    z = field.construct(mydim).array

            if name[0:1] == 't':
                if t is None:
                    t = field.construct(mydim).dtarray

        # Assign 0 to all dimensions with no data
        if x is None:
            nx = 0
            x = []
        else:
            nx = np.size(x)

        if y is None:
            ny = 0
            y =[]
        else:
            ny = np.size(y)

        if z is None:
            nz = 0
            z = []
        else:
            nz = np.size(z)

        if t is None:
            nt = 0
            t =[]
        else:
            nt = np.size(t)


        return (nx, ny, nz, nt, x, y, z, t)


    def cf_var_name(field=None, dim=None):
        """
         | cf_var_name - return the name from a supplied dimension
         |               in the following order
         |               ncvar
         |               short_name
         |               long_name
         |               standard_name
         |
         | field=None - field
         | dim=None - dimension required - 'dim0', 'dim1' etc.
         |
         :Returns:
          name
        """

        id = getattr(field.construct(dim), 'id', False)
        ncvar = field.construct(dim).nc_get_variable(False)
        short_name = getattr(field.construct(dim), 'short_name', False)
        long_name = getattr(field.construct(dim), 'long_name', False)
        standard_name = getattr(field.construct(dim), 'standard_name', False)

        name = 'No Name'
        if id:
            name = id
        if ncvar:
            name = ncvar
        if short_name:
            name = short_name
        if long_name:
            name = long_name
        if standard_name:
            name = standard_name

        units = getattr(field.construct(dim), 'units', '()')
        if units[0] != '(':
            units = '(' + units + ')'
        return name, units



    def fields_list(fields=None, order=None, search=False, order_changed=False):
        """
         | fields_list - return the field list for populating the field list widget
         |               
         | fields = None - list of fields to examine
         | order = 'index' or 'field' - order the fields by supplied parameter
         | search = False - return named search
         | order_changed = False - order of the fields has changed.  Use the stored 
         |                 fields_list rather than recalculating.
         |
         :Returns:
          widget_names
        """


        if order_changed:
            field_widget_names = plotvars.field_widget_names
            field_widget_title = plotvars.field_widget_title
        else:
            names_list = []
            index_list = []
            nx_list = []
            ny_list = []
            nz_list = []
            nt_list = []
            field_widget_names = []
    
            # Assemble field information
            for i in np.arange(len(fields)):
                field = fields[i]
                name = Cf_funcs.field_name(field)
                nx, ny, nz, nt, x, y, z, t = Cf_funcs.field_dims(field=field)

                nx_list.append(str(nx))
                ny_list.append(str(ny))
                nz_list.append(str(nz))
                nt_list.append(str(nt))
                names_list.append(name)
                index_list.append(str(i))

            # Work out the maximum lengths of the dimensions
            nx_length = len(max(nx_list, key=len))
            ny_length = len(max(ny_list, key=len))
            nz_length = len(max(nz_list, key=len))
            nt_length = len(max(nt_list, key=len))
            index_length = len(max(index_list, key=len))

            nx_length = max(nx_length, 2)
            ny_length = max(ny_length, 2)
            nz_length = max(nz_length, 2)
            nt_length = max(nt_length, 2)

            # Save the lengths into plotvars so they can be used when changing the dimensions
            plotvars.index_length = index_length
            plotvars.nx_length = nx_length
            plotvars.ny_length = ny_length
            plotvars.nz_length = nz_length
            plotvars.nt_length = nt_length

            # Work out the widget title
            field_widget_title ='index '
            field_widget_title += 'nx' + (nx_length - 1) * ' '
            field_widget_title += 'ny' + (ny_length - 1) * ' '
            field_widget_title += 'nz' + (nz_length - 1) * ' '
            field_widget_title += 'nt' + (nt_length - 1) * ' '
            field_widget_title += 'field name'

            # Work out the widget names
            for i in np.arange(len(fields)):
                field_widget_name = index_list[i] + (6 -len(index_list[i])) * ' '
                field_widget_name += nx_list[i] + (nx_length + 1 - len(nx_list[i])) * ' '
                field_widget_name += ny_list[i] + (ny_length + 1 - len(ny_list[i])) * ' '
                field_widget_name += nz_list[i] + (nz_length + 1 - len(nz_list[i])) * ' '
                field_widget_name += nt_list[i] + (nt_length + 1 - len(nt_list[i])) * ' '
                field_widget_name += names_list[i]
                field_widget_names.append(field_widget_name)

        plotvars.field_widget_names = field_widget_names


        if order == 'index':
            plotvars.field_widget_indicies = np.arange(len(field_widget_names))


        if order == 'field':
            # Split widget_name string into a list, remove empty strings and create 
            # a numpy ordered list
            names = []
            for i in np.arange(len(field_widget_names)):
                name_long = field_widget_names[i].split(' ')
                name_field = [x for x in name_long if x != ''][5]
                names.append(name_field)

            ordered_indicies = np.argsort(names)

            plotvars.field_widget_indicies = ordered_indicies
            field_widget_names_ordered = []
            for i in np.arange(len(field_widget_names)):
                field_widget_names_ordered.append(field_widget_names[ordered_indicies[i]])
 
            field_widget_names = field_widget_names_ordered



        if search:
            widget_names_searched = []
            ordered_indicies = []
            names = []
            for i in np.arange(len(field_widget_names)):
                name_long = field_widget_names[i].split(' ')
                name_field = [x for x in name_long if x != ''][5]
                if search in name_field:
                    widget_names_searched.append(field_widget_names[i])
                    ordered_indicies.append(i)

            plotvars.field_widget_indicies = ordered_indicies
            field_widget_names = widget_names_searched
                


        plotvars.field_widget_title = field_widget_title
        return field_widget_names, field_widget_title
    

    def selected_dims(cfview_parent):
        # Return the selected length of the data in the axes
        #self.cfview_parent = cfview_parent

        nx = len(cfview_parent.xlist.selectedItems())
        ny = len(cfview_parent.ylist.selectedItems())
        nz = len(cfview_parent.zlist.selectedItems())
        nt = len(cfview_parent.tlist.selectedItems())

        if plotvars.collapse_x != 'Off':
            nx = 1
        if plotvars.collapse_y != 'Off':
            ny = 1
        if plotvars.collapse_z != 'Off':
            nz = 1
        if plotvars.collapse_t != 'Off':
            nt = 1

        return nx, ny, nz, nt


    def selected_dims2(index):
        # Return the selected length of the data in the axes

        # Extract the dimensions and collapses for this field
        dims = plotvars.stored_dimensions['f' + str(index)]
        collapses = plotvars.stored_collapses['f' + str(index)] 

        f = plotvars.fields[index]
        print('f is', f)
        
        # Work out the selected points for the dimensions
        if dims['x'] == -1:
            nx = len(f.coord('X').array)
        else:
            nx = max(dims['x']) - min(dims['x']) + 1
            
        if dims['y'] == -1:
            ny = len(f.coord('Y').array)
        else:
            ny = max(dims['y']) - min(dims['y']) + 1

        if dims['z'] == -1:
            nz = len(f.coord('Z').array)
        else:
            nz = max(dims['z']) - min(dims['z']) + 1

        if dims['t'] == -1:
            nt = len(f.coord('T').array)
        else:
            nt = max(dims['t']) - min(dims['t']) + 1

        # If a collapse method is applied set the counter to 1
        if collapses['x'] != 'Off':
            nx = 1

        if collapses['y'] != 'Off':
            ny = 1

        if collapses['z'] != 'Off':
            nz = 1

        if collapses['z'] != 'Off':
            nz = 1

        return nx, ny, nz, nt





    def subspace_args(cfview_parent):

        subspace_args = {}

        f = deepcopy(plotvars.fields[plotvars.index_number])
        nx, ny, nz, nt, x, y, z, t = Cf_funcs.field_dims(f)
        dim_sizes = [nx, ny, nz, nt]
        dims = ['X', 'Y', 'Z', 'T']

        lists = [cfview_parent.xlist.selectedItems(), cfview_parent.ylist.selectedItems(),\
                 cfview_parent.zlist.selectedItems(), cfview_parent.tlist.selectedItems()]

        collapses = [plotvars.collapse_x, plotvars.collapse_y,\
                     plotvars.collapse_z, plotvars.collapse_t]

        for i in np.arange(4):
            vals = []
            for j in np.arange(len(lists[i])):
                vals.append(str(lists[i][j].text()))


            if plotvars.plot_type == 'Contour':
                if any(dim == dims[i].lower() for dim in plotvars.contour_type):
                    pass
                else:
                    if collapses[i] == 'Off':
                        if dim_sizes[i] > 1:
                            vals = [vals[0]]

            if plotvars.plot_type == 'Line':
                mydim = str(cfview_parent.line_type_ComboBox.currentText())
                print('subspace_args - mydim is ', mydim)
                if any(dim == dims[i].lower() for dim in [mydim]):
                    pass
                else:
                    if collapses[i] == 'Off':
                        if dim_sizes[i] > 1:
                            vals = [vals[0]]



            if len(vals) != dim_sizes[i]:
                if len(vals) == 1:

                    if collapses[i] == 'Off':
                        if dims[i] != 'T':
                            subspace_args[dims[i]] = float(vals[0])
                        else:
                            subspace_args[dims[i]] = cf.dt(vals[0])
                else:
                    if dims[i] != 'T':
                        # cf.wi needs to go from min to max but the widget return
                        # goes in order of selection
                        val1 = np.min(np.array(vals).astype(np.float64))
                        val2 = np.max(np.array(vals).astype(np.float64))
                        subspace_args[dims[i]] = cf.wi(val1, val2)
                    else:
                        val1 = min(vals)
                        val2 = max(vals)
                        subspace_args[dims[i]] = cf.wi(cf.dt(val1), cf.dt(val2))

        return subspace_args


    def subspace_args2(index):

        subspace_args = {}

        f = deepcopy(plotvars.fields[index])
        nx, ny, nz, nt, x, y, z, t = Cf_funcs.field_dims(f)
        dim_sizes = [nx, ny, nz, nt]
        dims = ['X', 'Y', 'Z', 'T']

        # Extract the dimensions and collapses for this field
        dim_vals = plotvars.stored_dimensions['f' + str(index)]
        collapses = plotvars.stored_collapses['f' + str(index)] 

        print('dim_vals are ', dim_vals)
        print('collapses are', collapses)

        #lists = [cfview_parent.xlist.selectedItems(), cfview_parent.ylist.selectedItems(),\
        #         cfview_parent.zlist.selectedItems(), cfview_parent.tlist.selectedItems()]

        #collapses = [plotvars.collapse_x, plotvars.collapse_y,\
        #             plotvars.collapse_z, plotvars.collapse_t]

        for i in np.arange(4):
            vals = []

            # Select all indicies if stored value is -1
            dim_indicies = dim_vals[dims[i].lower()]
            if dim_indicies == -1:
                dim_indicies = np.arange(dim_sizes[i])

            # Order the dim indicies
            dim_indicies.sort()

            
            for j in np.arange(len(dim_indicies)):
                if i <= 2:
                    val = f.coord(dims[i]).array[dim_indicies[j]]
                else:
                    val = f.coord(dims[i]).dtarray[dim_indicies[j]]
                vals.append(str(val))

            print('i and vals are ', i, vals)






            if plotvars.plot_type in ['Contour', 'Vector', 'Contour and Vector'] :
                if any(dim == dims[i].lower() for dim in plotvars.contour_type):
                    pass
                else:
                    if collapses[dims[i].lower()] == 'Off':
                        if dim_sizes[i] > 1:
                            vals = [vals[0]]

            if plotvars.plot_type == 'Line':
                mydim = str(cfview_parent.line_type_ComboBox.currentText())
                print('subspace_args - mydim is ', mydim)
                if any(dim == dims[i].lower() for dim in [mydim]):
                    pass
                else:
                    if collapses[dims[i].lower()] == 'Off':
                        if dim_sizes[i] > 1:
                            vals = [vals[0]]


            if len(vals) != dim_sizes[i]:
                if len(vals) == 1:

                    if collapses[dims[i].lower()] == 'Off':
                        if dims[i] != 'T':
                            subspace_args[dims[i]] = float(vals[0])
                        else:
                            subspace_args[dims[i]] = cf.dt(vals[0])
                else:
                    if dims[i] != 'T':
                        # cf.wi needs to go from min to max but the widget return
                        # goes in order of selection
                        val1 = np.min(np.array(vals).astype(np.float64))
                        val2 = np.max(np.array(vals).astype(np.float64))
                        subspace_args[dims[i]] = cf.wi(val1, val2)
                    else:
                        val1 = min(vals)
                        val2 = max(vals)
                        subspace_args[dims[i]] = cf.wi(cf.dt(val1), cf.dt(val2))

        return subspace_args



    def com_subspace_collapse(subspace_args):

        # Form the subspace command
        com_subspace = '' 
            
        if len(subspace_args) > 0:
            i = 0
            for arg in subspace_args:
                if i > 0:
                    com_subspace += ', '
                i = i + 1
                if type(subspace_args[arg]) == cf.query.Query:
                    vals = subspace_args[arg].value
                    if arg != 'T':
                        com_subspace += arg + '=cf.wi(' + str(vals[0]) + ', ' + str(vals[1]) + ')'
                    else:
                        com_subspace += arg + "=cf.wi(cf.dt('" + str(vals[0]) + "'), " + "cf.dt('" + str(vals[1]) + "'))"
                else:
                    com_subspace += arg + '=' 
                    if arg != 'T':
                        com_subspace += str(subspace_args[arg])
                    else:
                        com_subspace += "cf.dt('" + str(subspace_args[arg]) + "')"

        # Form the collapse command
        com_collapse = ''
        i = 0
        area = False
        dims = ['X', 'Y', 'Z', 'T']
        dims_small = ['x', 'y', 'z', 't']
        vars = [plotvars.collapse_x, plotvars.collapse_y, plotvars.collapse_z, plotvars.collapse_t]

        if vars[0] != 'Off' and vars[1] != 'Off':
            if vars[0] == vars[1]:
                area = True
                i = 1
                com_collapse += "'area: " + vars[0]

        for idim in np.arange(4):
            if vars[idim] != 'Off':
                if idim > 1:
                    area = False
                if not area:
                    if i == 0:
                        com_collapse += "'"
                    if i > 0:
                        com_collapse += ' '
                    i = i + 1
                    com_collapse += dims[idim] + ": " + vars[idim]

        if i > 0:
            com_collapse += "'"


        return com_subspace, com_collapse



    def generate_code(com_subspace, com_collapse):

        com = 'import cf\n'
        com += 'import cfplot as cfp\n'

        index = plotvars.index_number
        f = deepcopy(plotvars.fields[index])

        if isinstance(plotvars.file_selected, str):
             file = plotvars.file_selected.split('/')[-1]
             com += "f = cf.read('" + str(file) + "')[" + str(index) +']\n'
        else:
             file = plotvars.file_selected
             com += "f = cf.read(" + str(file) + ")[" + str(index) +']\n'


        # Check for bounds if a collapse is required
        # and add them if they are missing
        vars = [plotvars.collapse_x, plotvars.collapse_y,\
                plotvars.collapse_z, plotvars.collapse_t]
        dims = ['X', 'Y', 'Z', 'T']

        for idim in np.arange(4):
            if vars[idim] != 'Off':
                coord = f.coord(dims[idim])
                # Check axis has more than one cell
                if len(coord.array) > 1:
                    if coord.has_bounds() is False:
                        bounds = coord.create_bounds()
                        coord.set_bounds(bounds)
                        com += '\n# Adding missing bounds for ' + dims[idim] + '\n'
                        com += "coord = f.coord('" + dims[idim] + "')\n"
                        com += 'bounds = coord.create_bounds()\n'
                        com += 'coord.set_bounds(bounds)\n\n'


        i = 0
        variable_names = ['f', 'g', 'h']

        if com_subspace != '':
            com += variable_names[i+1] + ' = f.subspace(' + com_subspace + ')\n'
            i = i + 1

        if com_collapse != '':
            com += variable_names[i+1] + ' = ' + variable_names[i]
            com += '.collapse(' + com_collapse + ', weights=True)\n'
            i = i + 1

        return com, i





class Line_window(QWidget):
    '''popup window for changing line defaults'''

    def __init__(self):
        super(Line_window, self).__init__()
        self.initUI()


    def initUI(self):

        # Set up the bottom buttons
        resetButton = QPushButton("Reset")
        resetButton.clicked.connect(self.reset)

        helpButton = QPushButton("Help")
        helpButton.clicked.connect(self.help)

        quitButton = QPushButton("Quit")
        quitButton.clicked.connect(self.close)

        # Text box labels
        titleLabel = QLabel('title')
        xminLabel = QLabel('xmin')
        xmaxLabel = QLabel('xmax')
        yminLabel = QLabel('ymin')
        ymaxLabel = QLabel('ymax')
        styleLabel = QLabel('line style')
        colourLabel = QLabel('line colour')
        thicknessLabel = QLabel('line thickness')
        markerLabel = QLabel('Marker')
        markersizeLabel = QLabel('Marker size')
        markeredgecolorLabel = QLabel('Marker edge colour')
        markeredgewidthLabel = QLabel('Marker edge width')
        line_optionsLabel = QLabel('Line options')
        marker_optionsLabel = QLabel('Marker options')

        # Text boxes
        titleTextBox = QLineEdit()
        titleTextBox.setText('')
        titleTextBox.textChanged.connect(lambda: self.textbox_changed('title'))

        colourTextBox = QLineEdit()
        colourTextBox.setText('C0')
        colourTextBox.textChanged.connect(lambda: self.textbox_changed('colour'))

        thicknessTextBox = QLineEdit()
        thicknessTextBox.setText('1.0')
        thicknessTextBox.textChanged.connect(lambda: self.textbox_changed('thickness'))

        xminTextBox = QLineEdit()
        xminTextBox.setText('')
        xminTextBox.textChanged.connect(lambda: self.textbox_changed('xmin'))

        xmaxTextBox = QLineEdit()
        xmaxTextBox.setText('')
        xmaxTextBox.textChanged.connect(lambda: self.textbox_changed('xmax'))

        yminTextBox = QLineEdit()
        yminTextBox.setText('')
        yminTextBox.textChanged.connect(lambda: self.textbox_changed('ymin'))

        ymaxTextBox = QLineEdit()
        ymaxTextBox.setText('')
        ymaxTextBox.textChanged.connect(lambda: self.textbox_changed('ymax'))

        markerTextBox = QLineEdit()
        markerTextBox.setText('')
        markerTextBox.textChanged.connect(lambda: self.textbox_changed('marker'))

        markersizeTextBox = QLineEdit()
        markersizeTextBox.setText('')
        markersizeTextBox.textChanged.connect(lambda: self.textbox_changed('markersize'))

        markeredgecolorTextBox = QLineEdit()
        markeredgecolorTextBox.setText('')
        markeredgecolorTextBox.textChanged.connect(lambda: self.textbox_changed('markeredgecolor'))

        markeredgewidthTextBox = QLineEdit()
        markeredgewidthTextBox.setText('')
        markeredgewidthTextBox.textChanged.connect(lambda: self.textbox_changed('markeredgewidth'))


        # Combo boxes
        line_style_ComboBox = QComboBox()
        line_style_ComboBox.addItem('solid')
        line_style_ComboBox.addItem('dashed')
        line_style_ComboBox.addItem('dashdot')
        line_style_ComboBox.addItem('dotted')
        line_style_ComboBox.activated[str].connect(self.line_style)

        # Check boxes
        user_data_limitsCheckBox = QCheckBox("User defined plot limits")
        user_data_limitsCheckBox.setChecked(False)
        user_data_limitsCheckBox.clicked.connect(lambda: self.data_limits('automatic'))

        # Put widgets into self
        self.thicknessTextBox = thicknessTextBox
        self.titleTextBox = titleTextBox
        self.xminLabel = xminLabel
        self.xmaxLabel = xmaxLabel
        self.yminLabel = yminLabel
        self.ymaxLabel = ymaxLabel
        self.titleLabel = titleLabel
        self.styleLabel = styleLabel
        self.colourLabel = colourLabel
        self.thicknessLabel = thicknessLabel
        self.markerLabel = markerLabel
        self.markersizeLabel = markersizeLabel
        self.markeredgecolorLabel = markeredgecolorLabel
        self.markeredgewidthLabel = markeredgewidthLabel

        self.xminTextBox = xminTextBox
        self.xmaxTextBox = xmaxTextBox
        self.yminTextBox = yminTextBox
        self.ymaxTextBox = ymaxTextBox
        self.thicknessTextBox = thicknessTextBox
        self.colourTextBox = colourTextBox
        self.line_style_ComboBox = line_style_ComboBox
        self.markerTextBox = markerTextBox
        self.markersizeTextBox = markersizeTextBox
        self.markeredgecolorTextBox = markeredgecolorTextBox
        self.markeredgewidthTextBox = markeredgewidthTextBox

        self.user_data_limitsCheckBox = user_data_limitsCheckBox


        # Set the layout
        vbox = QVBoxLayout()

        hbox_titles = QHBoxLayout()
        hbox_titles.addWidget(self.titleLabel)
        hbox_titles.addWidget(self.titleTextBox)
        vbox.addLayout(hbox_titles)

        vbox.addWidget(HLine())
        vbox.addWidget(line_optionsLabel)

        hbox_type = QHBoxLayout()
        hbox_type.addWidget(self.styleLabel)
        hbox_type.addWidget(self.line_style_ComboBox)
        vbox.addLayout(hbox_type)

        hbox_thickness = QHBoxLayout()
        hbox_thickness.addWidget(self.thicknessLabel)
        hbox_thickness.addWidget(self.thicknessTextBox)
        vbox.addLayout(hbox_thickness)

        hbox_colour = QHBoxLayout()
        hbox_colour.addWidget(self.colourLabel)
        hbox_colour.addWidget(self.colourTextBox)
        vbox.addLayout(hbox_colour)

        vbox.addWidget(HLine())
        vbox.addWidget(marker_optionsLabel)

        hbox_marker = QHBoxLayout()
        hbox_marker.addWidget(self.markerLabel)
        hbox_marker.addWidget(self.markerTextBox)
        vbox.addLayout(hbox_marker)

        hbox_markersize = QHBoxLayout()
        hbox_markersize.addWidget(self.markersizeLabel)
        hbox_markersize.addWidget(self.markersizeTextBox)
        vbox.addLayout(hbox_markersize)

        hbox_markeredgecolor = QHBoxLayout()
        hbox_markeredgecolor.addWidget(self.markeredgecolorLabel)
        hbox_markeredgecolor.addWidget(self.markeredgecolorTextBox)
        vbox.addLayout(hbox_markeredgecolor)

        hbox_markeredgewidth = QHBoxLayout()
        hbox_markeredgewidth.addWidget(self.markeredgewidthLabel)
        hbox_markeredgewidth.addWidget(self.markeredgewidthTextBox)
        vbox.addLayout(hbox_markeredgewidth)

        vbox.addWidget(HLine())

        vbox.addWidget(self.user_data_limitsCheckBox)
        hbox_plot_x = QHBoxLayout()
        hbox_plot_x.addWidget(self.xminLabel)
        hbox_plot_x.addWidget(self.xminTextBox)
        hbox_plot_x.addWidget(self.xmaxLabel)
        hbox_plot_x.addWidget(self.xmaxTextBox)
        vbox.addLayout(hbox_plot_x)

        hbox_plot_y = QHBoxLayout()
        hbox_plot_y.addWidget(self.yminLabel)
        hbox_plot_y.addWidget(self.yminTextBox)
        hbox_plot_y.addWidget(self.ymaxLabel)
        hbox_plot_y.addWidget(self.ymaxTextBox)
        vbox.addLayout(hbox_plot_y)

        # The buttons
        hbox_buttons = QHBoxLayout()
        vbox.addLayout(hbox_buttons)
        hbox_buttons.addWidget(resetButton)
        hbox_buttons.addWidget(helpButton)
        hbox_buttons.addWidget(quitButton)
        vbox.addLayout(hbox_buttons)


        self.line_help = None  # No external window yet.

        self.setWindowTitle('line plot settings')
        self.setLayout(vbox)

        # Set theme and font
        palette = QPalette()
        palette.setColor(QPalette.Window, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Base, QColor(plotvars.background_colour))
        palette.setColor(QPalette.Button, QColor(plotvars.button_colour))
        palette.setColor(QPalette.ButtonText, QColor(plotvars.buttontext_colour))
        palette.setColor(QPalette.Highlight, QColor(plotvars.highlight_colour))
        palette.setColor(QPalette.HighlightedText, QColor(plotvars.text_colour))
        palette.setColor(QPalette.Text,  QColor(plotvars.text_colour))
        palette.setColor(QPalette.WindowText, QColor(plotvars.windowtext_colour))
        self.setPalette(palette)

        custom_font = QFont(plotvars.font, plotvars.fontsize)
        self.window().setFont(custom_font)

        self.data_limits('automatic')

        self.show()


    def line_style(self, text):
        # Set line type
        plotvars.line_style = text


    def reset(self):

        # Reset line options

        self.xminTextBox.setText('')
        self.xmaxTextBox.setText('')
        self.yminTextBox.setText('')
        self.ymaxTextBox.setText('')
        self.titleTextBox.setText('')
        self.markerTextBox.setText('')
        self.markersizeTextBox.setText('')
        self.markeredgecolorTextBox.setText('')
        self.markeredgewidthTextBox.setText('')
        self.thicknessTextBox.setText('1.0')
        self.colourTextBox.setText('C0')
        self.line_style_ComboBox.setCurrentIndex(0)

        self.user_data_limitsCheckBox.setChecked(False)
        self.data_limits('automatic')

        plotvars.line_style = 'solid'
        self.line_xmin = None
        self.line_xmax = None
        self.line_ymin = None
        self.line_ymax = None


    def textbox_changed(self, text):

        textbox = getattr(self, text + 'TextBox') 
        setattr(plotvars, 'line_' + text, textbox.text()) 



    def data_limits(self, text):
        print('in data_limits')

        if self.user_data_limitsCheckBox.isChecked():
            text = 'user'


        plotvars.line_limits = text
        print('text is ', text)

        objs = [self.xminTextBox, self.xmaxTextBox, self.yminTextBox, self.ymaxTextBox,\
                self.xminLabel, self.xmaxLabel, self.yminLabel, self.ymaxLabel]

        if plotvars.line_limits == 'user':
            color = plotvars.text_colour
            flags = [True] * 8
        else:
            color = plotvars.text_colour_insensitive
            flags = [False] * 8


        for i in np.arange(len(objs)):
            obj = objs[i]
            color = plotvars.text_colour_insensitive
            if flags[i]:
                color = plotvars.text_colour
            obj.setEnabled(flags[i])
            pal = QPalette(obj.palette())
            pal.setColor(QPalette.WindowText, QColor(color))
            obj.setPalette(pal)






    def help(self):

        if self.line_help is None:

            html = '<body><h2>Line plot options</h2>'
            html += '<h3>Line properties</h3>'
            html += 'The default line properties are a solid line of thickness 1.0 and colour C0\n'
            html += 'A list of default line colours is shown at\n'
            html += 'https://matplotlib.org/stable/users/dflt_style_changes.html\n'
            html += 'A list of named colours is shown at\n'
            html += 'https://matplotlib.org/stable/gallery/color/named_colors.html\n'
            html += '<h3>Marker properties</h3>'
            html += 'The default is for no markers to be drawn at the node points for the line.\n'
            html += 'A list of markers is available at\n'
            html += 'https://matplotlib.org/stable/api/markers_api.html\n'
            html += 'The quotes in this list are not needed in the cfview interface so a circle marker is\n'
            html += 'just an o in the marker text box.\n'
            html += 'Marker size, colour and edge width can also be specified\n'
            html += '<h3>Plot limits</h3>'
            html += 'Plot limits are generally taken from the supplied data but can be specied manually in\n'
            html += 'the four plot limits text boxes.Here xmin and xmax are the limits in the page x direction and \n'
            html += 'not the X direction i.e. longitude as specified in the data\n' 
            self.line_help = Help(html)

        self.line_help.show()






def main(filename, defaults='~/.cfview_defaults'):
    app = QApplication(sys.argv)
    app.setStyle('Fusion')

    ex = Cfview(filename, defaults)
    sys.exit(app.exec_())

if __name__ == '__main__':

    parser = argparse.ArgumentParser(description='cfview - climate data GUI using cf-python and cf-plot')
    parser.add_argument('-d', '--defaults', default='~/.cfview_defaults', help='defaults file')
    parser.add_argument("file", nargs="*", help='netCDF, Met Office PP or fields file')
    args = parser.parse_args()

    if len(args.file) == 0:
        main(None, defaults=args.defaults)
    else:
        #if len(args.file) > 1:
        #    print('\nWarning - multiple files passed but only first file being used\n')

        #main(args.file[0], defaults=args.defaults)

        main(args.file, defaults=args.defaults)













