예제 #1
0
  def __init__(self):
    PlotWindow.__init__(self)

    self.window_size=200
    self.values=numpy.zeros((self.window_size))
    self.index=0

    rospy.init_node('visualizer', anonymous=True)
    self.subscriber = rospy.Subscriber("event", Event, self.plotResults, queue_size = 1 )
예제 #2
0
파일: Signal.py 프로젝트: dareversat/test
    def plot_signal(self, columns = []): 
        if len(columns) == 0 :
            columns = self._signal_data.columns
        figure = PlotWindow(title = self._signal_name)

        if self._signal_data_type == 0 : 
            figure.plot_signal(self._signal_data, columns)
        else :
            figure.plot_signal(self._signal_data, columns, 1.5)
예제 #3
0
파일: main.py 프로젝트: MartinWeides/qkit
 def append_plot(self,parent,window_id,ds):
     # self, item, dataset
     
     window = PlotWindow(parent,self,ds)
     self.open_plots[window_id]=window
     self.open_ds[ds]=window_id
     
     window.show()   # non-modal
     #window.exec_() # modal
     #window.raise_()
     
     return window
예제 #4
0
    def createRSSIHistogram(self):
        d = self.getActiveDevices()
        child = PlotWindow(devices=d)
        sub = self.mdiArea.addSubWindow(child)
        sub.setWindowTitle("RSSI Histogram " + str(self.mdiChildNumber))
        self.mdiChildNumber = self.mdiChildNumber + 1
        child.showMaximized()
    
#     def deviceActivated(self, item):
#         print "Activated " + str(item)
#         print "Widget: " + self.listWidget.itemWidget(item).device.mac
#         
#     def deviceSelected(self):
#         item = self.listWidget.currentItem()
#         print "Selected " + str(item)
#         print "Widget: " + self.listWidget.itemWidget(item).device.mac        
            
예제 #5
0
    def __init__(self):
        PlotWindow.__init__(self)
    
        self.window_size=20
        self.values=numpy.zeros((self.window_size))
        self.index=0

        self.axes2D.set_autoscaley_on(False)
        self.axes2D.set_xlim((-1, 1))
        self.axes2D.set_ylim((-1, 1))
        
        self.axes3D.set_autoscaley_on(True)

        self.current_step = 0
        self.current_data = "flat"
        self.new_calibration = False
                        
        self.data_read = { "mag" : False, "pwm" : False, "bat" : False }
        self.latest = { "mag" : numpy.zeros(3), "pwm" : numpy.zeros(1), "bat" : numpy.zeros(1) }
        self.thrust = 0
        self.all_data = { "flat" :   { "mag" : { "x": [], "y": [], "z": []}, 
                                       "thrust" : [],
                                       "bat" : [] },
                          "sphere" : { "mag" : { "x": [], "y": [], "z": []}, 
                                       "thrust" : [],
                                       "bat" : [] }, 
                          "motor"  : { "mag" : { "x": [], "y": [], "z": []}, 
                                       "thrust" : [],
                                       "bat" : [] }}
        
        ## ROS
        rospy.init_node('magCalibrator', anonymous=True)
        self.subscriber = rospy.Subscriber("/cf/mag", magMSG, self.readMag, queue_size = 1 )
        self.subscriber = rospy.Subscriber("/cf/motor", motorMSG, self.readMotor, queue_size = 1 )
        self.subscriber = rospy.Subscriber("/cf/bat", batMSG, self.readBat, queue_size = 1 )
        self.sub_joy   = rospy.Subscriber("/cfjoy", joyMSG, self.new_joydata)
        self.pub_cal   = rospy.Publisher("/magCalib", magCalibMSG)

        self._readCalibrationFromFile()
    def prepareDataset(self, datasetObject):
        '''
        This is mostly for deciding what window to put the dataset in.
        '''

        windowName = datasetObject.windowName
        print "preparing dataset " + datasetObject.datasetName
        print windowName
        if windowName in self.windowDict.keys():
            window = self.windowDict[windowName]
            self.dwDict[datasetObject] = window
            window.new_dataset(datasetObject)
        else:
            window = PlotWindow(self.reactor)
            window.setWindowTitle(windowName)
            window.new_dataset(datasetObject)
            self.dwDict[datasetObject] = window
            self.windowDict[windowName] = window
            window.show()
예제 #7
0
            raise TypeError("TypeError in compute() :\n" + str(err_msg))
        except ValueError, err_msg:
            raise ValueError("ValueError in compute() :\n" + str(err_msg))
        except Exception, e :
            raise Exception("Exception in compute() :\n" + str(e))
        
        return True
    
    
    def visualizeResult(self) :         
        # Get plot method
        try :
            self._method_plot = getattr(self._method_class, "plot_result")
        except AttributeError, err :
            raise AttributeError("Cannot find plot() method of class : " + self._method_name)
        
        try : 
            self._plot_result = self._method_plot(self._method_instance, self._compute_result)
        except Exception, e :
            raise Exception("Exception in plot_result() :\n" + str(e))

        figure = PlotWindow()
        figure.plot_figure(self._plot_result)
        

            

        
        
        
    
예제 #8
0
            raise TypeError("TypeError in compute() :\n" + str(err_msg))
        except ValueError, err_msg:
            raise ValueError("ValueError in compute() :\n" + str(err_msg))
        except Exception, e :
            raise Exception("Exception in compute() :\n" + str(e))
        
        return True
    
    
    def visualizeResult(self) :         
        # Get plot method
        try :
            self._method_plot = getattr(self._method_class, "plot")
        except AttributeError, err :
            raise AttributeError("Cannot find plot() method of class : " + self._method_name)
        
        try : 
            self._plot_result = self._method_plot(self._method_instance)
        except Exception, e :
            raise Exception("Exception in plot() :\n" + str(e))

        figure = PlotWindow()
        figure.plot_figure(self._plot_result)
        

            

        
        
        
    
예제 #9
0
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.ui = main_design.Ui_MainWindow()
        self.ui.setupUi(self)

        self.image = None
        self.filename = ""
        self.detectorPosition = None
        self.detectorDirection = None
        self.detectorVisang = None
        self.wall = None
        self.separatrix = None
        self.imageMax = 0
        self.brightImageModifier = 1
        self.imageType = ImageType.I

        # Create plot window
        self.plotWindow = PlotWindow()
        # Create caption dialog
        self.captionDialog = SetCaption()
        # Create vessel dialog
        self.vesselDialog = Vessel()

        # Bind to events
        self.bindEvents()

        # Add plot types
        self.ui.cbPlotType.addItem('Normal', 0)
        self.ui.cbPlotType.addItem('Logarithmic', 1)

        # Add color map options
        self.ui.cbColormap.addItem('afmhot')
        self.ui.cbColormap.addItem('GeriMap')
        self.ui.cbColormap.addItem('gray')
        self.ui.cbColormap.addItem('viridis')
        self.ui.cbColormap.addItem('jet')
        self.ui.cbColormap.addItem('RdBu')

        # Add polarized image options
        for s in ImageType:
            if s != ImageType.EMPTY:
                self.ui.cbImageType.addItem(s.value)

        #self.ui.cbImageType.addItem('Image')
        #self.ui.cbImageType.addItem('Stokes Q (+)')
        #self.ui.cbImageType.addItem('Stokes Q (-)')
        #self.ui.cbImageType.addItem('Stokes U (+)')
        #self.ui.cbImageType.addItem('Stokes U (-)')
        #self.ui.cbImageType.addItem('Stokes V (+)')
        #self.ui.cbImageType.addItem('Stokes V (-)')
        #self.ui.cbImageType.addItem('Linear polarization fraction')
        #self.ui.cbImageType.addItem('Polarization angle')
        #self.ui.cbImageType.addItem('Horizontal')
        #self.ui.cbImageType.addItem('Vertical')
        #self.ui.cbImageType.addItem('Diagonal 1')
        #self.ui.cbImageType.addItem('Diagonal 2')

        # Check command-line arguments
        if len(sys.argv) == 2:
            if os.path.isfile(sys.argv[1]):
                self.ui.txtFilename.setText(os.path.abspath(sys.argv[1]))
                self.loadFile(sys.argv[1])

        self.ui.cbColormap.setCurrentIndex(1)
예제 #10
0
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.ui = main_design.Ui_MainWindow()
        self.ui.setupUi(self)

        self.image = None
        self.filename = ""
        self.detectorPosition = None
        self.detectorDirection = None
        self.detectorVisang = None
        self.wall = None
        self.separatrix = None
        self.imageMax = 0
        self.brightImageModifier = 1
        self.imageType = ImageType.I

        # Create plot window
        self.plotWindow = PlotWindow()
        # Create caption dialog
        self.captionDialog = SetCaption()
        # Create vessel dialog
        self.vesselDialog = Vessel()

        # Bind to events
        self.bindEvents()

        # Add plot types
        self.ui.cbPlotType.addItem('Normal', 0)
        self.ui.cbPlotType.addItem('Logarithmic', 1)

        # Add color map options
        self.ui.cbColormap.addItem('afmhot')
        self.ui.cbColormap.addItem('GeriMap')
        self.ui.cbColormap.addItem('gray')
        self.ui.cbColormap.addItem('viridis')
        self.ui.cbColormap.addItem('jet')
        self.ui.cbColormap.addItem('RdBu')

        # Add polarized image options
        for s in ImageType:
            if s != ImageType.EMPTY:
                self.ui.cbImageType.addItem(s.value)

        #self.ui.cbImageType.addItem('Image')
        #self.ui.cbImageType.addItem('Stokes Q (+)')
        #self.ui.cbImageType.addItem('Stokes Q (-)')
        #self.ui.cbImageType.addItem('Stokes U (+)')
        #self.ui.cbImageType.addItem('Stokes U (-)')
        #self.ui.cbImageType.addItem('Stokes V (+)')
        #self.ui.cbImageType.addItem('Stokes V (-)')
        #self.ui.cbImageType.addItem('Linear polarization fraction')
        #self.ui.cbImageType.addItem('Polarization angle')
        #self.ui.cbImageType.addItem('Horizontal')
        #self.ui.cbImageType.addItem('Vertical')
        #self.ui.cbImageType.addItem('Diagonal 1')
        #self.ui.cbImageType.addItem('Diagonal 2')

        # Check command-line arguments
        if len(sys.argv) == 2:
            if os.path.isfile(sys.argv[1]):
                self.ui.txtFilename.setText(os.path.abspath(sys.argv[1]))
                self.loadFile(sys.argv[1])

        self.ui.cbColormap.setCurrentIndex(1)

    def bindEvents(self):
        self.ui.sliderIntensity.valueChanged.connect(self.intensityChanged)
        self.ui.cbPlotType.currentIndexChanged.connect(self.toggleLogarithmic)
        self.ui.cbColormap.currentIndexChanged.connect(self.setColormap)
        self.ui.cbImageType.currentIndexChanged.connect(self.setImageType)
        self.ui.cbColorbar.stateChanged.connect(self.toggleColorbar)
        self.ui.cbInvert.stateChanged.connect(self.setColormap)
        self.ui.cbBrightImage.stateChanged.connect(self.intensityChanged)
        self.ui.cbRelativeColorbar.stateChanged.connect(self.toggleColorbar)
        self.ui.cbSeparatrix.stateChanged.connect(self.showSeparatrix)
        self.ui.cbTopview.stateChanged.connect(self.showTopview)
        self.ui.cbWallCross.stateChanged.connect(self.showWallCrossSection)
        self.ui.btnOpen.clicked.connect(self.openFile)
        self.ui.btnReload.clicked.connect(self.reloadFile)
        self.ui.btnSave.clicked.connect(self.saveFile)
        self.ui.btnSetCaption.clicked.connect(self.setCaption)
        self.ui.btnWall.clicked.connect(self.setWallOverlay)

        self.captionDialog.captionsUpdated.connect(self.captionsUpdated)
        self.vesselDialog.overlayChanged.connect(self.vesselUpdated)

    def captionsUpdated(self, captions):
        self.plotWindow.image.setCaptions(captions)
        self.plotWindow.image.plotCaptions()

    def closeEvent(self, event):
        self.exit()

    def exit(self):
        self.plotWindow.close()
        self.captionDialog.close()
        self.vesselDialog.close()
        self.close()

    def intensityChanged(self):
        bim = 1
        if self.ui.cbBrightImage.isChecked():
            bim = 1.0 / 100.0

        self.ui.lblIntensity.setText(
            str(self.ui.sliderIntensity.value() * bim) + '%')
        intmax = (self.ui.sliderIntensity.value() / 100.0) * bim
        self.plotWindow.image.changeIntensity(intmax, relative=True)
        self.plotWindow.syntheticImageUpdated()

    def loadFile(self, filename):
        self.ui.txtFilename.setText(filename)
        self.filename = filename

        self.plotWindow.image.loadImageFile(filename, self.imageType)
        imageMax = self.plotWindow.image.getImageMax()

        # Enable overlay checkboxes
        if self.plotWindow.image.hasSeparatrix():
            self.ui.cbSeparatrix.setEnabled(True)
        if self.plotWindow.image.hasTopview():
            self.ui.cbTopview.setEnabled(True)
        if self.plotWindow.image.hasWall():
            self.ui.cbWallCross.setEnabled(True)

        if imageMax == 0:
            self.statusBar().showMessage("Image is empty!")
        else:
            #self.statusBar().showMessage("Successfully loaded "+filename, 3000)
            self.statusBar().showMessage("Max value = " + str(imageMax))

        self.refreshImage()

    def openFile(self):
        filename, _ = QFileDialog.getOpenFileName(
            parent=self,
            caption="Open SOFT image file",
            filter=
            "SOFT Output (*.dat *.h5 *.hdf5 *.mat *.sdt);;All files (*.*)")

        if filename:
            self.loadFile(filename)

    def refreshImage(self):
        if not self.plotWindow.isVisible():
            self.plotWindow.show()

        self.plotWindow.plotImage()

    def reloadFile(self):
        if self.filename is "":
            return

        self.loadFile(self.filename)

    def saveFile(self):
        if not self.plotWindow.isVisible():
            QMessageBox.information(
                self, 'No image open',
                'No SOFT image file is currently open, thus there is no image to save. Please, open an image file!'
            )
            return

        filename, _ = QFileDialog.getSaveFileName(
            self,
            caption='Save SOFT image',
            filter=
            'Encapsulated Post-Script (*.eps);;Portable Network Graphics (*.png);;Portable Document Format (*.pdf);;Scalable Vector Graphics (*.svg)'
        )

        if filename:
            self.plotWindow.image.savePlot(filename)

    def setCaption(self):
        self.captionDialog.show()

    def setColormap(self):
        cmname = self.ui.cbColormap.currentText()
        if self.ui.cbInvert.isChecked():
            self.plotWindow.image.setColormap(cmname + '_r')
            self.plotWindow.syntheticImageUpdated(True)
        else:
            self.plotWindow.image.setColormap(cmname)
            self.plotWindow.syntheticImageUpdated(True)

    def setImageType(self):
        self.imageType = ImageType(self.ui.cbImageType.currentText())
        self.reloadFile()

    def setWallOverlay(self):
        self.vesselDialog.show()

    def showSeparatrix(self):
        if self.ui.cbSeparatrix.isChecked():
            self.plotWindow.image.plotSeparatrix()
        else:
            self.plotWindow.image.removeSeparatrix()

        self.plotWindow.syntheticImageUpdated()

    def showTopview(self):
        if self.ui.cbTopview.isChecked():
            self.plotWindow.image.plotTopview()
        else:
            self.plotWindow.image.removeTopview()

        self.plotWindow.syntheticImageUpdated()

    def showWallCrossSection(self):
        if self.ui.cbWallCross.isChecked():
            self.plotWindow.image.plotWallCrossSection()
        else:
            self.plotWindow.image.removeWallCrossSection()

        self.plotWindow.syntheticImageUpdated()

    def toggleColorbar(self):
        self.plotWindow.image.toggleColorbar(self.ui.cbColorbar.isChecked())
        self.plotWindow.image.toggleColorbarRelative(
            self.ui.cbRelativeColorbar.isChecked())

        if self.ui.cbColorbar.isChecked():
            self.plotWindow.image.plotColorbar()
        else:
            self.plotWindow.image.removeColorbar()

        self.plotWindow.syntheticImageUpdated()

    def toggleLogarithmic(self):
        if self.ui.cbPlotType.currentIndex() == 1:
            self.plotWindow.image.toggleLogarithmic(True)
        else:
            self.plotWindow.image.toggleLogarithmic(False)

        self.plotWindow.syntheticImageUpdated(True)

    def vesselUpdated(self, status):
        self.plotWindow.image.setOverlays(status)
        self.plotWindow.image.plotOverlays()
        self.plotWindow.syntheticImageUpdated()
예제 #11
0
class DetectorCalibration(QtWidgets.QMainWindow):
    def __init__(self, argv):
        global COLORS

        QtWidgets.QMainWindow.__init__(self)
        self.ui = detcal_design.Ui_DetectorCalibration()
        self.ui.setupUi(self)

        self.magfield = None
        self.image = None
        self.plotWindow = PlotWindow()
        self.toggleEnabled(False)

        if len(argv) > 2:
            QMessageBox.critical(
                self, 'Too many input arguments',
                'Too many input arguments were given. Expected at most 2 arguments.'
            )
            self.exit()

        imagefile = None
        meqfile = None
        for arg in argv:
            if arg.endswith('.png'):
                imagefile = arg
            elif arg.endswith('.h5') or arg.endswith('.mat') or args.endswith(
                    '.hdf5'):
                meqfile = arg
            else:
                QMessageBox.critical(
                    self, 'Unrecognized input file',
                    'The given input file is of an unrecognized type: {0}'.
                    format(arg))
                self.exit()

        i, selindex = 0, 0
        for clr, _ in COLORS.items():
            self.ui.cbColor.addItem(clr)

            if clr == 'white':
                selindex = i

            i += 1

        self.ui.cbColor.setCurrentIndex(selindex)

        if imagefile is not None:
            self.loadImage(imagefile)
        if meqfile is not None:
            self.loadEquilibrium(meqfile)

        self.bindEvents()

    def bindEvents(self):
        self.ui.btnBrowseEq.clicked.connect(self.openEquilibrium)
        self.ui.btnBrowseImage.clicked.connect(self.openImage)
        self.ui.btnRedraw.clicked.connect(self.updateWall)

        self.ui.cbColor.currentIndexChanged.connect(self.toroidalChanged)
        self.ui.sliderToroidal.valueChanged.connect(self.toroidalChanged)
        self.ui.dsbLinewidth.valueChanged.connect(self.toroidalChanged)

    def toggleEnabled(self, enabled=False):
        self.ui.gbDetector.setEnabled(enabled)

        self.ui.gbOverlay.setEnabled(enabled)
        """
        self.ui.sliderToroidal.setEnabled(enabled)
        self.ui.lblToroidal.setEnabled(enabled)
        self.ui.lblTor0.setEnabled(enabled)
        self.ui.lblTor90.setEnabled(enabled)
        self.ui.lblTor180.setEnabled(enabled)
        self.ui.lblTor270.setEnabled(enabled)
        self.ui.lblTor360.setEnabled(enabled)
        """

    def closeEvent(self, event):
        self.exit()

    def exit(self):
        self.plotWindow.close()
        self.close()

    def openEquilibrium(self):
        filename, _ = QFileDialog.getOpenFileName(
            parent=self,
            caption="Open SOFT magnetic equilibrium",
            filter="SOFT Equilibrium Data (*.h5 *.mat)")

        if filename:
            self.loadEquilibrium(filename)

    def loadEquilibrium(self, filename):
        self.ui.tbEquilibrium.setText(filename)
        self.magfield = MagneticField(filename)

        self.toggleEnabled(True)
        self.updateWall()

    def openImage(self):
        filename, _ = QFileDialog.getOpenFileName(
            parent=self,
            caption="Open SOFT magnetic equilibrium",
            filter="Image (*.png)")

        if filename:
            self.loadImage(filename)

    def loadImage(self, filename):
        self.ui.tbImage.setText(filename)
        self.image = mpimg.imread(filename)

        if not self.plotWindow.isVisible():
            self.plotWindow.show()

        self.setImage(self.image)

    def updateWall(self):
        if not self.plotWindow.isVisible():
            self.plotWindow.show()

        try:
            detpos = np.array([
                float(self.ui.tbPosX.text()),
                float(self.ui.tbPosY.text()),
                float(self.ui.tbPosZ.text())
            ])
            detdir = np.array([
                float(self.ui.tbDirX.text()),
                float(self.ui.tbDirY.text()),
                float(self.ui.tbDirZ.text())
            ])
            detdir = detdir / np.linalg.norm(detdir)
            visang = float(self.ui.tbVisang.text())
            tiltAngle = float(self.ui.tbTilt.text())
            self.setWall(detpos, detdir, visang, tiltAngle)
        except ValueError as e:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText(e.strerror)
            msg.setWindowTitle('Runtime Error')
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec_()

    def toroidalChanged(self):
        self.plotWindow.ax = self.gen()
        self.plotWindow.drawSafe()

    def gen(self):
        fig = self.plotWindow.figure

        fig.clear()
        ax = fig.add_subplot(111)
        pixelscale = 1

        if self.magfield is not None:
            pixelscale = np.tan(self.visang) / 2

        if self.image is not None:
            h = self.image.shape[0]
            w = self.image.shape[1]

            extent = []
            if h >= w:
                extent = [
                    -(w / h) * pixelscale, (w / h) * pixelscale, -pixelscale,
                    pixelscale
                ]
            else:
                extent = [
                    -pixelscale, pixelscale, -(h / w) * pixelscale,
                    (h / w) * pixelscale
                ]

            ax.imshow(self.image, extent=extent)

        if self.magfield is not None:
            toffset = self.ui.sliderToroidal.value()
            clr = self.ui.cbColor.currentText()
            linewidth = self.ui.dsbLinewidth.value()

            plotwall(ax,
                     self.magfield.wall,
                     self.detpos,
                     self.detdir,
                     degreesStart=[toffset - 30, toffset + 210],
                     degreesEnd=[toffset - 29, toffset + 211],
                     tiltAngle=self.tiltAngle,
                     color=COLORS[clr],
                     linewidth=linewidth)
            #plotwall(ax, self.magfield.wall, self.detpos, self.detdir, degreesStart=[toffset+190], degreesEnd=[toffset+350], rlim=0.46, spacing=5, tiltAngle=self.tiltAngle, color=COLORS[clr], linewidth=linewidth)
            #plotwall(ax, self.magfield.wall, self.detpos, self.detdir, degreesStart=[toffset+190], degreesEnd=[toffset+350], zuplim=-0.4, spacing=3, tiltAngle=self.tiltAngle, color=COLORS[clr], linewidth=linewidth)

            ax.set_xlim([-pixelscale, pixelscale])
            ax.set_ylim([-pixelscale, pixelscale])

        fig.subplots_adjust(top=1,
                            bottom=0,
                            right=1,
                            left=0,
                            hspace=0,
                            wspace=0)
        ax.set_axis_off()

        return ax

    def plot(self):
        self.plotWindow.ax = self.gen()
        self.plotWindow.drawSafe()

    def setImage(self, image):
        self.image = image
        self.plot()

    def setWall(self, detpos, detdir, visang, tiltAngle):
        self.detpos = detpos
        self.detdir = detdir
        self.visang = visang
        self.tiltAngle = tiltAngle

        self.plot()
예제 #12
0
class GreensFunctionR12(QtWidgets.QMainWindow):

    labels = {
        'gamma': r'$\gamma$',
        'p': r'$p / mc$',
        'ppar': r'$p_{\parallel} / mc$',
        'pperp': r'$p_{\perp} / mc$',
        'thetap': r'$\theta_{\rm p}$ (rad)',
        'ithetap': r'$\theta_{\rm p}$ (rad)',
        'xi': r'$\xi$'
    }

    poltypes = {
        'Intensity': lambda f: (f[0], 0, 1),
        'Horizontal polarization': lambda f: (0.5 * (f[0] + f[1]), 0, 1),
        'Vertical polarization': lambda f: (0.5 * (f[0] - f[1]), 0, 1),
        'Polarization angle': calcpolangle,
        'Polarization fraction': calcpolfrac,
        'Stokes I': lambda f: (f[0], 0, 1),
        'Stokes Q': lambda f: (f[1], -1, 1),
        'Stokes U': lambda f: (f[2], -1, 1),
        'Stokes V': lambda f: (f[3], -1, 1)
    }

    def __init__(self, argv):
        QtWidgets.QMainWindow.__init__(self)

        self.ui = r12_design.Ui_R12()
        self.ui.setupUi(self)

        if len(argv) != 1:
            raise Exception(
                "The Green's function must be specified at startup")

        self.filename = argv[0]
        self.plotWindow = PlotWindow(width=800, height=600)
        self.radialPlotWindow = PlotWindow(width=700, height=400)
        self.ax = None
        self.radialAx = None
        self.colorbar = None

        self.hasStokesParameters = False

        for key in self.poltypes:
            self.ui.cbRadiationType.addItem(key)

        self.loadGreensFunction(self.filename)
        self.setupFigure()

        self.bindEvents()

    def closeEvent(self, event):
        self.exit()

    def exit(self):
        self.plotWindow.close()
        self.radialPlotWindow.close()
        self.close()

    def bindEvents(self):
        self.ui.rbSingleR.toggled.connect(self.toggleSingleSum)
        self.ui.sliderRadius.valueChanged.connect(self.sliderRadiusChanged)
        self.ui.sliderWavelength.valueChanged.connect(
            self.sliderWavelengthChanged)
        self.ui.cbRadiationType.currentTextChanged.connect(
            self.cbRadiationTypeChanged)

        self.ui.btnMark.clicked.connect(self.markSuperParticle)
        self.ui.btnPlotRadialProfile.clicked.connect(self.plotRadialProfile)
        self.ui.btnSave.clicked.connect(self.saveFigure)

    def getGF(self):
        F = None

        FUNC = self.gf.FUNC
        if self.format[0] == 'w':
            idx = self.ui.sliderWavelength.value()
            FUNC = FUNC[idx, :]

        fmin, fmax = 0, 1
        if self.hasStokesParameters:
            FUNC, fmin, fmax = self.getPolFunction()

        if self.format in ['12', 'w12']:
            F = np.copy(FUNC).T
            mx = np.amax(np.abs(F))
            if mx != 0: F /= mx
        elif self.ui.rbSingleR.isChecked():
            idx = self.ui.sliderRadius.value()
            F = np.copy(FUNC[idx]).T
            mx = np.amax(np.abs(F))
            if mx != 0: F /= mx
        else:
            F = np.sum(FUNC, axis=0).T
            mx = np.amax(np.abs(F))
            if mx != 0: F /= mx

        # Locate super particle
        self.getSuperParticle(F)

        return F, fmin, fmax

    def getPolFunction(self):
        tp = self.ui.cbRadiationType.currentText()

        fun = self.poltypes[tp]
        return fun(self.gf.FUNC)

    def getSuperParticle(self, F):
        i, j = np.unravel_index(np.argmax(F), F.shape)
        param1max = self.gf._param1[j]
        param2max = self.gf._param2[i]

        self.ui.lblParam1.setText('{:.4}'.format(param1max))
        self.ui.lblParam2.setText('{:.4}'.format(param2max))
        self.ui.lblSuperEnergy.setText('{:.4} mc²'.format(self.gf.GAMMA[i, j]))
        self.ui.lblSuperPitch.setText('{:.4} rad'.format(self.gf.THETAP[i, j]))

        return param1max, param2max, i, j

    def loadGreensFunction(self, filename):
        self.gf = Green(filename=filename)

        fmt = self.gf.getFormat()
        if fmt == '12':
            self.ui.rbSingleR.setEnabled(False)
        elif fmt not in ['r12', 'wr12']:
            raise Exception(
                "The Green's function has an invalid format: '{}'. Expected '(s)12' or '(s)r12'."
                .format(fmt))

        self.format = fmt
        self.hasStokesParameters = self.gf.stokesparams
        self.ui.cbRadiationType.setEnabled(self.gf.stokesparams)

        self.ui.sliderRadius.setMaximum(self.gf.nr - 1)
        self.ui.sliderRadius.setTickInterval(
            max(1, int(np.round(self.gf.nr / 20))))

        if fmt == 'wr12':
            self.ui.sliderWavelength.setMaximum(self.gf._wavelengths.size - 1)

            self.sliderWavelengthChanged()
        else:
            self.ui.sliderWavelength.hide()
            self.ui.lblWavelengthLbl.hide()
            self.ui.lblWavelength.hide()

        self.ui.lblParam1Name.setText('Parameter 1 ({}):'.format(
            self.gf._param1name))
        self.ui.lblParam2Name.setText('Parameter 2 ({}):'.format(
            self.gf._param2name))

        self.sliderRadiusChanged()

    def markSuperParticle(self):
        F, _, _ = self.getGF()
        m1, m2, _, _ = self.getSuperParticle(F)
        self.ax.plot(m1,
                     m2,
                     'x',
                     color=(0, 1, 0),
                     markersize=10,
                     markeredgewidth=3)
        self.plotWindow.drawSafe()

    def plotRadialProfile(self):
        mc = 9.109e-31 * 299792458
        J = self.gf.getJacobian().T * mc**3
        r = self.gf._r
        fr = np.zeros((r.size, ))
        F = self.gf.FUNC

        for i in range(0, r.size):
            rrr = np.sum(F[i, :, :] * J)
            fr[i] = rrr

        self.radialAx = self.radialPlotWindow.figure.add_subplot(111)
        self.radialAx.plot(r, fr / (r - r[0])**2, linewidth=2)
        self.radialAx.set_xlabel(r'$\mathrm{Major\ radius}\ \rho$')
        self.radialAx.set_ylabel(
            r'$\mathrm{Radial\ intensity}\ \partial I/\partial\rho$')
        self.radialPlotWindow.drawSafe()

        if not self.radialPlotWindow.isVisible():
            self.radialPlotWindow.show()

    def redrawFigure(self):
        F, fmin, fmax = self.getGF()
        r = np.linspace(fmin, fmax, 20)
        self.ax.clear()

        cmap = 'GeriMap'
        if fmin < 0:
            cmap = 'RdBu'

        cntr = self.ax.contourf(self.gf._param1,
                                self.gf._param2,
                                F,
                                levels=r,
                                cmap=cmap,
                                vmin=fmin,
                                vmax=fmax)

        if self.colorbar is None:
            self.colorbar = self.plotWindow.figure.colorbar(cntr)
        else:
            self.colorbar.ax.clear()
            self.colorbar = self.plotWindow.figure.colorbar(
                cntr, cax=self.colorbar.ax)

        self.ax.set_xlabel(self.labels[self.gf._param1name])
        self.ax.set_ylabel(self.labels[self.gf._param2name])

        self.plotWindow.drawSafe()

    def saveFigure(self):
        filename, _ = QFileDialog.getSaveFileName(
            self,
            caption='Save figure',
            filter=
            'Portable Document Format (*.pdf);;Encapsulated PostScript (*.eps);;Portable Network Graphics (*.png);;All files (*.*)'
        )

        if filename:
            self.plotWindow.canvas.print_figure(filename, bbox_inches='tight')

    def setupFigure(self):
        self.ax = self.plotWindow.figure.add_subplot(111)

        if not self.plotWindow.isVisible():
            self.plotWindow.show()

        self.redrawFigure()

    def cbRadiationTypeChanged(self):
        self.redrawFigure()

    def sliderRadiusChanged(self):
        idx = self.ui.sliderRadius.value()
        self.ui.lblRIndex.setText(str(idx))
        self.ui.lblR.setText('r = {:.4}'.format(self.gf._r[idx]))

        if self.ax is not None:
            self.redrawFigure()

    def sliderWavelengthChanged(self):
        idx = self.ui.sliderWavelength.value()
        self.ui.lblWavelength.setText('{} nm'.format(
            self.gf._wavelengths[idx] / 1e-9))

        if self.ax is not None:
            self.redrawFigure()

    def toggleSingleSum(self):
        enbl = self.ui.rbSingleR.isChecked()
        self.ui.sliderRadius.setEnabled(enbl)
        self.ui.lblRIndex.setEnabled(enbl)
        self.ui.lblR.setEnabled(enbl)

        self.redrawFigure()
예제 #13
0
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.ui = main_design.Ui_MainWindow()
        self.ui.setupUi(self)

        self.wall = None
        self.image = None
        self.plotWindow = PlotWindow()
        self.ui.gbDetector.setEnabled(False)

        self.bindEvents()

    def bindEvents(self):
        self.ui.btnBrowseEq.clicked.connect(self.openEquilibrium)
        self.ui.btnBrowseImage.clicked.connect(self.openImage)
        self.ui.btnRedraw.clicked.connect(self.updateWall)

    def closeEvent(self):
        self.exit()

    def exit(self):
        self.plotWindow.close()
        self.close()

    def openEquilibrium(self):
        filename, _ = QFileDialog.getOpenFileName(parent=self, caption="Open SOFT magnetic equilibrium", filter="SOFT Equilibrium Data (*.h5 *.mat)")

        if filename:
            self.ui.tbEquilibrium.setText(filename)
            if filename.endswith('.mat'):
                matfile = scipy.io.loadmat(filename)
                self.wall = matfile['wall']
            elif filename.endswith('.h5') or filename.endswith('.hdf5'):
                hfile = h5py.File(filename, 'r')
                self.wall = list(hfile['wall'])
                hfile.close()

            self.ui.gbDetector.setEnabled(True)
            self.updateWall()
        
    def openImage(self):
        filename, _ = QFileDialog.getOpenFileName(parent=self, caption="Open SOFT magnetic equilibrium", filter="Image (*.jpeg *jpg *.png)")

        if filename:
            self.ui.tbImage.setText(filename)
            self.image = mpimg.imread(filename)
            
            if not self.plotWindow.isVisible():
                self.plotWindow.show()

            self.plotWindow.setImage(self.image)

    def updateWall(self):
        if not self.plotWindow.isVisible():
            self.plotWindow.show()

        try:
            detpos = np.array([float(self.ui.tbPosX.text()), float(self.ui.tbPosY.text()), float(self.ui.tbPosZ.text())])
            detdir = np.array([float(self.ui.tbDirX.text()), float(self.ui.tbDirY.text()), float(self.ui.tbDirZ.text())])
            detdir = detdir / np.linalg.norm(detdir)
            visang = float(self.ui.tbVisang.text())
            tiltAngle = float(self.ui.tbTilt.text())
            self.plotWindow.setWall(self.wall, detpos, detdir, visang, tiltAngle)
        except ValueError as e:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText(e.strerror)
            msg.setWindowTitle('Runtime Error')
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec_()
예제 #14
0
class SingleEnergyPitchIJ(QtWidgets.QMainWindow):
    def __init__(self, argv):
        QtWidgets.QMainWindow.__init__(self)

        self.ui = SingleEnergyPitchIJ_design.Ui_SingleEnergyPitchIJ()
        self.ui.setupUi(self)

        filename = None
        if len(argv) > 1:
            raise Exception("Too many input arguments given to 's12ij'.")
        elif len(argv) == 1:
            filename = argv[0]

        self.plotWindow = PlotWindow()

        self.GF = None
        self.GFintensity = None

        self.superPlotCanvas = None
        self.superPlotLayout = None
        self.superPlotAx = None
        self.superPlotHandle = None
        self.superPlotDomHandle = None
        self.pitchAngles = None
        self.overlay = None
        self.overlayHandle = None

        self.toggleEnabled(False)

        self.bindEvents()

        self.gerimap, _ = registerGeriMap(None)

        if filename is not None and os.path.isfile(filename):
            self.loadFile(filename)

    def bindEvents(self):
        self.ui.btnBrowse.clicked.connect(self.openFile)
        self.ui.btnBrowseOverlay.clicked.connect(self.openOverlay)
        self.ui.btnSaveImage.clicked.connect(self.saveImage)
        self.ui.btnSaveSuper.clicked.connect(self.saveSuper)
        self.ui.btnSaveBoth.clicked.connect(self.saveBoth)

        self.ui.sliderEnergy.valueChanged.connect(self.energyChanged)
        self.ui.sliderPitchAngle.valueChanged.connect(
            self.pitchAngleParameterChanged)
        self.ui.sliderOverlay.valueChanged.connect(self.overlaySliderChanged)

        self.ui.cbUnderlay.toggled.connect(self.toggleOverlayType)

    def closeEvent(self, event):
        self.exit()

    def exit(self):
        self.plotWindow.close()
        self.close()

    def setupSuperPlot(self):
        ymax = 1.1
        z = np.zeros(self.pitchAngles.shape)

        self.superPlotLayout = QtWidgets.QVBoxLayout(self.ui.widgetDistPlot)

        self.superPlotCanvas = FigureCanvas(Figure())
        self.superPlotLayout.addWidget(self.superPlotCanvas)

        self.superPlotAx = self.superPlotCanvas.figure.subplots()
        self.superPlotHandle, = self.superPlotAx.plot(self.pitchAngles,
                                                      z,
                                                      linewidth=2)
        self.superPlotDomHandle, = self.superPlotAx.plot([0, 0], [0, ymax],
                                                         'k--')

        self.superPlotAx.set_xlim([self.pitchAngles[0], self.pitchAngles[-1]])
        self.superPlotAx.set_ylim([0, ymax])
        self.superPlotAx.get_yaxis().set_ticks([])

        self.superPlotAx.set_xlabel(r'$\theta_{\rm p}\ \mathrm{(rad)}$')
        self.superPlotAx.set_ylabel(r'$f(\theta_{\rm p}) / f_{\rm max}$')

        self.superPlotCanvas.figure.tight_layout(pad=2.5)

    def updateSuperPlot(self, f=None):
        ei = self.getEnergyIndex()

        if f is None:
            f = self.getDistributionFunction()

        superParticle = self.GFintensity[ei, :] * f
        superParticle = superParticle / np.amax(superParticle)
        maxpitch = self.pitchAngles[np.argmax(superParticle)]

        self.ui.lblDomPitch.setText('{0:.3f} rad'.format(maxpitch))

        self.superPlotHandle.set_ydata(superParticle)
        self.superPlotDomHandle.set_xdata([maxpitch, maxpitch])

        self.superPlotCanvas.draw()
        self.superPlotCanvas.flush_events()

    def getDistributionFunction(self):
        C = self.ui.sliderPitchAngle.value()

        f = np.exp(C * self.cosPitchAngles)
        return f

    def energyChanged(self):
        ei = self.ui.sliderEnergy.value()
        if len(self.GF._param1.shape) == 2:
            self.ui.lblEnergy.setText('{0:.2f}'.format(self.GF._param1[0][ei]))
        else:
            self.ui.lblEnergy.setText('{0:.2f}'.format(self.GF._param1[ei]))

        f = self.getDistributionFunction()
        self.updateSuperPlot(f=f)
        self.updateImage(f=f)

    def pitchAngleParameterChanged(self):
        self.ui.lblPitchAngle.setText(str(self.ui.sliderPitchAngle.value()))

        f = self.getDistributionFunction()
        self.updateSuperPlot(f=f)
        self.updateImage(f=f)

    def toggleEnabled(self, enabled=False):
        self.ui.lblREEnergy.setEnabled(enabled)
        self.ui.lblREPitchAngle.setEnabled(enabled)

        self.ui.lblEnergy.setEnabled(enabled)
        self.ui.lblPitchAngle.setEnabled(enabled)

        self.ui.sliderEnergy.setEnabled(enabled)
        self.ui.sliderPitchAngle.setEnabled(enabled)

        self.ui.lblEnergyMin.setEnabled(enabled)
        self.ui.lblEnergyMax.setEnabled(enabled)
        self.ui.lblPitchAngleMin.setEnabled(enabled)
        self.ui.lblPitchAngleMax.setEnabled(enabled)

        self.ui.lblOverlay.setEnabled(enabled)
        self.ui.lblOverlayMin.setEnabled(enabled)
        self.ui.lblOverlayMax.setEnabled(enabled)
        self.ui.lblOverlay25.setEnabled(enabled)
        self.ui.lblOverlay50.setEnabled(enabled)
        self.ui.lblOverlay75.setEnabled(enabled)
        self.ui.btnBrowseOverlay.setEnabled(enabled)
        self.ui.tbOverlay.setEnabled(enabled)
        self.ui.sliderOverlay.setEnabled(enabled)

        self.ui.widgetDistPlot.setEnabled(enabled)

    def loadFile(self, filename):
        self.ui.tbFilename.setText(filename)

        self.GF = Green(filename)

        if not self.validateGreensFunction(self.GF):
            return

        self.toggleEnabled(True)
        if len(self.GF._param2.shape) == 2:
            self.pitchAngles = np.abs(self.GF._param2[0])
        else:
            self.pitchAngles = np.abs(self.GF._param2)

        self.cosPitchAngles = np.cos(self.pitchAngles)

        # Sum all pixels of each image
        self.GFintensity = np.sum(self.GF.FUNC, axis=(2, 3)) * np.sin(
            self.pitchAngles)

        self.setupEnergySlider()
        self.setupSuperPlot()
        self.setupImage()

        f = self.getDistributionFunction()
        self.updateSuperPlot(f=f)
        self.updateImage(f=f)

    def loadOverlay(self, filename):
        self.ui.tbOverlay.setText(filename)
        self.overlay = mpimg.imread(filename)

        self.setupOverlay()

    def openFile(self):
        filename, _ = QFileDialog.getOpenFileName(
            parent=self,
            caption="Open SOFT Green's function file",
            filter="SOFT Green's function (*.mat *.h5 *.hdf5);;All files (*.*)"
        )

        if filename:
            self.loadFile(filename)

    def openOverlay(self):
        filename, _ = QFileDialog.getOpenFileName(
            parent=self,
            caption="Open image overlay",
            filter="Portable Network Graphics (*.png)")

        if filename:
            self.loadOverlay(filename)

    def validateGreensFunction(self, gf):
        if gf.getFormat() != '12ij':
            QMessageBox.critical(
                self, 'Invalid input file',
                "The specified Green's function is not of the appropriate format. Expected '12ij', got '{0}'."
                .format(gf.getFormat()))
            return False

        pn = gf.getParameterName('1')
        if pn != 'gamma' and pn != 'p':
            QMessageBox.critical(
                self, 'Invalid input file',
                "The first momentum parameter has an invalid type: '{0}'. Expected either 'gamma' or 'p'."
                .format(pn))
            return False

        return True

    def saveImage(self):
        self.doSaveImage()

    def saveSuper(self):
        self.doSaveSuper()

    def doSaveImage(self, filename=None):
        if filename is None:
            filename, _ = QFileDialog.getSaveFileName(
                self,
                caption='Save synthetic image',
                filter=
                'Portable Document Form (*.pdf);;Portable Network Graphics (*.png);;Encapsulated Post-Script (*.eps);;Scalable Vector Graphics (*.svg)'
            )

        if not filename:
            return

        self.imageAx.set_axis_off()
        self.plotWindow.figure.subplots_adjust(top=1,
                                               bottom=0,
                                               right=1,
                                               left=0,
                                               hspace=0,
                                               wspace=0)

        self.imageAx.get_xaxis().set_major_locator(
            matplotlib.ticker.NullLocator())
        self.imageAx.get_yaxis().set_major_locator(
            matplotlib.ticker.NullLocator())

        fcolor = self.plotWindow.figure.patch.get_facecolor()

        self.plotWindow.canvas.print_figure(filename,
                                            bbox_inches='tight',
                                            pad_inches=0,
                                            dpi=300)

    def doSaveSuper(self, filename=None):
        if filename is None:
            filename, _ = QFileDialog.getSaveFileName(
                self,
                caption='Save super particle',
                filter=
                'Portable Document Form (*.pdf);;Portable Network Graphics (*.png);;Encapsulated Post-Script (*.eps);;Scalable Vector Graphics (*.svg)'
            )

        if not filename:
            return

        self.superPlotCanvas.print_figure(filename, bbox_inches='tight')

    def saveBoth(self):
        filename, _ = QFileDialog.getSaveFileName(
            self,
            caption='Save both figures',
            filter=
            'Portable Document Form (*.pdf);;Portable Network Graphics (*.png);;Encapsulated Post-Script (*.eps);;Scalable Vector Graphics (*.svg)'
        )

        if not filename:
            return

        f = filename.split('.')
        filename = str.join('.', f[:-1])
        ext = f[-1]

        if filename.endswith('_image') or filename.endswith('_super'):
            filename = filename[:-6]

        imgname = filename + '_image.' + ext
        supname = filename + '_super.' + ext

        self.doSaveImage(filename=imgname)
        self.doSaveSuper(filename=supname)

    def setupEnergySlider(self):
        if len(self.GF._param1.shape) == 2:
            vmin, vmax, vn = self.GF._param1[0][0], self.GF._param1[0][
                -1], self.GF._param1[0].size
        else:
            vmin, vmax, vn = self.GF._param1[0], self.GF._param1[
                -1], self.GF._param1.size

        if self.GF.getParameterName('1') == 'gamma':
            self.ui.lblREEnergy.setText('Runaway energy (mc²)')
        else:
            self.ui.lblREEnergy.setText('Runaway momentum (mc)')

        self.ui.lblEnergyMin.setText('{0:.2f}'.format(vmin))
        self.ui.lblEnergyMax.setText('{0:.2f}'.format(vmax))
        self.ui.lblEnergy.setText('{0:.2f}'.format(vmin))

        self.ui.sliderEnergy.setMinimum(0)
        self.ui.sliderEnergy.setMaximum(vn - 1)
        self.ui.sliderEnergy.setSingleStep(1)

    def getEnergyIndex(self):
        return self.ui.sliderEnergy.value()

    def setupImage(self):
        lbl = ''.join(random.choices(string.ascii_uppercase, k=4))
        self.imageAx = self.plotWindow.figure.add_subplot(111, label=lbl)

        a = 1
        if self.overlayHandle is not None:
            self.setupOverlay()
            if not self.ui.cbUnderlay.isChecked():
                a = 1 - (self.ui.sliderOverlay.value()) / 100.0

        dummy = np.zeros(self.GF._pixels)
        self.imageHandle = self.imageAx.imshow(dummy,
                                               cmap=self.gerimap,
                                               alpha=a,
                                               interpolation=None,
                                               clim=(0, 1),
                                               extent=[-1, 1, -1, 1],
                                               zorder=1)
        self.imageAx.get_xaxis().set_visible(False)
        self.imageAx.get_yaxis().set_visible(False)

        if not self.plotWindow.isVisible():
            self.plotWindow.show()

        self.plotWindow.drawSafe()

    def setupOverlay(self):
        if self.overlayHandle is not None:
            self.overlayHandle.remove()

        self.overlayHandle = self.imageAx.imshow(self.overlay,
                                                 extent=[-1, 1, -1, 1],
                                                 zorder=0)
        self.updateImage()
        self.plotWindow.drawSafe()

    def toggleOverlayType(self):
        ic = self.ui.cbUnderlay.isChecked()
        if not ic:
            self.gerimap, _ = registerGeriMap(None)
        else:
            self.gerimap, _ = registerGeriMap(transparencyThreshold=0.25)

        self.ui.sliderOverlay.setEnabled(not ic)
        self.ui.lblOverlayMin.setEnabled(not ic)
        self.ui.lblOverlay25.setEnabled(not ic)
        self.ui.lblOverlay50.setEnabled(not ic)
        self.ui.lblOverlay75.setEnabled(not ic)
        self.ui.lblOverlayMax.setEnabled(not ic)

        self.setupImage()

        f = self.getDistributionFunction()
        self.updateSuperPlot(f=f)
        self.updateImage(f=f)

    def overlaySliderChanged(self):
        self.updateImage()

    def updateImage(self, f=None):
        ei = self.getEnergyIndex()

        if f is None:
            f = self.getDistributionFunction()

        g = self.GF[ei, :, :, :]
        I = 0
        for i in range(0, f.size):
            I += g[i, :, :] * f[i]

        I = I.T / np.amax(I)

        self.imageHandle.set_data(I)

        if self.ui.cbUnderlay.isChecked() or self.overlayHandle is None:
            self.imageHandle.set_alpha(1)
        else:
            a = float(self.ui.sliderOverlay.value()) / 100.0
            self.imageHandle.set_alpha(1 - a)

        self.plotWindow.drawSafe()
예제 #15
0
class GreensFunctionIJ(QtWidgets.QMainWindow):

    WIDTH = 550
    HEIGHT = 450

    def __init__(self, argv):
        QtWidgets.QMainWindow.__init__(self)

        self.setupUi()

        if len(argv) != 1:
            raise Exception(
                "The Green's function must be specified at startup")

        self.filename = argv[0]

        # Create plot window
        self.plotWindow = PlotWindow()

        self.imageAx = None
        self.overlayHandle = None

        # Combobox used for select polarization quantity to plot
        self.stokesbox = None

        # Overlay controls
        self.tbOverlay = None
        self.btnOverlay = None
        self.lblOverlaySlider = None
        self.sliderOverlay = None

        # Load Green's function
        self.gf = Green(filename=self.filename)
        nparams, dims = self.classifyGreensFunction(self.gf)

        self.buildControls(dims, self.gf)
        self.setDetails()

        self.setWindowTitle("Green's function with image")
        self.setupImage()

    def closeEvent(self, event):
        self.exit()

    def exit(self):
        self.plotWindow.close()
        self.close()

    def buildControls(self, dims, gf):
        i = 0
        for d in dims:
            if d == '1':
                self.buildControl(index=i,
                                  coordname=self.getCoordinateName(
                                      gf._param1name),
                                  vals=gf._param1)
            elif d == '2':
                self.buildControl(index=i,
                                  coordname=self.getCoordinateName(
                                      gf._param2name),
                                  vals=gf._param2)
            elif d == 'r':
                self.buildControl(index=i, coordname='Radius', vals=gf._r)
            elif d == 's':
                self.buildStokes(index=i, coordname='Polarization quantity')
            elif d == 'w':
                self.buildControl(index=i,
                                  coordname='Wavelength',
                                  vals=gf._wavelengths)
            else:
                raise Exception(
                    "Unrecognized or unsupported Green's function format: '{}'."
                    .format(d))

            i += 1

        self.buildOverlay(index=i)

    def buildControl(self, index, coordname, vals):
        vmin = np.amin(vals)
        vmax = np.amax(vals)
        vn = vals.size
        self.paramValues.append(vals)

        gb = QtWidgets.QGroupBox(self.centralwidget)
        gb.setTitle(coordname)
        self.controlGroupboxes.append(gb)

        vl = QtWidgets.QVBoxLayout(gb)

        lbl = QtWidgets.QLabel(gb)
        font = QtGui.QFont()
        font.setPointSize(14)
        lbl.setFont(font)
        lbl.setText('{}'.format(vmin))
        lbl.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing
                         | QtCore.Qt.AlignVCenter)
        self.paramLabels.append(lbl)

        hs = QtWidgets.QSlider(gb)
        hs.setOrientation(QtCore.Qt.Horizontal)
        hs.setMinimum(0)
        hs.setMaximum(vn - 1)
        hs.setTickPosition(QtWidgets.QSlider.TicksBelow)
        hs.setTickInterval(1)
        self.paramSliders.append(hs)

        hs.valueChanged.connect(self.sliderChanged)

        vl.addWidget(lbl)
        vl.addWidget(hs)

        # Insert groupbox into window
        idx = self.verticalLayout.count() - 1
        self.verticalLayout.insertWidget(idx, gb)

        self.HEIGHT += gb.height()
        self.resize(self.WIDTH, self.HEIGHT)

    def buildOverlay(self, index):
        hl = QtWidgets.QHBoxLayout()

        lbl = QtWidgets.QLabel(self.centralwidget)
        lbl.setText("Overlay:")

        tb = QtWidgets.QLineEdit(self.centralwidget)
        tb.setReadOnly(True)
        self.tbOverlay = tb

        btn = QtWidgets.QPushButton(self.centralwidget)
        btn.setText('Browse...')
        self.btnOverlay = btn
        self.btnOverlay.clicked.connect(self.openOverlay)

        lblOverlaySlider = QtWidgets.QLabel(self.centralwidget)
        lblOverlaySlider.setText('50%')
        lblOverlaySlider.setAlignment(QtCore.Qt.AlignRight)
        self.lblOverlaySlider = lblOverlaySlider

        slider = QtWidgets.QSlider(self.centralwidget)
        slider.setOrientation(QtCore.Qt.Horizontal)
        slider.setMinimum(0)
        slider.setMaximum(100)
        slider.setValue(50)
        slider.setTickPosition(QtWidgets.QSlider.TicksBelow)
        slider.setTickInterval(5)
        self.sliderOverlay = slider

        slider.valueChanged.connect(self.sliderOverlayChanged)

        hl.addWidget(tb)
        hl.addWidget(btn)

        self.verticalLayout.addWidget(lbl)
        self.verticalLayout.addLayout(hl)
        self.verticalLayout.addWidget(lblOverlaySlider)
        self.verticalLayout.addWidget(slider)

        self.HEIGHT += tb.height() + lbl.height() + slider.height(
        ) + lblOverlaySlider.height()
        self.resize(self.WIDTH, self.HEIGHT)

    def buildStokes(self, index, coordname):
        cb = QtWidgets.QComboBox(self.centralwidget)
        self.stokesbox = cb

        cb.addItem("Polarization angle")
        cb.addItem("Polarization fraction")
        cb.addItem("Stokes I")
        cb.addItem("Stokes Q")
        cb.addItem("Stokes U")
        cb.addItem("Stokes V")

        cb.setCurrentIndex(2)
        cb.currentIndexChanged.connect(self.redrawFigure)

        self.verticalLayout.insertWidget(index, cb)

        self.HEIGHT += cb.height()
        self.resize(self.WIDTH, self.HEIGHT)

    def classifyGreensFunction(self, gf):
        dims = gf.format

        if dims[-2] != 'i' or dims[-1] != 'j':
            raise Exception(
                "Invalid format of Green's function. Format string must end in 'ij'."
            )

        # Just pick out the interesting dimensions
        dims = dims[:-2]
        nparams = len(dims)

        # Append Stoke's dimension?
        if gf.stokesparams:
            dims = 's' + dims
            nparams += 1

        return nparams, dims

    def getCoordinateName(self, s):
        """
        Converts a SOFT parameter name to a proper parameter label.
        """
        if s == "gamma": return "Energy (γ)"
        elif s == "p": return "Momentum (p)"
        elif s == "ppar": return "Parallel momentum"
        elif s == "pperp": return "Perpendicular momentum"
        elif s == "thetap": return "Pitch angle (θ)"
        elif s == "ithetap": return "Pitch angle (θ)"
        elif s == "xi": return "Pitch (ξ)"
        else: return "<UNKNOWN>"

    def getSelectedGreensFunction(self):
        """
        Returns the appropriate image to draw based on
        how the GUI controls are set.
        """
        Fmax, Fmin = None, 0
        F = self.gf.FUNC
        colormap = 'GeriMap'

        # Compute select polarization quantity
        if self.stokesbox is not None:
            val = self.stokesbox.currentText()

            if val == "Polarization angle":
                F = 0.5 * np.arctan2(F[2], F[1]) * 180 / np.pi
                F[np.where(F < -45)] += 180
                Fmax, Fmin = 135, -45
                colormap = 'RdBu'
            elif val == "Polarization fraction":
                F = np.sqrt(F[1]**2 + F[2]**2) / F[0]
                F[np.where(np.isnan(F))] = 0
                Fmax = 1
            elif val == "Stokes I":
                F = F[0]
            elif val == "Stokes Q":
                F = F[1]
                fmax = max(abs(np.amax(F)), abs(np.amin(F)))
                Fmax, Fmin = fmax, -fmax
                colormap = 'RdBu'
            elif val == "Stokes U":
                F = F[2]
                fmax = max(abs(np.amax(F)), abs(np.amin(F)))
                Fmax, Fmin = fmax, -fmax
                colormap = 'RdBu'
            elif val == "Stokes V":
                F = F[3]
                fmax = max(abs(np.amax(F)), abs(np.amin(F)))
                Fmax, Fmin = fmax, -fmax
                colormap = 'RdBu'
            else:
                raise Exception(
                    "INTERNAL ERROR: Unrecognized polarization quantity select: '{}'."
                    .format(val))

        if self.wfgb.isChecked():  # Draw with weight function
            print('Not supported yet...')
            return np.zeros(self.gf._pixels)
        else:
            indices = list()
            for s in self.paramSliders:
                F = F[s.value()]

            if len(F.shape) != 2:
                raise Exception(
                    'INTERNAL ERROR: F does not have the expected shape.')

            if Fmax is None:
                F /= np.amax(F)
                Fmax = 1

            return F.T, Fmax, Fmin, colormap

    def loadOverlay(self, filename):
        self.tbOverlay.setText(filename)
        self.overlay = mpimg.imread(filename)

        self.setupOverlay()

    def openOverlay(self):
        filename, _ = QFileDialog.getOpenFileName(
            parent=self,
            caption="Open image overlay",
            filter="Portable Network Graphics (*.png)")

        if filename:
            self.loadOverlay(filename)

    def redrawFigure(self):
        F, Fmax, Fmin, cmap = self.getSelectedGreensFunction()
        self.imageHandle.set_data(F)
        self.imageHandle.set_clim(vmin=Fmin, vmax=Fmax)
        self.imageHandle.set_cmap(cmap)
        self.plotWindow.drawSafe()

    def setDetails(self):
        self.lblFilename.setText(self.filename)

        # Green's function size
        totsize = self.gf.FUNC.size * 8
        fsize = totsize
        prefixes = ['ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi']
        pfi = -1
        while fsize > 1024:
            fsize /= 1024.0
            pfi += 1

        prefix = ''
        if pfi >= 0:
            prefix = prefixes[pfi]

        self.lblGFSize.setText('{:.1f} {:s}B ({:d} bytes)'.format(
            fsize, prefix, totsize))

        # Format
        self.lblFormat.setText(self.gf.format)

        # Number of pixels
        hpix, vpix = self.gf._pixels[0], self.gf._pixels[1]
        self.lblPixels.setText('{} × {} pixels'.format(hpix, vpix))

    def setupImage(self):
        self.imageAx = self.plotWindow.figure.add_subplot(111)

        F, Fmax, Fmin, cmap = self.getSelectedGreensFunction()
        self.imageHandle = self.imageAx.imshow(F,
                                               cmap=cmap,
                                               interpolation=None,
                                               clim=(Fmin, Fmax),
                                               extent=[-1, 1, -1, 1])
        self.imageAx.get_xaxis().set_visible(False)
        self.imageAx.get_yaxis().set_visible(False)

        self.colorbar = self.plotWindow.figure.colorbar(self.imageHandle,
                                                        ax=self.imageAx)

        if not self.plotWindow.isVisible():
            self.plotWindow.show()

        self.plotWindow.drawSafe()

    def setupOverlay(self):
        if self.overlayHandle is not None:
            self.overlayHandle.remove()

        val = self.sliderOverlay.value() / 100.0
        self.overlayHandle = self.imageAx.imshow(self.overlay,
                                                 alpha=val,
                                                 extent=[-1, 1, -1, 1],
                                                 zorder=100)
        self.plotWindow.drawSafe()

    def setupUi(self):
        self.resize(self.WIDTH, self.HEIGHT)

        self.centralwidget = QtWidgets.QWidget(self)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)

        # Control groupboxes
        self.controlGroupboxes = list()
        self.paramLabels = list()
        self.paramSliders = list()
        self.paramValues = list()

        # Information groupbox
        gb = QtWidgets.QGroupBox(self.centralwidget)
        gb.setTitle("Green's function details")

        # (declare labels)
        self.lblFilename = QtWidgets.QLabel(gb)
        self.lblGFSize = QtWidgets.QLabel(gb)
        self.lblFormat = QtWidgets.QLabel(gb)
        self.lblPixels = QtWidgets.QLabel(gb)

        vli = QtWidgets.QVBoxLayout(gb)

        h1 = QtWidgets.QHBoxLayout()
        h1.addWidget(QtWidgets.QLabel('File name:', gb))
        h1.addWidget(self.lblFilename)

        h2 = QtWidgets.QHBoxLayout()
        h2.addWidget(QtWidgets.QLabel('Function size: ', gb))
        h2.addWidget(self.lblGFSize)

        h3 = QtWidgets.QHBoxLayout()
        h3.addWidget(QtWidgets.QLabel('Pixels:', gb))
        h3.addWidget(self.lblPixels)

        h4 = QtWidgets.QHBoxLayout()
        h4.addWidget(QtWidgets.QLabel('Format: ', gb))
        h4.addWidget(self.lblFormat)

        vli.addLayout(h1)
        vli.addLayout(h2)
        vli.addLayout(h3)
        vli.addLayout(h4)

        # Distribution function window
        self.wfgb = QtWidgets.QGroupBox(self.centralwidget)
        self.wfgb.setCheckable(True)
        self.wfgb.setChecked(False)
        self.wfgb.setTitle('Weight function')

        vl = QtWidgets.QVBoxLayout(self.wfgb)

        font = QtGui.QFont()
        font.setFamily("Droid Sans Mono")

        txt = QtWidgets.QPlainTextEdit(self.wfgb)
        txt.setFont(font)
        txt.setMaximumSize(QtCore.QSize(16777215, 300))

        frm = QtWidgets.QFrame(self.wfgb)
        frm.setMinimumSize(QtCore.QSize(0, 200))
        frm.setFrameShape(QtWidgets.QFrame.StyledPanel)
        frm.setFrameShadow(QtWidgets.QFrame.Raised)

        vl.addWidget(txt)
        vl.addWidget(frm)

        self.verticalLayout.addWidget(gb)
        self.verticalLayout.addWidget(self.wfgb)
        self.setCentralWidget(self.centralwidget)

        self.wfgb.toggled.connect(self.toggleWeightFunction)

    def sliderChanged(self):
        for i in range(0, len(self.paramSliders)):
            idx = self.paramSliders[i].value()
            val = self.paramValues[i][idx]
            self.paramLabels[i].setText('{}'.format(val))

        self.redrawFigure()

    def sliderOverlayChanged(self):
        val = self.sliderOverlay.value() / 100.0
        self.lblOverlaySlider.setText('{}%'.format(self.sliderOverlay.value()))

        if self.overlayHandle is not None:
            self.overlayHandle.set_alpha(val)

        self.plotWindow.drawSafe()

    def toggleWeightFunction(self):
        for gb in self.controlGroupboxes:
            gb.setEnabled(not self.wfgb.isChecked())