diff -Nru navarp-1.0.0/CHANGELOG.rst navarp-1.3.0/CHANGELOG.rst --- navarp-1.0.0/CHANGELOG.rst 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/CHANGELOG.rst 2021-12-15 13:48:00.000000000 +0000 @@ -1,6 +1,82 @@ Changelog ========== +1.3.0: 2021/12/15 +------------------ +This version includes the possibility to rotate the isoenergy once shown, adds the loading support for MBS-krx single image acquisition and fix the loading of single scienta txt and hv_scan once loaded with a yaml-file. +Below a list of the main changes divided by modules: + +* `utils.navfile`: + + * Added support for MBS-krx single image acquisition; + * Fix load single scienta txt file; + * Fix loading hv scan collection of files using yaml-file. + +* `utils.isomclass`: + * Added rotate in isoenergy show method. + +* `examples`: + * Added example on isoenergy rotation in graphene deflector scan. + +1.2.0: 2021/11/23 +------------------ +This version includes many fix, a revision of the documentations and the following new features: (i) support to the new MBS-krx file the lorea NxARPES-file; (ii) the minimum gradient method as post-processing procedure. +Below a list of the main changes divided by modules: + +* `navarp_gui.py`: + + * Added post-processing procedure with order=1, which is the min minimum gradient method. + +* `utils.navfile`: + + * Fixed I05 file loading; + * Added new MBS-krx 64 bit file keeping the compatibility with the 32 bit one; + * Added tht_an and kspace in the yaml-file for loading already transformed data. + +* `utils.isomclass`: + + * Transpose data in isok export as nexus. + + +1.1.0: 2021/04/11 +------------------ + +This version includes very interesting new features as: (i) exporting the analyzed data on top or bottom panels as NXdata, or Igor Pro Text file, or HD5F; (ii) post-processing procedures as second derivative (in one direction), Laplace filter (if both direction are considered), curvature (only in one direction at the moment), Gaussian filter. Below a list of the main changes divided by modules: + +* `navarp_gui.py`: + + * Added post-processing procedure; + * Added panel for exporting the data; + * Use isomclass when possible; + * Removed the boolean variable in the analyzer panel called deflector because useless. + * Write efermi in the gui line edit when file loaded. + +* `utils.navfile`: + + * Removed the last angle value if angle array has the same length of energies; + * Fixed I05 file loading; + * Removed the boolean variable in NavAnalyzer called deflector because useless. + +* `utils.isomclass` (new file): + + * Fix isoenergy export as itx by transposing data. + * Fix export as NXdata and Igor-pro text file. + * Add postprocessing function and use it in all the isomclass. + * Use laplace filter if sigma has two values and use curvature only for sigma with one value. + * Rename file_path_* as file_path in all the export_as_* of the isomclass. + +* `utils.kinterp`: + + * In get_isoscan, use np.nan in fill_value instead of extrapolate because it is not correct to extrapolate data. + +* INTALLATION.rst: + + * The installation instruction of the master branch are now based on the PyPI package. + +* UPDATE.rst: + + * The update instruction of the master branch are now based on the PyPI package. + 1.0.0: 2021/04/11 ------------------ @@ -16,7 +92,7 @@ * Added support for krx-MBS file format; * Added support for ibw file format as saved by Scienta-Omicron SES program; * Added support for txt-Scienta file format with 3 dimensions; - * Added support for igor-pro text file format (saved as .itx or .txt); + * Added support for igor-pro text file format (saved as .itx or .txt); * Loading speed of about x3 faster for txt-based file input (txt from Scienta and MBS, sp2 from Specs); * Added set_efermi method to NavEntry to set the efermi of the entry object; * Added autoset_efermi method to NavEntry to automatically found the efermi by curve fitting; @@ -84,7 +160,7 @@ * `navarp.py`: * Added .navarp configuration file saved in the local user home - * Set the initial default value of k-transf to be without photons contribution + * Set the initial default value of k-transf to be without photons contribution * `utils.navfile`: diff -Nru navarp-1.0.0/CONTRIBUTING.rst navarp-1.3.0/CONTRIBUTING.rst --- navarp-1.0.0/CONTRIBUTING.rst 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/CONTRIBUTING.rst 2021-12-15 13:48:00.000000000 +0000 @@ -59,24 +59,26 @@ Ready to contribute? Here's how to set up `navarp` for local development. -1. Fork the `navarp` repo on GitLab. -2. Clone your fork locally:: +1. Create a dedicated conda environment (for example navarp-env):: - $ git clone git@gitlab.com:your_name_here/navarp.git + $ conda create --name navarp-env numpy scipy matplotlib colorcet h5py pyqt=5 jupyter pyyaml click + $ conda activate navarp-env + $ conda install -c conda-forge igor git -3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: +2. Fork the `navarp` repo on GitLab. +3. Move in the folder where you want to have the package and clone your fork locally by running:: - $ mkvirtualenv navarp - $ cd navarp/ - $ python setup.py develop + $ git clone git@gitlab.com:your_name_here/navarp.git + $ cd navarp/ + $ pip install -e . 4. Create a branch for local development:: $ git checkout -b name-of-your-bugfix-or-feature - Now you can make your changes locally. + Now you can make your changes locally and it will affect the navarp program as long as you stay in this enviroment (in this example is navarp-env). -5. When you're done making changes, check the code by using navarp.py and/or running the examples. +5. When you're done making changes, check the code by using navarp and/or running the examples. 6. Commit your changes and push your branch to GitLab:: diff -Nru navarp-1.0.0/debian/changelog navarp-1.3.0/debian/changelog --- navarp-1.0.0/debian/changelog 2021-11-17 14:11:48.000000000 +0000 +++ navarp-1.3.0/debian/changelog 2021-12-21 13:01:13.000000000 +0000 @@ -1,6 +1,18 @@ +navarp (1.3.0-1) unstable; urgency=medium + + [ Neil Williams ] + * Change d.watch file to use modified gitlab mangling + * Update control to add Debian PaN maintainers + + [ Picca Frédéric-Emmanuel ] + * d/watch: fixed to obtain the latest version. + * New upstream version 1.3.0 + + -- Picca Frédéric-Emmanuel Tue, 21 Dec 2021 14:01:13 +0100 + navarp (1.0.0-2) unstable; urgency=medium - * Source-only upload to migrate to testing. + * Source-only upload to migrate to testing. -- Neil Williams Wed, 17 Nov 2021 14:11:48 +0000 diff -Nru navarp-1.0.0/debian/control navarp-1.3.0/debian/control --- navarp-1.0.0/debian/control 2021-10-08 12:10:46.000000000 +0000 +++ navarp-1.3.0/debian/control 2021-12-21 13:01:13.000000000 +0000 @@ -1,8 +1,9 @@ Source: navarp Section: science Priority: optional -Maintainer: Debian Science Maintainers +Maintainer: Debian PaN Maintainers Uploaders: + Debian Science Maintainers , Neil Williams , Picca Frédéric-Emmanuel , Build-Depends: diff -Nru navarp-1.0.0/debian/watch navarp-1.3.0/debian/watch --- navarp-1.0.0/debian/watch 2021-09-30 14:29:33.000000000 +0000 +++ navarp-1.3.0/debian/watch 2021-12-21 13:01:13.000000000 +0000 @@ -3,6 +3,5 @@ # GitLab # https://gitlab.com/fbisti/navarp/-/archive/v1.0.0/navarp-v1.0.0.tar.gz -# this may only work after the package has been uploaded. -https://qa.debian.org/cgi-bin/fakeupstream.cgi?upstream=gitlab_releases/fbisti/navarp \ -.*/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ + +https://gitlab.com/fbisti/navarp/tags?sort=updated_desc .*v(\d\S+)\.tar\.gz diff -Nru navarp-1.0.0/docs/conf.py navarp-1.3.0/docs/conf.py --- navarp-1.0.0/docs/conf.py 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/docs/conf.py 2021-12-15 13:48:00.000000000 +0000 @@ -13,21 +13,20 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -import os -import sys -sys.path.insert(0, os.path.abspath('../navarp/utils/.')) +# import os +# import sys # -- Project information ----------------------------------------------------- project = 'navarp' -copyright = '2020, Federico Bisti' +copyright = '2021, Federico Bisti' author = 'Federico Bisti' # The short X.Y version version = '' # The full version, including alpha/beta/rc tags -release = '1.0.0' +release = '1.3.0' # -- General configuration --------------------------------------------------- @@ -77,7 +76,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'classic' +html_theme = 'alabaster' html_logo = '../navarp/gui/icons/navarp.svg' @@ -86,14 +85,14 @@ # further. For a list of options available for each theme, see the # documentation. # -html_theme_options = { - "sidebarbgcolor": "whitesmoke", - "sidebartextcolor": "black", - "sidebarlinkcolor": "black", - "relbarbgcolor": "#003380", - "footerbgcolor": "white", - "footertextcolor": "black" -} +# html_theme_options = { +# "sidebarbgcolor": "whitesmoke", +# "sidebartextcolor": "black", +# "sidebarlinkcolor": "black", +# "relbarbgcolor": "#003380", +# "footerbgcolor": "white", +# "footertextcolor": "black" +# } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -108,8 +107,9 @@ # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', # 'searchbox.html']``. # -# html_sidebars = {} - +html_sidebars = { + '**': ['globaltoc.html', 'sourcelink.html', 'searchbox.html'], +} # -- Options for HTMLHelp output --------------------------------------------- diff -Nru navarp-1.0.0/docs/index.rst navarp-1.3.0/docs/index.rst --- navarp-1.0.0/docs/index.rst 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/docs/index.rst 2021-12-15 13:48:00.000000000 +0000 @@ -3,22 +3,19 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Homepage +NavARP documentation ------------------------------- -Abstract -================================== - **Nav**\ igation tools for **A**\ ngle **R**\ esolved **P**\ hotoemission spectroscopy data, *i.e.*: * a **companion app** during ARPES data acquitision (as in beamtime); - * a set of **dedicated libs** helping to get high quality figures for publication. + * a set of **dedicated python libs** helping to get high quality figures for publication. *By Federico Bisti, University of L'Aquila, Italy.* .. image:: ../images/intro.gif - :width: 400 + :width: 100% -Contents +Table of Contents ================================== .. toctree:: @@ -27,19 +24,17 @@ installation update usage + auto_examples/index authors contributing changelog -Examples -============== +API reference +================== .. toctree:: :maxdepth: 2 - auto_examples/index - -API reference -================== + utils * :ref:`genindex` * :ref:`modindex` diff -Nru navarp-1.0.0/docs/utils.rst navarp-1.3.0/docs/utils.rst --- navarp-1.0.0/docs/utils.rst 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/docs/utils.rst 2021-12-15 13:48:00.000000000 +0000 @@ -1,7 +1,10 @@ +API - navarp.utils +******************* + fermilevel ------------------------------ -.. automodule:: fermilevel +.. automodule:: navarp.utils.fermilevel :members: :undoc-members: :show-inheritance: @@ -9,7 +12,7 @@ isocut ------------------------------ -.. automodule:: isocut +.. automodule:: navarp.utils.isocut :members: :undoc-members: :show-inheritance: @@ -17,7 +20,7 @@ isomclass ------------------------------ -.. automodule:: isomclass +.. automodule:: navarp.utils.isomclass :members: :undoc-members: :show-inheritance: @@ -25,7 +28,7 @@ kinterp ------------------------------ -.. automodule:: kinterp +.. automodule:: navarp.utils.kinterp :members: :undoc-members: :show-inheritance: @@ -33,7 +36,7 @@ ktransf ------------------------------ -.. automodule:: ktransf +.. automodule:: navarp.utils.ktransf :members: :undoc-members: :show-inheritance: @@ -41,7 +44,7 @@ navfile ------------------------------ -.. automodule:: navfile +.. automodule:: navarp.utils.navfile :members: :undoc-members: :show-inheritance: @@ -49,7 +52,7 @@ navplt ------------------------------ -.. automodule:: navplt +.. automodule:: navarp.utils.navplt :members: :undoc-members: :show-inheritance: diff -Nru navarp-1.0.0/examples/plot_gr_deflector_scan.py navarp-1.3.0/examples/plot_gr_deflector_scan.py --- navarp-1.0.0/examples/plot_gr_deflector_scan.py 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/examples/plot_gr_deflector_scan.py 2021-12-15 13:48:00.000000000 +0000 @@ -107,11 +107,14 @@ entry.isoscan(0).show() # %% + +# sphinx_gallery_thumbnail_number = 7 + entry.isoenergy(0).show() # %% # I can also place together in a single figure different images: -# sphinx_gallery_thumbnail_number = 5 + fig, axs = plt.subplots(1, 2) @@ -121,6 +124,39 @@ plt.tight_layout() # %% +# For the isoenergy case, I can also rotate the image around its origin. +# Which can be useful sometime if the sample was not exactly aligned during +# the data acquisition. Or if you are a fun on what I consider as a very +# bad practice, you can repeat the same image at each symmetric point. + +fig, axs = plt.subplots(2, 2, constrained_layout=True) + +ax = axs[0][0] +entry.isoenergy(0).show(ax=ax) +ax.set_title('No rotation'.format()) + +rot_ang = 30 +ax = axs[0][1] +ax.set_title('Rotation of {} degrees'.format(rot_ang)) +entry.isoenergy(0).show(ax=ax, rotate=rot_ang) + +rot_ang = 90 +ax = axs[1][0] +ax.set_title('Rotation of {} degrees'.format(rot_ang)) +entry.isoenergy(0).show(ax=ax, rotate=rot_ang) + +rot_angs = [0, 60, 120, 180, 240, 300] +ax = axs[1][1] +ax.set_title('Repetition at every 60 degrees') +isoen_fs = entry.isoenergy(0) +for rot_ang in rot_angs: + isoen_fs.show(ax=ax, rotate=rot_ang) + +for ax in axs.ravel(): + ax.set_aspect('equal') + + +# %% # Many other options: # ^^^^^^^^^^^^^^^^^^^ diff -Nru navarp-1.0.0/examples/plot_postprocessing_isoscan.py navarp-1.3.0/examples/plot_postprocessing_isoscan.py --- navarp-1.0.0/examples/plot_postprocessing_isoscan.py 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/examples/plot_postprocessing_isoscan.py 2021-12-15 13:48:00.000000000 +0000 @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- """ -Export isoenergy at the Fermi level +Postprocessing on isoscan ==================================== -Simple workflow for exporting the isoenergy at the Fermi level. +Example of isoscan postprocessing procedures. The data are a deflector scan on graphene as simulated from a third nearest neighbor tight binding model. The same workflow can be applied to any tilt-, polar-, deflector- or hv-scan.""" @@ -73,14 +73,14 @@ # energy axis: # sphinx_gallery_thumbnail_number = 3 -entry.isoscan(0, sigma=[0, 5]).show() +entry.isoscan(0, sigma=[3, 5]).show() # %% # Only the Gaussian filtered image can be obtained using again sigma but also # specifying the order=0, which by default is equal to 2 giving the second # derivative as before.: -entry.isoscan(0, sigma=[3, 5], order=0).show() +entry.isoscan(0, sigma=[10, 10], order=0).show() # %% # To export it as NXdata class of the nexus format uncomment this line: Binary files /tmp/tmp4mv2ak9v/UzAkcub2g4/navarp-1.0.0/images/intro.gif and /tmp/tmp4mv2ak9v/RNCDaBJugt/navarp-1.3.0/images/intro.gif differ diff -Nru navarp-1.0.0/INSTALLATION.rst navarp-1.3.0/INSTALLATION.rst --- navarp-1.0.0/INSTALLATION.rst 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/INSTALLATION.rst 2021-12-15 13:48:00.000000000 +0000 @@ -4,90 +4,104 @@ Installation ============ -Download and install the last Anaconda distribution for Python 3.x from -`here`_, it can be installed with or without admin privilege (just remind the +First, download Anaconda +-------------------------- + +Download and install the last Anaconda distribution for Python 3.x from +`here`_, it can be installed with or without admin privilege (just remind the chosen option for later). .. _here: https://www.anaconda.com/distribution/#download-section -After installation, few commands must be run in the proper **command line -interface** before being able to use the NavARP package, and this **command +Command line interface +************************* + +After installation, few commands must be run in the proper **command line +interface** before being able to use the NavARP package, and this **command line interface** depends on the operating system. -The **command line interface** corresponds to the **Anaconda Prompt** on -Windows (that can be found in the Start menu after searching Anaconda Prompt -or after opening the Anaconda Navigator), and to the **terminal** on macOS and +The **command line interface** corresponds to the **Anaconda Prompt** on +Windows (that can be found in the Start menu after searching Anaconda Prompt +or after opening the Anaconda Navigator), and to the **terminal** on macOS and Linux. -Regarding macOS, it might happen that after Anaconda installation the default -Python version accessible from the terminal is still the default one from -macOS (so not the one related to the Anaconda distribution). To check if it -is the case, type and run ``python --version`` in the terminal. If the word -``Anaconda`` is not the printed lines, then Python is not of Anaconda and the -installation cannot continue. To fix it, you can change the python environment -by typing ``conda activate``. Or (at your risk!), you can try to change your -``.bash_profile`` making sure that the Anaconda directory is the first one in +Regarding **macOS**, it might happen that after Anaconda installation the default +Python version accessible from the terminal is still the default one from +macOS (so not the one related to the Anaconda distribution). To check if it +is the case, type and run ``python --version`` in the terminal. If the word +``Anaconda`` is not the printed lines, then Python is not of Anaconda and the +installation cannot continue. To fix it, you can change the python environment +by typing ``conda activate``. Or (at your risk!), you can try to change your +``.bash_profile`` making sure that the Anaconda directory is the first one in the line beginning with ``export PATH=...`` . -Therefore, launch the proper **command line interface** and run the following -command to install igor (necessary for opening ibw and pxt files) and -colorcet (it gives additional perceptually uniform colormap):: - conda install --channel conda-forge igor colorcet +Novice user procedure +----------------------- -Otherwise, add conda-forge channel first and then install the packages:: +Launch the proper **command line interface** and run the following +command to install igor package (necessary for opening ibw and pxt files) and +colorcet package (it gives additional perceptually uniform colormap):: - conda config --append channels conda-forge - conda install igor colorcet + conda install --channel conda-forge igor colorcet -After this step, NavARP must be installed as a package using pip. To do it with -admin privilege (depending on the Anaconda installation), run the following +After this step, NavARP must be installed as a package using pip. To do it with +admin privilege (depending on the Anaconda installation), run the following command for the last stable version:: - pip install https://gitlab.com/fbisti/navarp/-/archive/master/navarp-master.zip + pip install navarp Without administrator privilege run instead:: - pip install --user https://gitlab.com/fbisti/navarp/-/archive/master/navarp-master.zip + pip install --user navarp -If you are brave enough you can also install the version still under +If you are brave enough you can also install the version still under development by using one of the two commands:: pip install https://gitlab.com/fbisti/navarp/-/archive/develop/navarp-develop.zip pip install --user https://gitlab.com/fbisti/navarp/-/archive/develop/navarp-develop.zip -After this steps NavARP should run directly by typing in the **command line +After this steps NavARP should run directly by typing in the **command line interface** the following command:: navarp -Instead, for getting familiar with the libraries, launch Jupyter Notebook from -the Anaconda Navigator (or in proper *command line interface* run the command -``jupyter notebook``) and open some examples which you can find in the +Instead, for getting familiar with the libraries, launch Jupyter Notebook from +the Anaconda Navigator (or in proper *command line interface* run the command +``jupyter notebook``) and open some examples which you can find in the `example folder`_: .. _example folder: https://gitlab.com/fbisti/navarp/-/tree/master/example -Finally, if you are familiar with ``conda`` you can also create a dedicated -enviroment (for example ``navarp-env``) and install only the basic packages + +Expert user procedure +------------------------ + +If you are familiar with ``conda`` you can also create a dedicated +environment (for example ``navarp-env``) and install only the basic packages using the following commands:: conda create --name navarp-env numpy scipy matplotlib colorcet h5py pyqt=5 jupyter pyyaml click conda activate navarp-env conda install -c conda-forge igor -And then you can install it directly with:: +And then you can install the last stable version with:: + + pip install navarp - pip install https://gitlab.com/fbisti/navarp/-/archive/master/navarp-master.zip +Or the version still under development with:: -Or maybe you can also have it under control with ``git``, then do:: + pip install https://gitlab.com/fbisti/navarp/-/archive/develop/navarp-develop.zip + +For getting familiar with the libraries, launch Jupyter Notebook from +the Anaconda Navigator (or in proper *command line interface* run the command +``jupyter notebook``) and open some examples which you can find in the +`example folder`_: + +.. _example folder: + https://gitlab.com/fbisti/navarp/-/tree/master/example - conda install -c conda-forge git - git clone https://gitlab.com/fbisti/navarp - pip install -e . -The version under development will be installed and any modification in the local -directory will affect the installed program. \ No newline at end of file diff -Nru navarp-1.0.0/navarp/gui/about.ui navarp-1.3.0/navarp/gui/about.ui --- navarp-1.0.0/navarp/gui/about.ui 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/navarp/gui/about.ui 2021-12-15 13:48:00.000000000 +0000 @@ -91,28 +91,38 @@ - - - 0 - - - - - font-size: 16px; + + + font-size: 16px; font-weight: bold; - - - NavARP - - - Qt::RichText - - - Qt::AlignCenter - - - - + + + NavARP + + + Qt::RichText + + + Qt::AlignCenter + + + + + + + + 75 + false + true + + + + by Federico Bisti + + + Qt::AlignCenter + + @@ -133,7 +143,7 @@ - <html><head/><body><p align="center"><span style=" font-size:10pt;">NavARP is a package for the navigation into ARPES data.</span></p></body></html> + <html><head/><body><p align="center"><span style=" font-size:10pt;">A navigator for ARPES data, never get lost in the reciprocal space!</span></p></body></html> Qt::RichText @@ -165,8 +175,7 @@ font-size: 12px; - © Copyright 2016-2019 -by Federico Bisti + © Copyright 2016-2021 ALBA Synchrotron, Spain diff -Nru navarp-1.0.0/navarp/gui/export.ui navarp-1.3.0/navarp/gui/export.ui --- navarp-1.0.0/navarp/gui/export.ui 1970-01-01 00:00:00.000000000 +0000 +++ navarp-1.3.0/navarp/gui/export.ui 2021-12-15 13:48:00.000000000 +0000 @@ -0,0 +1,156 @@ + + + exportDialog + + + + 0 + 0 + 416 + 281 + + + + Export data + + + + + + + + Panel + + + + + + + + + + File format + + + + + + + + + + + + + + + Interpolation on uniform grid: + + + + + + + + + kxbins + + + + + + + 20 + + + 100000 + + + + + + + ksbins + + + + + + + 20 + + + 100000 + + + + + + + + + + + + + + Select folder + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + false + + + + + + + + + buttonBox + accepted() + exportDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + exportDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff -Nru navarp-1.0.0/navarp/gui/main.ui navarp-1.3.0/navarp/gui/main.ui --- navarp-1.0.0/navarp/gui/main.ui 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/navarp/gui/main.ui 2021-12-15 13:48:00.000000000 +0000 @@ -9,7 +9,7 @@ 0 0 - 800 + 830 800 @@ -33,24 +33,6 @@ QLayout::SetMaximumSize - - - - - Open - - - - - - - true - - - - - - @@ -73,13 +55,13 @@ - 300 + 320 0 - 300 + 320 16777215 @@ -108,10 +90,10 @@ QLayout::SetFixedSize - 5 + 0 - 5 + 0 @@ -377,13 +359,13 @@ 5 - 5 + 0 5 - 5 + 0 @@ -422,19 +404,19 @@ #qpb_isoa { border: 1px solid #8f8f91; border-radius: 4px; -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(200, 230, 255, 255), stop:0.55 rgba(180, 210, 240, 255), stop:1 rgba(60, 110, 190, 255)); font: 12px; min-height: 30px; } #qpb_isoa:pressed { -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(60, 110, 190, 255), stop:0.45 rgba(180, 210, 240, 255), stop:1 rgba(200, 230, 255, 255)); } #qpb_isoa:checked { -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(60, 110, 190, 255), stop:0.45 rgba(180, 210, 240, 255), stop:1 rgba(200, 230, 255, 255)); } @@ -467,19 +449,19 @@ #qpb_isoe { border: 1px solid #8f8f91; border-radius: 4px; -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(200, 230, 255, 255), stop:0.55 rgba(180, 210, 240, 255), stop:1 rgba(60, 110, 190, 255)); font: 12px; min-height: 30px; } #qpb_isoe:pressed { -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(60, 110, 190, 255), stop:0.45 rgba(180, 210, 240, 255), stop:1 rgba(200, 230, 255, 255)); } #qpb_isoe:checked { -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(60, 110, 190, 255), stop:0.45 rgba(180, 210, 240, 255), stop:1 rgba(200, 230, 255, 255)); } @@ -503,19 +485,19 @@ #qpb_isoek { border: 1px solid #8f8f91; border-radius: 4px; -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(200, 230, 255, 255), stop:0.55 rgba(180, 210, 240, 255), stop:1 rgba(60, 110, 190, 255)); font: 12px; min-height: 30px; } #qpb_isoek:pressed { -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(60, 110, 190, 255), stop:0.45 rgba(180, 210, 240, 255), stop:1 rgba(200, 230, 255, 255)); } #qpb_isoek:checked { -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(60, 110, 190, 255), stop:0.45 rgba(180, 210, 240, 255), stop:1 rgba(200, 230, 255, 255)); } @@ -581,8 +563,8 @@ 0 0 - 285 - 406 + 305 + 399 @@ -592,7 +574,7 @@ - ▶ Color scale parameters + ▶ Colorscale and signal processing @@ -705,6 +687,9 @@ 3 + + 5 + @@ -713,11 +698,18 @@ 0 + + + 9 + 75 + true + + Qt::LeftToRight - Top panel contrast + Top panel Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -730,12 +722,32 @@ 5 - 20 + 0 0 + + + Contrast: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + true @@ -805,8 +817,44 @@ + + + + + + Post-processing: + + + + + + + 5 + + + 10 + + + 0 + - + + + + 0 + 0 + + + + Sigma: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + Qt::Horizontal @@ -818,12 +866,142 @@ + + + + true + + + x-axis + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + 1 + + + 0.000000000000000 + + + 100.000000000000000 + + + 0.100000000000000 + + + + + + + true + + + y-axis + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + 1 + + + 100.000000000000000 + + + 0.100000000000000 + + + 0.000000000000000 + + + + + + + + + 10 + + + 0 + + + + + Order (0: Gauss. filter; 2: 2nd deriv.): + + + + + + + + 2 + + + + + 1 + + + + + 0 + + + + + + + + + + 10 + + + 0 + + + + + Curvature (only 1-Dim): + + + + + + + 3 + + + 10000.000000000000000 + + + 0.010000000000000 + + + - + 2 @@ -836,16 +1014,29 @@ 3 + + 5 + - + 0 0 + + + 9 + 75 + true + + + + Qt::LeftToRight + - Bottom panel contrast + Bottom panel Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -858,13 +1049,33 @@ 5 - 20 + 0 0 - + + + Contrast: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + true @@ -893,10 +1104,13 @@ 0.050000000000000 + + 0.001000000000000 + - + true @@ -916,6 +1130,9 @@ 3 + + 0.001000000000000 + 1.000000000000000 @@ -927,8 +1144,44 @@ + + + + + + Post-processing: + + + + + + + 5 + + + 10 + + + 0 + + + + + + 0 + 0 + + + + Sigma: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + - + Qt::Horizontal @@ -940,18 +1193,138 @@ + + + + true + + + x-axis + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + 1 + + + 0.000000000000000 + + + 100.000000000000000 + + + 0.100000000000000 + + + + + + + true + + + y-axis + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + 1 + + + 100.000000000000000 + + + 0.100000000000000 + + + 0.000000000000000 + + + + + + + + + 10 + + + 0 + + + + + Order (0: Gauss. filter; 2: 2nd deriv.): + + + + + + + + 2 + + + + + 1 + + + + + 0 + + + + + + + + + + 10 + + + 0 + + + + + Curvature (only 1-Dim): + + + + + + + 3 + + + 10000.000000000000000 + + + 0.010000000000000 + + + - - - - - - 10 - - - 0 - @@ -984,8 +1357,8 @@ 0 0 - 285 - 406 + 305 + 399 @@ -1225,14 +1598,14 @@ #qrb_ef_update { border: 1px solid #8f8f91; -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(232, 255, 230, 255), stop:0.5 rgba(197, 235, 186, 255), stop:1 rgba(117, 158, 108, 255)); border-radius: 6px; font: 12px; } #qrb_ef_update:pressed { -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(117, 158, 108, 255), stop:0.5 rgba(197, 235, 186, 255), stop:1 rgba(232, 255, 230, 255)); } @@ -1279,8 +1652,8 @@ 0 0 - 285 - 406 + 305 + 399 @@ -1369,12 +1742,12 @@ #qpb_set_ref_p { border: 1px solid #8f8f91; border-radius: 8px; -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(250, 210, 200, 255), stop:0.65 rgba(230, 120, 110, 255), stop:1 rgba(150, 50, 40, 255)); } #qpb_set_ref_p:pressed { -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(150, 50, 40, 255), stop:0.35 rgba(230, 120, 110, 255), stop:1 rgba(250, 210, 200, 255)); } @@ -1639,12 +2012,12 @@ #qpb_set_ref_gamma { border: 1px solid #8f8f91; border-radius: 8px; -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(250, 210, 200, 255), stop:0.65 rgba(230, 120, 110, 255), stop:1 rgba(150, 50, 40, 255)); } #qpb_set_ref_gamma:pressed { -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(150, 50, 40, 255), stop:0.35 rgba(230, 120, 110, 255), stop:1 rgba(250, 210, 200, 255)); } @@ -1863,12 +2236,12 @@ #qpb_set_analyzer { border: 1px solid #8f8f91; border-radius: 8px; -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(250, 210, 200, 255), stop:0.65 rgba(230, 120, 110, 255), stop:1 rgba(150, 50, 40, 255)); } #qpb_set_analyzer:pressed { -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(150, 50, 40, 255), stop:0.35 rgba(230, 120, 110, 255), stop:1 rgba(250, 210, 200, 255)); } @@ -1893,35 +2266,6 @@ 0 - - - - - 50 - 16777215 - - - - - - - false - - - 0 - - - - no - - - - - yes - - - - @@ -1951,16 +2295,6 @@ - - - - defl. - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - @@ -2034,8 +2368,8 @@ 0 0 - 285 - 406 + 305 + 399 @@ -2084,8 +2418,8 @@ 0 0 - 800 - 20 + 830 + 26 @@ -2093,7 +2427,19 @@ Help + + + + + + File + + + + + + @@ -2102,13 +2448,38 @@ About + + + Export + + + + + Exit + + + + + Open + + + + + Documentation + + + + + Report issue + + - + - + diff -Nru navarp-1.0.0/navarp/__init__.py navarp-1.3.0/navarp/__init__.py --- navarp-1.0.0/navarp/__init__.py 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/navarp/__init__.py 2021-12-15 13:48:00.000000000 +0000 @@ -4,4 +4,4 @@ __author__ = """Federico Bisti""" __email__ = 'federico.bisti@univaq.it' -__version__ = '1.0.0' +__version__ = '1.3.0' diff -Nru navarp-1.0.0/navarp/navarp_gui.py navarp-1.3.0/navarp/navarp_gui.py --- navarp-1.0.0/navarp/navarp_gui.py 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/navarp/navarp_gui.py 2021-12-15 13:48:00.000000000 +0000 @@ -40,7 +40,7 @@ NavigationToolbar2QT as NavigationToolbar) try: - from navarp.utils import navfile, navplt, ktransf, isocut + from navarp.utils import navfile, navplt, ktransf except ImportError: raise ImportError("navarp must be installed before using it.") # from utils import navfile, fermilevel, navplt, ktransf, isocut @@ -51,6 +51,7 @@ # GUI from PyQt5 import QtWidgets # Import the PyQt5 module from PyQt5 import QtGui +from PyQt5.QtCore import QUrl # if exe-file # from gui.main import Ui_MainWindow # This file holds the MainWindow # else @@ -69,13 +70,14 @@ class Main(QtWidgets.QMainWindow, Ui_MainWindow): + """NavARP main window.""" + def __init__(self): - """Class initialization + """Class initialization. Args: self """ - super().__init__() # init main gui @@ -112,7 +114,6 @@ self.file_loaded_flag = False self.entry = None - self.qpb_file.clicked.connect(self.openfile) # init figure self.fig = Figure(facecolor='#FFFFFF', constrained_layout=True) @@ -144,19 +145,30 @@ ]) self.qcb_cmaps.setCurrentText("magma_r") + # File menu + self.actionOpen.triggered.connect(self.openfile) + self.actionExit.triggered.connect(self.close) + + # init ExportDialog gui + self.exportDialog = ExportDialog(parent=self) + self.openExportDialogAction.triggered.connect(self.openExportDialog) + + # Help menu # init AboutDialog gui self.aboutDialog = AboutDialog(parent=self) self.openAboutDialogAction.triggered.connect(self.openAboutDialog) + self.actionDocumentation.triggered.connect(self.opendocs) + self.actionReport_issue.triggered.connect(self.reportissue) + def openfile(self): - """ Method for opening a new entry file. + """Open a new entry file. It use QtWidgets.QFileDialog.getOpenFileName to get the file path Args: self """ - namefilter = ( 'ARPES files ' '(*.h5 *.ibw *.itx *.krx *.nxs *.pxt *.sp2 *.txt *.yaml *.zip)' @@ -170,7 +182,6 @@ print("Loading ", file_path) self.file_path = file_path # set file_path note in the gui - self.qle_file.setText(file_path) start_navfile = timer() self.entry = navfile.load(file_path) @@ -261,6 +272,23 @@ qsb_clim.valueChanged.connect(self.set_clim) # normalization of each scan in FS self.isoe_norm_cbx.clicked.connect(self.updateisov) + # sigma + for qsb_value, updatevalue in zip( + [self.qsb_top_sigmax, self.qsb_top_sigmay, + self.qsb_bot_sigmax, self.qsb_bot_sigmay], + [self.updatescan, self.updatescan, + self.updateisov, self.updateisov] + ): + qsb_value.valueChanged.connect(updatevalue) + # order + self.qcb_top_order.activated[str].connect(self.updatescan) + self.qcb_bot_order.activated[str].connect(self.updateisov) + # curvature + for qsb_value, updatevalue in zip( + [self.qsb_top_curvature, self.qsb_bot_curvature], + [self.updatescan, self.updateisov] + ): + qsb_value.valueChanged.connect(updatevalue) # ############################### # set FermiLevelPage @@ -280,6 +308,17 @@ # connect FermiLevelPage qrb_ef_update self.qrb_ef_update.clicked.connect(self.align_fermi) + # set line edit of the Fermi level value with the initial efermi + efermi = ktransf.asarray(self.entry.efermi) + if len(efermi) == 1: + self.qle_ef_val.setText(str(efermi[0])) + self.qle_ef_val.setEnabled(True) + self.qrb_ef_val.setEnabled(True) + else: + self.qle_ef_val.setText('') + self.qle_ef_val.setEnabled(False) + self.qrb_ef_val.setEnabled(False) + # set FermiLevelPage with no Fermi alignment self.qrb_ef_no.setChecked(True) self.qrb_range_full.setChecked(True) @@ -323,7 +362,18 @@ # ############################### # set FileInfoPage - self.qte_note.setText(self.entry.file_note) + self.qte_note.setText('file_path = {}\n{}'.format( + self.entry.file_path, self.entry.file_note)) + + # ############################### + # set ExportDialog + self.exportDialog.le_exptfiledir.setText( + os.path.dirname(file_path)) + + self.exportDialog.kxbinsSpinBox.setValue( + len(self.entry.angles)*1.5) + self.exportDialog.ksbinsSpinBox.setValue( + len(self.entry.scans)*5) # ############################### # make the plot @@ -340,12 +390,11 @@ print("No file selected") def select_mode(self): - """Method switching the plot mode between Iso-Angle Iso-E(ang) Iso-E(k) + """Switch the plot mode between Iso-Angle Iso-E(ang) Iso-E(k). Args: self """ - for qsb_value in [self.qsb_angle, self.qsb_isov, self.qsb_isod]: qsb_value.valueChanged.disconnect() @@ -377,6 +426,9 @@ self.qsb_angle.setValue( (energies.max() - energies.min())*0.7 + energies.min()) + # disable export isoenergy + self.exportDialog.activate_isoenergy_export(False) + elif self.qpb_isoe.isChecked() or self.qpb_isoek.isChecked(): if self.qpb_isoe.isChecked(): print("Selected mode is Iso-E(ang)") @@ -400,6 +452,9 @@ self.qsb_angle.setSingleStep(angle_range*0.005) self.qsb_angle.setValue(self.qsb_angle.value()) + # enable export isoenergy + self.exportDialog.activate_isoenergy_export(True) + # enabling qsb_scan and qsb_angle functions self.qsb_scan.setEnabled(not self.qpb_isoek.isChecked()) self.qsb_angle.setEnabled(not self.qpb_isoek.isChecked()) @@ -420,8 +475,7 @@ self.qle_energy_ref, self.qle_tht_ap, self.qle_phi_ap, - self.qle_wfa, - self.qcb_defl + self.qle_wfa ]: qle.setEnabled(not self.qpb_isoek.isChecked()) @@ -430,15 +484,17 @@ [self.updateangle, self.updateisov, self.updateisod]): qsb_value.valueChanged.connect(updatevalue) + # enable export isoenergy + self.exportDialog.update_interpolation_panel() + self.newplot() def addmpl(self): - """Method for adding a new matplotlib-layout widget + """Add a new matplotlib-layout widget. Args: self """ - self.canvas = FigureCanvas(self.fig) self.mpllayout.addWidget(self.canvas) self.canvas.draw() @@ -453,12 +509,11 @@ 'scroll_event', self.mpl_mouse_scroll) def rmvmpl(self): - """Method for removing the present matplotlib-layout widget + """Remove the present matplotlib-layout widget. Args: self """ - if self.file_loaded_flag: self.axtop.lines.remove(self.isovmd_ln) self.axtop.lines.remove(self.isovpd_ln) @@ -477,89 +532,110 @@ self.toolbar.close() def newplot(self): - """ Method for plotting the self.entry. + """Plot the self.entry. It removes the present matplotlib-layour making a new one. Args: self """ - start_newplot = timer() self.rmvmpl() # remove present plot - # calculate ztop - ztop = self.get_ztop() - - # calculate zbot - zbot = self.get_zbot() + # calculate xtop, ytop and xbot, ybot + # bot panel + isov = self.qsb_isov.value() + isod = self.qsb_isod.value() - if self.en_name == 'eef': - energies = self.entry.ebins - elif self.en_name == 'ekin': - energies = self.entry.energies + if self.isoe_norm_cbx.isChecked(): + norm_mode = "each" + else: + norm_mode = "all" - # calculate xtop, ytop and xbot, ybot if self.qpb_isoa.isChecked(): - # new plot in axtop - xtop = self.entry.angles - ytop = energies - - # new plot in axbot - xbot = energies - ybot = self.entry.scans + self.topxname = 'tht' - elif self.qpb_isoe.isChecked(): - # new plot in axtop - xtop = self.entry.angles - ytop = energies - - # new plot in axbot - xbot = self.entry.angles - ybot = self.entry.scans + self.isoangle = self.entry.isoangle( + isov, isod, norm_mode=norm_mode) + self.qmbot = self.isoangle.show( + xname=self.en_name, yname='scan', ax=self.axbot) - elif self.qpb_isoek.isChecked(): - self.get_surface_normal() - self.entry.kx = self.get_ktransf_kx() - kx_val, ks_val = self.get_ktransf_kx_ks_vals() - self.entry.kx_fs, self.entry.ks_fs = self.get_ktransf_fs() + elif self.qpb_isoe.isChecked() or self.qpb_isoek.isChecked(): + if self.qpb_isoe.isChecked(): + self.topxname = 'tht' - self.qsb_ks.valueChanged.disconnect() - self.qsb_kx.valueChanged.disconnect() + self.botxname = 'tht' + if self.entry.scan_type == 'hv': + self.botyname = 'hv' + else: + self.botyname = 'phi' + elif self.qpb_isoek.isChecked(): + self.topxname = 'kx' + self.botxname = 'kx' + self.botyname = 'ks' + self.set_entry_kspace() + + kx_val, ks_val = self.get_ktransf_kx_ks_vals() + + self.qsb_ks.valueChanged.disconnect() + self.qsb_kx.valueChanged.disconnect() + + # set kx and ks ranges + kx_range_emin, ks_range_emin = ktransf.get_k_isoen( + self.entry, + e_kin_val=self.entry.ebins.min()+self.entry.efermi + ) + kx_range_emax, ks_range_emax = ktransf.get_k_isoen( + self.entry, + e_kin_val=self.entry.ebins.max()+self.entry.efermi + ) + kx_range_min = min(kx_range_emin.min(), kx_range_emax.min()) + kx_range_max = max(kx_range_emin.max(), kx_range_emax.max()) + self.qsb_kx.setRange(kx_range_min, kx_range_max) + self.qsb_kx.setSingleStep((kx_range_max - kx_range_min)*0.005) + ks_range_min = min(ks_range_emin.min(), ks_range_emax.min()) + ks_range_max = max(ks_range_emin.max(), ks_range_emax.max()) + self.qsb_ks.setRange(ks_range_min, ks_range_max) + self.qsb_ks.setSingleStep((ks_range_max - ks_range_min)*0.01) - # set kx and ks ranges - kx_range_emin, ks_range_emin = self.get_ktransf_fs( - e_kin_val=self.entry.ebins.min()+self.entry.efermi) - kx_range_emax, ks_range_emax = self.get_ktransf_fs( - e_kin_val=self.entry.ebins.max()+self.entry.efermi) - kx_range_min = min(kx_range_emin.min(), kx_range_emax.min()) - kx_range_max = max(kx_range_emin.max(), kx_range_emax.max()) - self.qsb_kx.setRange(kx_range_min, kx_range_max) - self.qsb_kx.setSingleStep(((kx_range_max - kx_range_min)*0.005)) - ks_range_min = min(ks_range_emin.min(), ks_range_emax.min()) - ks_range_max = max(ks_range_emin.max(), ks_range_emax.max()) - self.qsb_ks.setRange(ks_range_min, ks_range_max) - self.qsb_ks.setSingleStep(((ks_range_max - ks_range_min)*0.01)) - - self.qsb_kx.setValue(float(kx_val)) - self.qsb_ks.setValue(float(ks_val)) - self.qle_kskx_angle.setText('atan2(ks,kx)={:.3f}°'.format( - np.rad2deg(np.arctan2(float(ks_val), float(kx_val))))) + self.qsb_kx.setValue(float(kx_val)) + self.qsb_ks.setValue(float(ks_val)) + self.qle_kskx_angle.setText('atan2(ks,kx)={:.3f}°'.format( + np.rad2deg(np.arctan2(float(ks_val), float(kx_val))))) - self.qsb_ks.valueChanged.connect(self.updatescan) - self.qsb_kx.valueChanged.connect(self.updateangle) + self.qsb_ks.valueChanged.connect(self.updatescan) + self.qsb_kx.valueChanged.connect(self.updateangle) - # axtop kx vs Bind. E. - xtop = self.entry.kx - ytop = energies - - # axbot Kx vs Scan - xbot = self.entry.kx_fs - ybot = self.entry.ks_fs + if self.en_name == 'eef': + isov = isov + elif self.en_name == 'ekin': + isov = isov - self.entry.efermi + + self.isoenergy = self.entry.isoenergy( + isov, + isod, + norm_mode=norm_mode, + sigma=self.get_sigma_bot(), + order=int(self.qcb_top_order.currentText()), + curvature=self.get_curvature(self.qsb_bot_curvature.value()) + ) + + self.qmbot = self.isoenergy.show( + xname=self.botxname, yname=self.botyname, ax=self.axbot) + + # top panel + self.isoscan = self.entry.isoscan( + scan=float(self.qsb_scan.value()), + dscan=0, + norm_mode='all', + sigma=self.get_sigma_top(), + order=int(self.qcb_top_order.currentText()), + curvature=self.get_curvature(self.qsb_top_curvature.value()) + ) + self.qmtop = self.isoscan.show( + xname=self.topxname, yname=self.en_name, ax=self.axtop) - self.qmtop = self.get_new_qm(xtop, ytop, ztop, "top") - self.qmbot = self.get_new_qm(xbot, ybot, zbot, "bot") self.set_scan_ln() self.set_angle_ln() self.set_isov_lns() @@ -574,58 +650,43 @@ end_newplot = timer() print("newplot time =", end_newplot-start_newplot) - def get_new_qm(self, x, y, z, panel): - """Method plotting ax from x, y, z and returning qm. - - Args: - x (ndarray): Array for the horizontal axis - y (ndarray): Array for the vertical axis - z (ndarray): Intensity matrix - panel (string): "top" or "bot", panel name referring to ax - Returns: - The returned value is the object matplotlib.collections.QuadMesh - from ax.pcolormesh - """ - if panel == "top": - ax = self.axtop - style = self.get_qmtop_style() - z_range = [float(self.qsb_top_zmin.value()), - float(self.qsb_top_zmax.value())] - elif panel == "bot": - ax = self.axbot - style = self.get_qmbot_style() - z_range = [float(self.qsb_bot_zmin.value()), - float(self.qsb_bot_zmax.value())] - - cmap = self.qcb_cmaps.currentText() - cmapscale = self.qcb_cmapscale.currentText() - qm = navplt.pimage( - x, y, z, cmap, ax, z_range, style, cmapscale=cmapscale) - return qm - - def get_surface_normal(self): - """Method generating self.tht_an and self.phi_an. + def set_entry_kspace(self): + """Set the kspace of the entry. Args: self """ - self.entry.analyzer.tht_ap = float(self.qle_tht_ap.text()) self.entry.analyzer.phi_ap = float(self.qle_phi_ap.text()) - refs_p = {"tht_p": float(self.qle_theta_ref.text()), - "hv_p": float(self.qle_hv_ref.text()), - "e_kin_p": float(self.qle_energy_ref.text()), - "k_along_slit_p": float(self.qle_kx_ref.text()), - "p_hv": self.get_p_hv(), - "scan_p": float(self.qle_tilt_ref.text()), - "ks_p": float(self.qle_ky_ref.text())} + self.entry.set_kspace( + tht_p=float(self.qle_theta_ref.text()), + k_along_slit_p=float(self.qle_kx_ref.text()), + scan_p=float(self.qle_tilt_ref.text()), + ks_p=float(self.qle_ky_ref.text()), + e_kin_p=float(self.qle_energy_ref.text()), + inn_pot=14, + p_hv=self.get_p_hv(), + hv_p=float(self.qle_hv_ref.text()), + k_perp_slit_for_kz=0, + print_out=False + ) + + def get_curvature(self, curvature): + """Return curvature from panel. - self.tht_an, self.phi_an, self.scans_0 = ktransf.get_surface_normal( - self.entry, refs_p) + Args: + curvature + Return: + curvature or None if curvature == 0 + """ + if (curvature == 0): + return None + else: + return curvature def get_ktransf_kx_ks_vals(self): - """Method returning k-space values. + """Return k-space values. Args: self @@ -650,33 +711,64 @@ s_index = np.argmin(abs(self.entry.scans-s_val)) kx_val = ktransf.get_k_along_slit( - e_kin_val[s_index], angle_val, self.tht_an, - p_hv=p_hv, hv=s_val, tht_ap=tht_ap) + e_kin_val[s_index], + angle_val, + self.entry.tht_an, + p_hv=p_hv, + hv=s_val, + tht_ap=tht_ap + ) ks_val = ktransf.get_k_perp_sample( - e_kin_val[s_index], inn_pot, kx_val, ky_p, - p_hv=p_hv, hv=s_val, tht_ap=tht_ap, phi_ap=phi_ap, - tht_an=self.tht_an, phi_an=self.phi_an) + e_kin_val[s_index], + inn_pot, + kx_val, + ky_p, + p_hv=p_hv, + hv=s_val, + tht_ap=tht_ap, + phi_ap=phi_ap, + tht_an=self.entry.tht_an, + phi_an=self.entry.phi_an + ) else: kx_val = ktransf.get_k_along_slit( - e_kin_val, angle_val, self.tht_an, - p_hv=p_hv, hv=self.entry.hv[0], tht_ap=tht_ap) + e_kin_val, + angle_val, + self.entry.tht_an, + p_hv=p_hv, + hv=self.entry.hv[0], + tht_ap=tht_ap + ) if (self.entry.scan_type == "polar" or self.entry.scan_type == "tilt"): phi = 0 # NO DEFLECTOR! ks_val = ktransf.get_k_perp_slit( - e_kin_val, angle_val, self.tht_an, phi, s_val-self.scans_0, - p_hv=p_hv, hv=self.entry.hv[0], - tht_ap=tht_ap, phi_ap=phi_ap) + e_kin_val, + angle_val, + self.entry.tht_an, + phi, + s_val-self.entry.scans_0, + p_hv=p_hv, + hv=self.entry.hv[0], + tht_ap=tht_ap, + phi_ap=phi_ap + ) elif self.entry.scan_type == "deflector": # DEFLECTOR scan! ks_val = ktransf.get_k_perp_slit( - e_kin_val, angle_val, self.tht_an, - s_val-self.scans_0, self.phi_an, - p_hv=p_hv, hv=self.entry.hv[0], - tht_ap=tht_ap, phi_ap=phi_ap) + e_kin_val, + angle_val, + self.entry.tht_an, + s_val-self.entry.scans_0, + self.entry.phi_an, + p_hv=p_hv, + hv=self.entry.hv[0], + tht_ap=tht_ap, + phi_ap=phi_ap + ) elif self.entry.scan_type == "azimuth": - scans_rad = np.radians(s_val-self.scans_0) + scans_rad = np.radians(s_val-self.entry.scans_0) krho = kx_val kx_val = np.squeeze(krho * np.cos(scans_rad)) ks_val = np.squeeze(krho * np.sin(scans_rad)) @@ -685,110 +777,8 @@ return kx_val, ks_val - def get_ktransf_kx(self): - """Method returning k-space values. - - Args: - self - """ - - if self.entry.scan_type == "hv": - s_val = float(self.qsb_scan.value()) - s_index = np.argmin(abs(self.entry.scans-s_val)) - energies_for_kx = self.entry.energies[s_index, :] - hv_for_kx = self.entry.hv[s_index] - else: - energies_for_kx = self.entry.energies - hv_for_kx = self.entry.hv[0] - - kxs = ktransf.get_k_along_slit( - energies_for_kx, - self.entry.angles, - self.tht_an, - p_hv=self.get_p_hv(), - hv=hv_for_kx, - tht_ap=float(self.qle_tht_ap.text()) - ) - - return kxs - - def get_ktransf_fs(self, e_kin_val=np.array([])): - """Method returning k-space values. - - Args: - self - """ - if e_kin_val.size > 0: - e_kin_val = e_kin_val - else: - if self.en_name == 'eef': - e_kin_val = self.qsb_isov.value() + self.entry.efermi - elif self.en_name == 'ekin': - e_kin_val = self.qsb_isov.value() - - self.entry.analyzer.tht_ap = float(self.qle_tht_ap.text()) - self.entry.analyzer.phi_ap = float(self.qle_phi_ap.text()) - - kx_fs = ktransf.get_k_along_slit( - e_kin_val, - self.entry.angles, - self.tht_an, - self.get_p_hv(), - self.entry.hv, - self.entry.analyzer.tht_ap - ) - - if self.entry.scan_type == "hv": - ks_fs = ktransf.get_k_perp_sample( - e_kin_val, - float(self.qle_inn_pot.text()), - kx_fs, - float(self.qle_ky_ref.text()), - self.get_p_hv(), - self.entry.hv, - self.entry.analyzer.tht_ap, - self.entry.analyzer.phi_ap, - self.tht_an, - self.phi_an - ) - elif ( - self.entry.scan_type == "polar" or self.entry.scan_type == "tilt" - ): - ks_fs = ktransf.get_k_perp_slit( - e_kin_val, - self.entry.angles, - self.tht_an, - self.entry.defl_angles, - self.phi_an, - self.get_p_hv(), - self.entry.hv, - self.entry.analyzer.tht_ap, - self.entry.analyzer.phi_ap - ) - elif self.entry.scan_type == "deflector": - ks_fs = ktransf.get_k_perp_slit( - e_kin_val, - self.entry.angles, - self.tht_an, - self.entry.scans-self.scans_0, - self.phi_an, - self.get_p_hv(), - self.entry.hv, - self.entry.analyzer.tht_ap, - self.entry.analyzer.phi_ap - ) - elif self.entry.scan_type == "azimuth": - scans_rad = np.radians(self.entry.scans) - krho = kx_fs - kx_fs = np.squeeze(krho * np.cos(scans_rad)[:, None, None]) - ks_fs = np.squeeze(krho * np.sin(scans_rad)[:, None, None]) - else: - ks_fs = self.entry.scans - - return kx_fs, ks_fs - def get_p_hv(self): - """Method returning p_hv from gui values. + """Return p_hv from gui values. Args: p_hv @@ -801,48 +791,8 @@ return p_hv - def get_ztop(self): - """Method returning ztop for gui values. - - Args: - self - """ - s_val = float(self.qsb_scan.value()) - dscan = 0 - ztop = isocut.maps_sum( - s_val, dscan, self.entry.scans, self.entry.data, axis=0) - ztop = navplt.norm(ztop, mode="all") - return ztop - - def get_zbot(self): - """Method returning zbot for gui values. - - Args: - self - """ - isov = self.qsb_isov.value() - isod = self.qsb_isod.value() - - if self.en_name == 'eef': - energies = self.entry.ebins - elif self.en_name == 'ekin': - energies = self.entry.energies - - if self.qpb_isoa.isChecked(): - zbot = isocut.maps_sum( - isov, isod, self.entry.angles, self.entry.data, axis=1) - elif self.qpb_isoe.isChecked() or self.qpb_isoek.isChecked(): - zbot = isocut.maps_sum( - isov, isod, energies, self.entry.data, axis=2) - - if self.isoe_norm_cbx.isChecked(): - zbot = navplt.norm(zbot, mode="each") - else: - zbot = navplt.norm(zbot, mode="all") - return zbot - def get_qmtop_style(self): - """Method returning qmbot_style depending on scan_type and plot mode. + """Return qmbot_style depending on scan_type and plot mode. Args: qmtop_style @@ -863,7 +813,7 @@ return x_label + '_' + y_label def get_qmbot_style(self): - """Method returning qmbot_style depending on scan_type and plot mode. + """Return qmbot_style depending on scan_type and plot mode. Args: self @@ -892,7 +842,7 @@ return x_label + '_' + y_label def get_ln_color(self): - """Method returning line color, depending on cmap used. + """Return line color, depending on cmap used. Args: self @@ -907,13 +857,46 @@ ln_color = 'w' return ln_color + def get_sigma(self, sigmax, sigmay): + """Return sigma from sigmax and sigmay. + + Args: + sigmax + sigmay + Return: + (sigmax, sigmay) or None if (0, 0) + """ + if (sigmax == 0) and (sigmay == 0): + sigma = None + elif (sigmax != 0) and (sigmay != 0): + sigma = [sigmax, sigmay] + elif (sigmax != 0) and (sigmay == 0): + sigma = sigmax + elif (sigmax == 0) and (sigmay != 0): + sigma = sigmay + + return sigma + + def get_sigma_bot(self): + """Return sigma bot.""" + sigmax = float(self.qsb_bot_sigmax.value()) + sigmay = float(self.qsb_bot_sigmay.value()) + # reverse order between sigmay, sigmax + # because isoenergy is (scan, angles) + return self.get_sigma(sigmay, sigmax) + + def get_sigma_top(self): + """Return sigma top.""" + sigmax = float(self.qsb_top_sigmax.value()) + sigmay = float(self.qsb_top_sigmay.value()) + return self.get_sigma(sigmax, sigmay) + def set_scan_ln(self): - """Method setting the scan line of axbot. + """Set the scan line of axbot. Args: self """ - if self.scan_ln: # if line already exist then update, else create if self.qpb_isoa.isChecked() or self.qpb_isoe.isChecked(): s_val = float(self.qsb_scan.value()) @@ -922,19 +905,19 @@ if self.entry.scan_type == "hv": s_val = float(self.qsb_scan.value()) s_index = np.argmin(abs(self.entry.scans-s_val)) - self.scan_ln.set_xdata(self.entry.kx_fs[:, s_index]) - self.scan_ln.set_ydata(self.entry.ks_fs[:, s_index]) + self.scan_ln.set_xdata(self.isoenergy.kx[:, s_index]) + self.scan_ln.set_ydata(self.isoenergy.ks[:, s_index]) elif (self.entry.scan_type == "polar" or self.entry.scan_type == "tilt" or self.entry.scan_type == "deflector"): s_val = float(self.qsb_scan.value()) s_index = np.argmin(abs(self.entry.scans-s_val)) - self.scan_ln.set_ydata(self.entry.ks_fs[s_index, :]) + self.scan_ln.set_ydata(self.isoenergy.ks[s_index, :]) elif self.entry.scan_type == "azimuth": s_val = float(self.qsb_scan.value()) s_index = np.argmin(abs(self.entry.scans-s_val)) - self.scan_ln.set_xdata(self.entry.kx_fs[s_index, :]) - self.scan_ln.set_ydata(self.entry.ks_fs[s_index, :]) + self.scan_ln.set_xdata(self.isoenergy.kx[s_index, :]) + self.scan_ln.set_ydata(self.isoenergy.ks[s_index, :]) else: ks_val = float(self.qsb_ks.value()) self.scan_ln.set_ydata(ks_val) @@ -951,8 +934,8 @@ s_val = float(self.qsb_scan.value()) s_index = np.argmin(abs(self.entry.scans-s_val)) self.scan_ln, = self.axbot.plot( - self.entry.kx_fs[:, s_index], - self.entry.ks_fs[:, s_index], + self.isoenergy.kx[:, s_index], + self.isoenergy.ks[:, s_index], '-', color=ln_color, linewidth=1.0 @@ -965,8 +948,8 @@ s_val = float(self.qsb_scan.value()) s_index = np.argmin(abs(self.entry.scans-s_val)) self.scan_ln, = self.axbot.plot( - self.entry.kx_fs, - self.entry.ks_fs[s_index, :], + self.isoenergy.kx, + self.isoenergy.ks[s_index, :], '-', color=ln_color, linewidth=1.0 @@ -975,8 +958,8 @@ s_val = float(self.qsb_scan.value()) s_index = np.argmin(abs(self.entry.scans-s_val)) self.scan_ln, = self.axbot.plot( - self.entry.kx_fs[s_index, :], - self.entry.ks_fs[s_index, :], + self.isoenergy.kx[s_index, :], + self.isoenergy.ks[s_index, :], '-', color=ln_color, linewidth=1.0 @@ -989,12 +972,11 @@ self.scan_ln.set_visible(not self.qcb_bot_lns.isChecked()) def set_angle_ln(self): - """Method setting the angle line of axbot. + """Set the angle line of axbot. Args: self """ - if self.qpb_isoa.isChecked(): val = float(self.qsb_angle.value()) elif self.qpb_isoe.isChecked(): @@ -1013,12 +995,11 @@ self.angle_ln.set_visible(not self.qcb_bot_lns.isChecked()) def set_isov_lns(self): - """Method setting the iso-value lines of axtop. + """Set the iso-value lines of axtop. Args: self """ - isov = self.qsb_isov.value() isod = self.qsb_isod.value() @@ -1047,26 +1028,24 @@ self.isovpd_ln.set_visible(not self.qcb_iso_lns.isChecked()) def set_ref_gamma(self): - """ Method setting the ref-point to the gamma point. + """Set the ref-point to the gamma point. The ref-point is used in the isoek mode. Args: self """ - self.qle_kx_ref.setText(str(0)) self.qle_ky_ref.setText(str(0)) def set_ref_point(self): - """ Method extracting the ref-point form the cursor. + """Set the ref-point form the cursor. The ref-point is used in the isoek mode. Args: self """ - if self.qpb_isoa.isChecked(): energy_panel = self.qsb_angle.value() self.qle_theta_ref.setText(str(self.qsb_isov.value())) @@ -1099,26 +1078,23 @@ self.qle_hv_ref.setCursorPosition(1) def set_analyzer(self): - """ Method setting the analyzer from entry. + """Set the analyzer from entry. - The ref-point is used in the isoek mode. + The analyzer is used in the isoek mode and fermi level. Args: self """ - self.qle_tht_ap.setText(str(self.entry.analyzer.tht_ap)) self.qle_phi_ap.setText(str(self.entry.analyzer.phi_ap)) self.qle_wfa.setText(str(self.entry.analyzer.work_fun)) - self.qcb_defl.setCurrentIndex(int(self.entry.analyzer.deflector)) def hideline(self): - """ Method for hiding the navigation lines of the matplotlib-layout. + """Hide the navigation lines of the matplotlib-layout. Args: self """ - self.scan_ln.set_visible(not self.qcb_bot_lns.isChecked()) self.angle_ln.set_visible(not self.qcb_bot_lns.isChecked()) self.isovmd_ln.set_visible(not self.qcb_iso_lns.isChecked()) @@ -1128,12 +1104,11 @@ restore_axtop=True, restore_axbot=True, canvas_update=True) def set_cmap(self): - """ Method for changing the color of the maps and lines. + """Set the color of the maps and lines. Args: self """ - self.qmtop.set_cmap(self.qcb_cmaps.currentText()) self.qmbot.set_cmap(self.qcb_cmaps.currentText()) ln_color = self.get_ln_color() @@ -1147,12 +1122,11 @@ canvas_update=True) def set_cmapscale(self): - """ Method for changing the colormap scale between linear/log/power. + """Set the colormap scale between linear/log/power. Args: self """ - zmin = float(self.qsb_top_zmin.value()) zmax = float(self.qsb_top_zmax.value()) norm_top = navplt.get_cmapscale(self.qcb_cmapscale.currentText(), @@ -1170,12 +1144,11 @@ canvas_update=True) def set_clim(self): - """ Method for changing the color scale max and min of the maps. + """Set the color scale max and min of the maps. Args: self """ - sender_top = [self.qsb_top_zmin, self.qsb_top_zmax] sender_bot = [self.qsb_bot_zmin, self.qsb_bot_zmax] @@ -1203,7 +1176,7 @@ draw_axtop=False, draw_axbot=False, clr_axtop=False, clr_axbot=False, canvas_update=False, canvas_draw=False): - """ Method for updating the matplotlib-layout. + """Update the matplotlib-layout. The method saves or restores the background for top or bot axes. This avoids to re-draw unmodified part of the matplotlib figure, giving @@ -1343,26 +1316,26 @@ self.canvas.draw() def updatescan(self, sender=None): - """ Method for updating the maps after changing the scan value. + """Update the maps after changing the scan value. Args: self """ - - ztop = self.get_ztop() - - if self.en_name == 'eef': - energies = self.entry.ebins - elif self.en_name == 'ekin': - energies = self.entry.energies - self.set_scan_ln() if (sender == 'mpl_mouse_motion' or sender == 'mpl_mouse_release'): self.set_angle_ln() # In the case of navbot_motion, angle changes if self.qpb_isoa.isChecked() or self.qpb_isoe.isChecked(): - self.qmtop.set_array(ztop.ravel()) + self.isoscan = self.entry.isoscan( + scan=float(self.qsb_scan.value()), + dscan=0, + norm_mode='all', + sigma=self.get_sigma_top(), + order=int(self.qcb_top_order.currentText()), + curvature=self.get_curvature(self.qsb_top_curvature.value()) + ) + self.qmtop.set_array(self.isoscan.data.ravel()) clr_axtop = False elif self.qpb_isoek.isChecked(): if (sender != 'mpl_mouse_motion' and @@ -1385,24 +1358,30 @@ isov, work_fun, inn_pot, kx_val, ky_p, ks_val, hv_p_init=hv_p_init, p_hv=p_hv, tht_ap=tht_ap, phi_ap=phi_ap, - tht_an=self.tht_an, phi_an=self.phi_an) + tht_an=self.entry.tht_an, phi_an=self.entry.phi_an) self.qsb_scan.setValue(s_val) - self.entry.kx = self.get_ktransf_kx() - - xtop = self.entry.kx - ytop = energies - - self.qmtop = self.get_new_qm(xtop, ytop, ztop, "top") + # top panel + self.isoscan = self.entry.isoscan( + scan=s_val, + dscan=0, + norm_mode='all', + sigma=self.get_sigma_top(), + order=int(self.qcb_top_order.currentText()), + curvature=self.get_curvature( + self.qsb_top_curvature.value()) + ) + self.qmtop = self.isoscan.show( + yname=self.en_name, ax=self.axtop) clr_axtop = True else: if (self.entry.scan_type == "polar" or self.entry.scan_type == "tilt" or self.entry.scan_type == "deflector"): - angle_index = np.argmin(abs(self.entry.kx_fs-kx_val)) + angle_index = np.argmin(abs(self.isoenergy.kx-kx_val)) s_index = np.argmin( - abs(self.entry.ks_fs[:, angle_index]-ks_val)) + abs(self.isoenergy.ks[:, angle_index]-ks_val)) elif self.entry.scan_type == "azimuth": azim_val = np.arctan2(ks_val, kx_val) a_index_mid = int(self.entry.angles.shape[0]*0.5) @@ -1410,20 +1389,29 @@ s_index = 0 for a_index in np.array([0, a_index_mid, -1]): s_index_new = np.argmin(abs(azim_val - np.arctan2( - self.entry.ks_fs[:, a_index], - self.entry.kx_fs[:, a_index] + self.isoenergy.ks[:, a_index], + self.isoenergy.kx[:, a_index] ))) azim_diff_new = abs(azim_val - np.arctan2( - self.entry.ks_fs[s_index_new, a_index], - self.entry.kx_fs[s_index_new, a_index] + self.isoenergy.ks[s_index_new, a_index], + self.isoenergy.kx[s_index_new, a_index] )) if azim_diff_new < azim_diff: azim_diff = azim_diff_new s_index = s_index_new else: - s_index = np.argmin(abs(self.entry.ks_fs-ks_val)) + s_index = np.argmin(abs(self.isoenergy.ks-ks_val)) self.qsb_scan.setValue(self.entry.scans[s_index]) - self.qmtop.set_array(ztop.ravel()) + self.isoscan = self.entry.isoscan( + scan=float(self.qsb_scan.value()), + dscan=0, + norm_mode='all', + sigma=self.get_sigma_top(), + order=int(self.qcb_top_order.currentText()), + curvature=self.get_curvature( + self.qsb_top_curvature.value()) + ) + self.qmtop.set_array(self.isoscan.data.ravel()) clr_axtop = True if (sender != 'mpl_mouse_motion' and sender != 'mpl_mouse_release'): @@ -1438,39 +1426,59 @@ draw_axtop=True, canvas_update=True) def updateangle(self): - """ Method for updating the maps after changing the angle value. + """Update the maps after changing the angle value. Args: self """ - self.set_angle_ln() - self.updatecanvas(restore_axbot=True, canvas_update=True) def updateisov(self, sender=None): - """ Method for updating the maps after changing the iso-value. + """Update the maps after changing the iso-value. Args: self """ + self.set_isov_lns() - zbot = self.get_zbot() + isov = self.qsb_isov.value() + isod = self.qsb_isod.value() - self.set_isov_lns() + if self.isoe_norm_cbx.isChecked(): + norm_mode = "each" + else: + norm_mode = "all" - if self.qpb_isoa.isChecked() or self.qpb_isoe.isChecked(): - self.qmbot.set_array(zbot.ravel()) + if self.qpb_isoa.isChecked(): + self.isoangle = self.entry.isoangle( + isov, isod, norm_mode=norm_mode) + self.qmbot.set_array(self.isoangle.data.ravel()) clr_axbot = False - elif self.qpb_isoek.isChecked(): # new plot because axes changing - self.entry.kx_fs, self.entry.ks_fs = self.get_ktransf_fs() - xbot = self.entry.kx_fs - ybot = self.entry.ks_fs + elif self.qpb_isoe.isChecked() or self.qpb_isoek.isChecked(): + if self.en_name == 'eef': + isov = isov + elif self.en_name == 'ekin': + isov = isov - self.entry.efermi - self.qmbot = self.get_new_qm(xbot, ybot, zbot, "bot") + self.isoenergy = self.entry.isoenergy( + isov, + isod, + norm_mode=norm_mode, + sigma=self.get_sigma_bot(), + order=int(self.qcb_bot_order.currentText()), + curvature=self.get_curvature(self.qsb_bot_curvature.value()) + ) - clr_axbot = True + if self.qpb_isoe.isChecked(): + self.qmbot.set_array(self.isoenergy.data.ravel()) + clr_axbot = False + + elif self.qpb_isoek.isChecked(): + self.qmbot = self.isoenergy.show( + xname=self.botxname, yname=self.botyname, ax=self.axbot) + clr_axbot = True if sender == 'mpl_mouse_motion': self.updatecanvas(restore_axtop=True, clr_axbot=True, @@ -1481,30 +1489,28 @@ draw_axbot=True, canvas_update=True) def updateisod(self): - """ Method for updating the maps after changing the iso-value delta. + """Update the maps after changing the iso-value delta. Args: self """ - self.qsb_isov.setSingleStep(self.qsb_isod.value()) self.updateisov() def mpl_mouse_scroll(self, event): - """ Method for mouse scroll navigation, changing iso-value delta. + """Mouse scroll navigation, changing iso-value delta. Args: self event (matplotlib.backend_bases.Event): mouse event description """ - if event.button == 'up': self.qsb_isod.setValue(self.qsb_isod.value()*2) elif event.button == 'down': self.qsb_isod.setValue(self.qsb_isod.value()*0.5) def mpl_mouse_press(self, event): - """ Method for mouse right-click navigation, button pressed. + """Mouse right-click navigation, button pressed. If right-click in the top panel, iso-value is changed to the mouse position. @@ -1518,7 +1524,6 @@ self event (matplotlib.backend_bases.Event): mouse event description """ - # if it is not the mouse right button then exit if event.button != 3: return None @@ -1556,7 +1561,7 @@ 'button_release_event', self.mpl_mouse_release) def mpl_mouse_motion(self, event): - """ Method for mouse right-click navigation, button pressed in motion. + """Mouse right-click navigation, button pressed in motion. If right-click motion in the top panel, iso-value is changed following to the mouse position. @@ -1568,7 +1573,6 @@ Args: self """ - # Navigation with the cursor in axbot if event.button == 3 and event.inaxes == self.axbot: if self.qpb_isoa.isChecked() or self.qpb_isoe.isChecked(): @@ -1598,7 +1602,7 @@ self.updateisov(sender='mpl_mouse_motion') def mpl_mouse_release(self, event): - """ Method for mouse right-click navigation, button released. + """Mouse right-click navigation, button released. If right-click in the top panel, iso-value is changed to the mouse position. @@ -1611,7 +1615,6 @@ self event (matplotlib.backend_bases.Event): mouse event description """ - # disconnect for mouse motion self.canvas.mpl_disconnect(self.cidmotion) # disconnect for mouse leaving axes @@ -1643,12 +1646,11 @@ self.mpl_mouse_scroll) def align_fermi(self): - """ Method for aligning the energy scale to the fermi level. + """Align the energy scale to the fermi level. Args: self """ - scans = self.entry.scans if self.sender().isChecked() or self.sender() == self.qrb_ef_update: @@ -1770,9 +1772,134 @@ self.newplot() def openAboutDialog(self): + """Show the about dialog.""" self.aboutDialog.show() + def opendocs(self): + """Open documentation web-page on a browser.""" + QtGui.QDesktopServices.openUrl(QUrl( + "https://fbisti.gitlab.io/navarp/")) + + def reportissue(self): + """Open report-issue web-page on a browser.""" + QtGui.QDesktopServices.openUrl(QUrl( + "https://gitlab.com/fbisti/navarp/-/issues")) + + def openExportDialog(self): + """Show the export dialog.""" + self.exportDialog.show() + if self.exportDialog.exec_() == 1: + isomap_name = self.exportDialog.get_isomap_name() + file_ext = self.exportDialog.get_file_ext() + + export_file_path = os.path.join( + self.exportDialog.le_exptfiledir.text(), isomap_name) + + export_file_path, _ = QtWidgets.QFileDialog.getSaveFileName( + directory=export_file_path, + filter="{} (*.{})".format(file_ext.upper(), file_ext[1:]) + ) + if not export_file_path: + print("No file selected") + return + + if isomap_name == 'isoscan': # top panel + + if file_ext == ".h5": + kbins = None + else: + if 'tht' in self.topxname: + kbins = None + elif 'kx' in self.topxname: + kbins = self.exportDialog.kxbinsSpinBox.value() + + # norm_mode is 'no' instead of 'all' in the case of export + isoscan = self.entry.isoscan( + scan=float(self.qsb_scan.value()), + dscan=0, + norm_mode='all', + sigma=self.get_sigma_top(), + order=int(self.qcb_top_order.currentText()), + curvature=self.get_curvature( + self.qsb_top_curvature.value()), + kbins=kbins + ) + + if file_ext == ".nxs": + isoscan.export_as_nxs( + file_path=export_file_path, + xname=self.topxname, + yname=self.en_name, + ) + elif file_ext == ".h5": + isoscan.export_as_hdf5( + file_path=export_file_path, + xname=self.topxname, + yname=self.en_name, + ) + elif file_ext == ".itx": + isoscan.export_as_itx( + file_path=export_file_path, + xname=self.topxname, + yname=self.en_name, + ) + + elif isomap_name == 'isoenergy': # bot panel + + if file_ext == ".h5": + kbins = None + else: + if 'tht' in self.botxname: + kbins = None + elif 'kx' in self.botxname: + kbins = [ + self.exportDialog.kxbinsSpinBox.value(), + self.exportDialog.ksbinsSpinBox.value() + ] + + if self.en_name == 'eef': + isov = self.qsb_isov.value() + elif self.en_name == 'ekin': + isov = self.qsb_isov.value() - self.entry.efermi + + if self.isoe_norm_cbx.isChecked(): + norm_mode = "each" + else: + # norm_mode is 'no' instead of 'all' in the case of export + norm_mode = "no" + + isoenergy = self.entry.isoenergy( + ebin=isov, + debin=self.qsb_isod.value(), + norm_mode=norm_mode, + sigma=self.get_sigma_bot(), + order=int(self.qcb_bot_order.currentText()), + curvature=self.get_curvature( + self.qsb_bot_curvature.value()), + kbins=kbins + ) + + if file_ext == ".nxs": + isoenergy.export_as_nxs( + file_path=export_file_path, + xname=self.botxname, + yname=self.botyname + ) + elif file_ext == ".h5": + isoenergy.export_as_hdf5( + file_path=export_file_path, + xname=self.botxname, + yname=self.botyname + ) + elif file_ext == ".itx": + isoenergy.export_as_itx( + file_path=export_file_path, + xname=self.botxname, + yname=self.botyname + ) + def closeEvent(self, event): + """Save in HOMEPATH/.navarp the navarp configuration.""" print("Saving configurations before closing") config_dic = {'file_path': self.file_path} @@ -1790,14 +1917,94 @@ class AboutDialog(QtWidgets.QDialog): + """About dialog of navarp with the info on the program.""" + def __init__(self, parent): + """Class initialization. + + Args: + self + parent + """ super(AboutDialog, self).__init__(parent) loadUi(os.path.join(path_gui, 'about.ui'), baseinstance=self) +class ExportDialog(QtWidgets.QDialog): + """Dialog for exporting the isoscan or isoenergy map in a single file.""" + + def __init__(self, parent): + """Class initialization. + + Args: + self + parent + """ + super(ExportDialog, self).__init__(parent) + + self.parent_qpb_isoek = parent.qpb_isoek + + loadUi(os.path.join(path_gui, 'export.ui'), baseinstance=self) + + self.panelSelectComboBox.addItem( + "isoscan (top-panel)", "isoscan") + self.activate_isoenergy_export(True) + + self.fileFormatComboBox.addItem( + "NXdata (Nexus format)", ".nxs") + self.fileFormatComboBox.addItem( + "ITX (IGOR Pro Text File)", ".itx") + self.fileFormatComboBox.addItem( + "HDF5 (without any interpolation)", ".h5") + + self.panelSelectComboBox.activated[str].connect( + self.update_interpolation_panel) + self.fileFormatComboBox.activated[str].connect( + self.update_interpolation_panel) + self.btn_exptfiledir.clicked.connect(self.select_exptfiledir) + + def activate_isoenergy_export(self, activate): + """Enable or disable isoenergy export option.""" + index_isoen = self.panelSelectComboBox.findData("isoenergy") + if activate: + if index_isoen == -1: + self.panelSelectComboBox.addItem( + "isoenergy (bottom-panel)", "isoenergy") + else: + if index_isoen != -1: + self.panelSelectComboBox.removeItem(index_isoen) + + def get_isomap_name(self): + """Return the isomap name (isoscan or isoenergy).""" + return self.panelSelectComboBox.itemData( + self.panelSelectComboBox.currentIndex()) + + def get_file_ext(self): + """Return the file extension (.nxs, .itx or .h5).""" + return self.fileFormatComboBox.itemData( + self.fileFormatComboBox.currentIndex()) + + def select_exptfiledir(self): + """Select the export file folder.""" + export_file_dir = QtWidgets.QFileDialog.getExistingDirectory() + if export_file_dir: + self.le_exptfiledir.setText(export_file_dir) + + def update_interpolation_panel(self): + """Update interpolation panel based on isoek and file format.""" + isoek_is_checked = self.parent_qpb_isoek.isChecked() + isnot_hdf5 = (".h5" != self.get_file_ext()) + is_isoenergy = ("isoenergy" == self.get_isomap_name()) + + self.kxbinsSpinBox.setEnabled(isoek_is_checked and isnot_hdf5) + self.ksbinsSpinBox.setEnabled( + is_isoenergy and isoek_is_checked and isnot_hdf5) + + @click.command() def main(): + """Launch the navarp gui.""" app = QtWidgets.QApplication(sys.argv) # A new instance of QApplication app.setApplicationName("navarp") diff -Nru navarp-1.0.0/navarp/utils/isomclass.py navarp-1.3.0/navarp/utils/isomclass.py --- navarp-1.0.0/navarp/utils/isomclass.py 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/navarp/utils/isomclass.py 2021-12-15 13:48:00.000000000 +0000 @@ -28,7 +28,8 @@ import numpy as np import matplotlib.pyplot as plt -from scipy.ndimage import gaussian_filter +from scipy.ndimage import ( + gaussian_filter, gaussian_laplace, gaussian_gradient_magnitude) import h5py try: @@ -38,7 +39,7 @@ class IsoScan: - """Sum of entry.data over the scan axis within [scan-dscan, scan+dscan] + """Sum of entry.data over the scan axis within [scan-dscan, scan+dscan]. Args: entry (NavEntry class): The class for the data explored by NavARP; @@ -91,6 +92,7 @@ curvature=None, kbins=None ): + """Class initialization.""" self.scan = scan self.dscan = dscan self.data_init = isocut.maps_sum( @@ -122,7 +124,7 @@ self.dataprocessing(norm_mode, sigma, order, curvature, kbins) def get_axs_and_data(self, xname='auto', yname='auto'): - """Return the data and relative axes + """Return the data and relative axes. Args: xname (string, optional, auto/tht/kx): Select the x variable; @@ -130,7 +132,6 @@ Returns: xax, yax, data, xname, yname """ - if self.kx_interp is not None: xname = 'kx' xax = self.kx_interp @@ -159,7 +160,7 @@ return xax, yax, self.data, xname, yname def dataprocessing(self, norm_mode, sigma, order, curvature, kbins): - """Use data post-processing procedure + """Apply data post-processing procedure. Args: norm_mode (string, optional, 'no' or 'all' or 'each'): if 'no', no @@ -178,12 +179,12 @@ with that derivative of a Gaussian. For example, an order of 2 corresponds to convolution with that second derivative of a Gaussian; - curvature (integer, optional, default=None): if not None the data - are the curvature of the signal; + curvature (float, optional, default=None): if not None the data + are the curvature of the signal, only in 1-dimension, meaning + only for sigma with one value; kbins (integer, optional, default=None): if not None the data are interpolated on a uniform k-array binned with the kbins number. """ - if kbins is not None: if hasattr(self, 'kx'): self.kx_interp, self.data = kinterp.get_isoscan( @@ -194,18 +195,14 @@ self.data = np.copy(self.data_init) self.kx_interp = None - if norm_mode != 'no': + if norm_mode == 'each': self.data = navplt.norm(self.data, mode=norm_mode, axis=1) if sigma is not None: - if curvature is not None: - dev1pwr2 = gaussian_filter(self.data, sigma, order=1)**2 - dev2 = gaussian_filter(self.data, sigma, order=2) - curv_max = curvature*abs(dev1pwr2.max() - dev1pwr2.min()) - self.data = dev2*np.power((curv_max + dev1pwr2), -1.5) + self.data = postprocessing(self.data, sigma, order, curvature) - else: - self.data = gaussian_filter(self.data, sigma, order) + if norm_mode == 'all': + self.data = navplt.norm(self.data, mode=norm_mode, axis=1) def show( self, @@ -218,7 +215,7 @@ print_out=False, cmapscale="linear" ): - """Plot the isomap + """Plot the isomap. Args: xname (string, optional, auto/tht/kx): Select the x variable; @@ -236,7 +233,6 @@ The returned value is the object matplotlib.collections.QuadMesh from ax.pcolormesh. """ - xax, yax, data, xname, yname = self.get_axs_and_data(xname, yname) if style is None: @@ -255,28 +251,25 @@ ) return qmisoscan - def export_as_nxs( + def export_as_hdf5( self, - file_path_nxs, + file_path, xname='auto', yname='auto', title='NavARP_isoscan' ): - """Save the isomap as NXdata nexus class + """Save the isomap as hdf5 format. Args: xname (string, optional, auto/tht/kx): Select the x variable; yname (string, optional, auto/eef/ekin): Select the y variable; title (string, optiona): data title. """ - xax, yax, data, xname, yname = self.get_axs_and_data(xname, yname) - f = h5py.File(file_path_nxs, "w") # create the HDF5 NeXus file - f.attrs[u"default"] = u"isoscan" + f = h5py.File(file_path, "w") # create the HDF5 file nxdata = f.create_group(u"isoscan") - nxdata.attrs[u"NX_class"] = u"NXdata" nxdata.create_dataset(u"title", data=title) @@ -309,21 +302,80 @@ f.close() + def export_as_nxs( + self, + file_path, + xname='auto', + yname='auto', + title='NavARP_isoscan' + ): + """Save the isomap as NXdata nexus class. + + Args: + xname (string, optional, auto/tht/kx): Select the x variable; + yname (string, optional, auto/eef/ekin): Select the y variable; + title (string, optiona): data title. + """ + xax, yax, data, xname, yname = self.get_axs_and_data(xname, yname) + + if len(xax.shape) > 1: + raise ValueError( + "Data must be interpolated on uniform grid, first. " + "Use kbins during isoscan initialization or in dataprocessing." + ) + return None + + f = h5py.File(file_path, "w") # create the HDF5 NeXus file + f.attrs[u"default"] = u"isoscan" + + nxdata = f.create_group(u"isoscan") + nxdata.attrs[u"NX_class"] = u"NXdata" + + nxdata.create_dataset(u"title", data=title) + + if xname == 'kx': + axes_names = ['', 'momentum'] + xdata = nxdata.create_dataset(axes_names[1], data=xax) + xdata.attrs[u"units"] = u"1/angstrom" + else: + axes_names = ['', 'angles'] + xdata = nxdata.create_dataset(axes_names[1], data=xax) + xdata.attrs[u"units"] = u"degrees" + xdata.attrs[u"axis"] = 2 + xdata.attrs[u"primary"] = 1 + + if yname == 'eef': + axes_names[0] = "binding_energies" + else: + axes_names[0] = "kinetic_energies" + ydata = nxdata.create_dataset(axes_names[0], data=yax) + ydata.attrs[u"axis"] = 1 + ydata.attrs[u"primary"] = 1 + ydata.attrs[u"units"] = u"eV" + + data_nx = nxdata.create_dataset( + u"data", data=data.transpose(), compression='gzip', chunks=True) + data_nx.attrs[u"units"] = u"counts" + nxdata.attrs[u"signal"] = u"data" + + nxdata.attrs[u"axes"] = [axesn.encode('utf8') for axesn in axes_names] + + f.close() + def export_as_itx( self, - file_path_itx, + file_path, xname='auto', yname='auto', wave_name='NavARP_isoscan' ): - """Save the isomap as Igor Text file + """Save the isomap as Igor Pro Text file. Args: xname (string, optional, auto/tht/kx): Select the x variable; yname (string, optional, auto/eef/ekin): Select the y variable; wave_name (string, optiona): name of the wave. """ - xax, yax, data, xname, yname = self.get_axs_and_data(xname, yname) if len(xax.shape) > 1: @@ -361,7 +413,7 @@ ) np.savetxt( - file_path_itx, + file_path, data, fmt='%.6f', delimiter=' ', @@ -374,7 +426,7 @@ class IsoEnergy: - """Sum of entry.data over the ebin axis within [ebin-debin, ebin+debin] + """Sum of entry.data over the ebin axis within [ebin-debin, ebin+debin]. Args: entry (NavEntry class): The class for the data explored by NavARP; @@ -428,6 +480,7 @@ curvature=None, kbins=None ): + """Class initialization.""" self.ebin = ebin self.debin = debin self.data_init = isocut.maps_sum( @@ -449,7 +502,7 @@ self.dataprocessing(norm_mode, sigma, order, curvature, kbins) def dataprocessing(self, norm_mode, sigma, order, curvature, kbins): - """Use data post-processing procedure + """Apply data post-processing procedure. Args: norm_mode (string, optional, 'no' or 'all' or 'each'): if 'no', no @@ -468,8 +521,9 @@ with that derivative of a Gaussian. For example, an order of 2 corresponds to convolution with that second derivative of a Gaussian; - curvature (integer, optional, default=None): if not None the data - are the curvature of the signal; + curvature (float, optional, default=None): if not None the data + are the curvature of the signal, only in 1-dimension, meaning + only for sigma with one value; kbins (array, optional, default=None): if not None, the data are interpolated on a uniform k-array binned following the [kxbins, kybins] numbers; kbins must be an array of two integer @@ -478,7 +532,6 @@ is necessary due to how the code recognize the element order and placement in the data matrix). """ - if kbins is not None: if len(kbins) != 2: raise ValueError( @@ -489,6 +542,8 @@ kbins[1] += 1 self.kx_interp, self.ks_interp, self.data = kinterp.get_isoen( kbins[0], kbins[1], self.kx, self.ks, self.data_init) + if self.ks_interp.shape[0] == self.data.shape[1]: + self.data = self.data.transpose() else: raise AttributeError('No valid tht_an, do set_tht_an first') else: @@ -496,21 +551,17 @@ self.kx_interp = None self.ks_interp = None - if norm_mode != 'no': + if norm_mode == 'each': self.data = navplt.norm(self.data, mode=norm_mode, axis=1) if sigma is not None: - if curvature is not None: - dev1pwr2 = gaussian_filter(self.data, sigma, order=1)**2 - dev2 = gaussian_filter(self.data, sigma, order=2) - curv_max = curvature*abs(dev1pwr2.max() - dev1pwr2.min()) - self.data = dev2*np.power((curv_max + dev1pwr2), -1.5) + self.data = postprocessing(self.data, sigma, order, curvature) - else: - self.data = gaussian_filter(self.data, sigma, order) + if norm_mode == 'all': + self.data = navplt.norm(self.data, mode=norm_mode, axis=1) def get_axs_and_data(self, xname='auto', yname='auto'): - """Return the data and relative axes + """Return the data and relative axes. Args: xname (string, optional, auto/tht/kx): Select the x variable; @@ -518,7 +569,6 @@ Returns: xax, yax, data, xname, yname """ - if self.kx_interp is not None: xname = 'kx' xax = self.kx_interp @@ -543,7 +593,7 @@ else: xax = self.angles - if yname == 'auto': + if yname == 'auto' or (yname == 'ks'): if hasattr(self, 'ks'): if self.scan_type == 'hv': yname = 'kz' @@ -574,9 +624,10 @@ z_range=None, style=None, print_out=False, - cmapscale="linear" + cmapscale="linear", + rotate=None ): - """Plot the isomap + """Plot the isomap. Args: xname (string, optional, auto/tht/kx): Select the x variable; @@ -589,21 +640,37 @@ print_out (boolean, optional): If True, print the axes dimension with them adaptations; cmapscale (string, optional, linear/log/power): Select the scale - mode. + mode; + rotate (float, optional): angle in degrees for a counter clockwise + rotation of the shown isoenergy. Returns: The returned value is the object matplotlib.collections.QuadMesh from ax.pcolormesh. """ - xax, yax, data, xname, yname = self.get_axs_and_data(xname, yname) if style is None: style = xname + '_' + yname + if rotate: + if len(xax.shape) != 2: + xax_cp = np.tile(xax, (self.scans.shape[0], 1)) + else: + xax_cp = np.copy(xax) + + if len(yax.shape) != 2: + yax_cp = np.tile(yax, (self.angles.shape[0], 1)).T + else: + yax_cp = np.copy(yax) + + rot_ang = np.deg2rad(rotate) + xax = np.cos(rot_ang)*xax_cp - np.sin(rot_ang)*yax_cp + yax = np.sin(rot_ang)*xax_cp + np.cos(rot_ang)*yax_cp + qmiso = navplt.pimage( xax, yax, - self.data, + data, cmap=cmap, ax=ax, z_range=z_range, @@ -613,24 +680,86 @@ ) return qmiso - def export_as_nxs( + def export_as_hdf5( self, - file_path_nxs, + file_path, xname='auto', yname='auto', title='NavARP_isoenergy' ): - """Save the isomap as NXdata nexus class + """Save the isomap as hdf5 format. Args: xname (string, optional, auto/tht/kx): Select the x variable; yname (string, optional, auto/eef/ekin): Select the y variable; title (string, optiona): data title. """ + xax, yax, data, xname, yname = self.get_axs_and_data(xname, yname) + + f = h5py.File(file_path, "w") # create the HDF5 NeXus file + + nxdata = f.create_group(u"isoenergy") + + nxdata.create_dataset(u"title", data=title) + + if xname == 'kx': + axes_names = ['', 'k_along_slit'] + xdata = nxdata.create_dataset(axes_names[1], data=xax) + xdata.attrs[u"units"] = u"1/angstrom" + else: + axes_names = ['', 'angles'] + xdata = nxdata.create_dataset(axes_names[1], data=xax) + xdata.attrs[u"units"] = u"degrees" + xdata.attrs[u"axis"] = 2 + xdata.attrs[u"primary"] = 1 + + if (yname == 'ky') or (yname == 'kz'): + axes_names[0] = 'k_along_scan' + ydata = nxdata.create_dataset(axes_names[0], data=yax) + ydata.attrs[u"units"] = u"1/angstrom" + else: + axes_names[0] = self.scan_type + ydata = nxdata.create_dataset(axes_names[0], data=yax) + if self.scan_type == 'hv': + ydata.attrs[u"units"] = u"eV" + else: + ydata.attrs[u"units"] = u"degree" + ydata.attrs[u"axis"] = 1 + ydata.attrs[u"primary"] = 1 + data_nx = nxdata.create_dataset( + u"data", data=data, compression='gzip', chunks=True) + data_nx.attrs[u"units"] = u"counts" + nxdata.attrs[u"signal"] = u"data" + + nxdata.attrs[u"axes"] = axes_names + + f.close() + + def export_as_nxs( + self, + file_path, + xname='auto', + yname='auto', + title='NavARP_isoenergy' + ): + """Save the isomap as NXdata nexus class. + + Args: + xname (string, optional, auto/tht/kx): Select the x variable; + yname (string, optional, auto/eef/ekin): Select the y variable; + title (string, optiona): data title. + """ xax, yax, data, xname, yname = self.get_axs_and_data(xname, yname) - f = h5py.File(file_path_nxs, "w") # create the HDF5 NeXus file + if (len(xax.shape) > 1) or (len(yax.shape) > 1): + raise ValueError( + "Data must be interpolated on uniform grid, first. Use " + "kbins during isoenergy initialization or in dataprocessing." + ) + return None + + f = h5py.File(file_path, "w") # create the HDF5 NeXus file f.attrs[u"default"] = u"isoenergy" nxdata = f.create_group(u"isoenergy") @@ -639,28 +768,28 @@ nxdata.create_dataset(u"title", data=title) if xname == 'kx': - axes_names = ['k_along_slit', ''] - xdata = nxdata.create_dataset(axes_names[0], data=xax) + axes_names = [u'', u'k_along_slit'] + xdata = nxdata.create_dataset(axes_names[1], data=xax) xdata.attrs[u"units"] = u"1/angstrom" else: - axes_names = ['angles', ''] - xdata = nxdata.create_dataset(axes_names[0], data=xax) + axes_names = [u'', u'angles'] + xdata = nxdata.create_dataset(axes_names[1], data=xax) xdata.attrs[u"units"] = u"degrees" - xdata.attrs[u"axis"] = 1 + xdata.attrs[u"axis"] = 2 xdata.attrs[u"primary"] = 1 if (yname == 'ky') or (yname == 'kz'): - axes_names[1] = 'k_along_scan' - ydata = nxdata.create_dataset(axes_names[0], data=xax) + axes_names[0] = u'k_along_scan' + ydata = nxdata.create_dataset(axes_names[0], data=yax) ydata.attrs[u"units"] = u"1/angstrom" else: - axes_names[1] = self.scan_type - ydata = nxdata.create_dataset(axes_names[0], data=xax) - if self.scan_type == 'hv': + axes_names[0] = self.scan_type + ydata = nxdata.create_dataset(axes_names[0], data=yax) + if self.scan_type == u'hv': ydata.attrs[u"units"] = u"eV" else: ydata.attrs[u"units"] = u"degree" - ydata.attrs[u"axis"] = 2 + ydata.attrs[u"axis"] = 1 ydata.attrs[u"primary"] = 1 data_nx = nxdata.create_dataset( @@ -668,25 +797,24 @@ data_nx.attrs[u"units"] = u"counts" nxdata.attrs[u"signal"] = u"data" - nxdata.attrs[u"axes"] = [axesn.encode('utf8') for axesn in axes_names] + nxdata.attrs[u"axes"] = axes_names f.close() def export_as_itx( self, - file_path_itx, + file_path, xname='auto', yname='auto', wave_name='NavARP_isoenergy' ): - """Save the isomap as Igor Text file + """Save the isomap as Igor Pro Text file. Args: xname (string, optional, auto/tht/kx): Select the x variable; yname (string, optional, auto/eef/ekin): Select the y variable; wave_name (string, optiona): name of the wave. """ - xax, yax, data, xname, yname = self.get_axs_and_data(xname, yname) if (len(xax.shape) > 1) or (len(yax.shape) > 1): @@ -696,6 +824,9 @@ ) return None + # data transpose for itx + data_itx = data.transpose() + if xname == 'kx': xlabel = 'k along slit [1/Angstrom]' else: @@ -711,7 +842,7 @@ header = ( "IGOR\n" + - "WAVES/N=({0[0]},{0[1]})\t".format(data.shape) + + "WAVES/N=({0[0]},{0[1]})\t".format(data_itx.shape) + wave_name + "\n" + "BEGIN" ) @@ -727,8 +858,8 @@ ) np.savetxt( - file_path_itx, - data, + file_path, + data_itx, fmt='%.6f', delimiter=' ', newline='\n', @@ -740,7 +871,7 @@ class IsoAngle: - """Sum of entry.data over the angle axis in [angle-dangle, angle+dangle] + """Sum of entry.data over the angle axis in [angle-dangle, angle+dangle]. Args: entry (NavEntry class): The class for the data explored by NavARP; @@ -791,6 +922,7 @@ curvature=None, kbins=None ): + """Class initialization.""" self.angle = angle self.dangle = dangle self.data_init = isocut.maps_sum( @@ -821,7 +953,7 @@ print_out=False, cmapscale="linear" ): - """Plot the isomap + """Plot the isomap. Args: xname (string, optional, auto/phi/hv): Select the x variable; @@ -840,26 +972,30 @@ from ax.pcolormesh. """ - - if xname == 'auto': + if xname == 'auto' or (xname == 'scan'): if self.scan_type == 'hv': xname = 'hv' else: xname = 'phi' - x_ax = self.scans + x_ax = self.scans + elif xname == 'ekin': + x_ax = self.ekins + elif xname == 'eef': + x_ax = self.ebins if yname == 'auto': yname = 'eef' y_ax = self.ebins elif yname == 'ekin': - if hasattr(self, 'ekin'): - y_ax = self.ekins - else: - print('Attribute ekin does not exist, using ebin') - y_ax = self.ebins - yname = 'eef' + y_ax = self.ekins elif yname == 'eef': y_ax = self.ebins + elif yname == 'scan': + if self.scan_type == 'hv': + yname = 'hv' + else: + yname = 'phi' + y_ax = self.scans if style is None: style = xname + '_' + yname @@ -878,7 +1014,7 @@ return qmisoangle def dataprocessing(self, norm_mode, sigma, order, curvature): - """Use data post-processing procedure + """Use data post-processing procedure. Args: norm_mode (string, optional, 'no' or 'all' or 'each'): if 'no', no @@ -900,25 +1036,20 @@ curvature (integer, optional, default=None): if not None the data are the curvature of the signal. """ - self.data = np.copy(self.data_init) - if norm_mode != 'no': + if norm_mode == 'each': self.data = navplt.norm(self.data, mode=norm_mode, axis=1) if sigma is not None: - if curvature is not None: - dev1pwr2 = gaussian_filter(self.data, sigma, order=1)**2 - dev2 = gaussian_filter(self.data, sigma, order=2) - curv_max = curvature*abs(dev1pwr2.max() - dev1pwr2.min()) - self.data = dev2*np.power((curv_max + dev1pwr2), -1.5) + self.data = postprocessing(self.data, sigma, order, curvature) - else: - self.data = gaussian_filter(self.data, sigma, order) + if norm_mode == 'all': + self.data = navplt.norm(self.data, mode=norm_mode, axis=1) class IsoK: - """Interpolate the entry.data along specified k-points + """Interpolate the entry.data along specified k-points. Args: entry (NavEntry class): the class for the data explored by NavARP; @@ -950,8 +1081,9 @@ with that derivative of a Gaussian. For example, an order of 2 corresponds to convolution with that second derivative of a Gaussian; - curvature (integer, optional, default=None): if not None the data - are the curvature of the signal. + curvature (float, optional, default=None): if not None the data + are the curvature of the signal, only in 1-dimension, meaning + only for sigma with one value. Attributes: data_init (ndarray): The matrix composed by interpolated values along @@ -988,7 +1120,7 @@ order=2, curvature=None ): - + """Class initialization.""" self.klabels = klabels self.kx_pts = kx_pts self.ky_pts = ky_pts @@ -1016,7 +1148,7 @@ self.dataprocessing(norm_mode, sigma, order, curvature) def dataprocessing(self, norm_mode, sigma, order, curvature): - """Use data post-processing procedure + """Use data post-processing procedure. Args: norm_mode (string, optional, 'no' or 'all' or 'each'): if 'no', no @@ -1038,31 +1170,25 @@ curvature (integer, optional, default=None): if not None the data are the curvature of the signal. """ - self.data = np.copy(self.data_init) - if norm_mode != 'no': + if norm_mode == 'each': self.data = navplt.norm(self.data, mode=norm_mode, axis=1) if sigma is not None: - if curvature is not None: - dev1pwr2 = gaussian_filter(self.data, sigma, order=1)**2 - dev2 = gaussian_filter(self.data, sigma, order=2) - curv_max = curvature*abs(dev1pwr2.max() - dev1pwr2.min()) - self.data = dev2*np.power((curv_max + dev1pwr2), -1.5) + self.data = postprocessing(self.data, sigma, order, curvature) - else: - self.data = gaussian_filter(self.data, sigma, order) + if norm_mode == 'all': + self.data = navplt.norm(self.data, mode=norm_mode, axis=1) def get_yax(self, yname='auto'): - """Return the selected y axis + """Return the selected y axis. Args: yname (string, optional, auto/eef/ekin): Select the y variable. Returns: yax, yname """ - if yname == 'auto': yname = 'eef' yax = self.ebins @@ -1080,7 +1206,7 @@ def path_show( self, ax=None, lc='k', textcolor='r', textsize=14, xytext=(8, 5)): - """Plot the path + """Plot the path. Args: ax (matplotlib.axes, optional): Axes, if None it is created inside @@ -1091,7 +1217,6 @@ xytext (array, optional): relative text position of the labels. """ - if ax is None: fig, ax = plt.subplots(1) @@ -1137,7 +1262,7 @@ ls='-', lw=1 ): - """Plot the isomap + """Plot the isomap. Args: yname (string, optional, auto/eef/ekin): Select the y variable; @@ -1155,7 +1280,6 @@ from ax.pcolormesh. """ - xname = 'kx' xax = self.krho @@ -1198,20 +1322,19 @@ def export_as_nxs( self, - file_path_nxs, + file_path, yname='auto', title='NavARP_isok' ): - """Save the isomap as NXdata nexus class + """Save the isomap as NXdata nexus class. Args: yname (string, optional, auto/eef/ekin): Select the y variable; title (string, optiona): data title. """ - yax, yname = self.get_yax(yname) - f = h5py.File(file_path_nxs, "w") # create the HDF5 NeXus file + f = h5py.File(file_path, "w") # create the HDF5 NeXus file f.attrs[u"default"] = u"isok" nxdata = f.create_group(u"isok") @@ -1219,23 +1342,27 @@ nxdata.create_dataset(u"title", data=title) - axes_names = ['momentum', ''] - xdata = nxdata.create_dataset(axes_names[0], data=self.krho) + axes_names = ['', 'momentum'] + xdata = nxdata.create_dataset(axes_names[1], data=self.krho) xdata.attrs[u"units"] = u"1/angstrom" - xdata.attrs[u"axis"] = 1 + xdata.attrs[u"axis"] = 2 xdata.attrs[u"primary"] = 1 if yname == 'eef': - axes_names[1] = "binding_energies" + axes_names[0] = "binding_energies" else: - axes_names[1] = "kinetic_energies" - ydata = nxdata.create_dataset(axes_names[1], data=yax) - ydata.attrs[u"axis"] = 2 + axes_names[0] = "kinetic_energies" + ydata = nxdata.create_dataset(axes_names[0], data=yax) + ydata.attrs[u"axis"] = 1 ydata.attrs[u"primary"] = 1 ydata.attrs[u"units"] = u"eV" data_nx = nxdata.create_dataset( - u"data", data=self.data, compression='gzip', chunks=True) + u"data", + data=self.data.transpose(), + compression='gzip', + chunks=True + ) data_nx.attrs[u"units"] = u"counts" nxdata.attrs[u"signal"] = u"data" @@ -1245,18 +1372,17 @@ def export_as_itx( self, - file_path_itx, + file_path, yname='auto', wave_name='NavARP_isok' ): - """Save the isomap as Igor Text file + """Save the isomap as Igor Pro Text file. Args: xname (string, optional, auto/tht/kx): Select the x variable; yname (string, optional, auto/eef/ekin): Select the y variable; wave_name (string, optiona): name of the wave. """ - xax = self.krho yax, yname = self.get_yax(yname) @@ -1283,7 +1409,7 @@ ) np.savetxt( - file_path_itx, + file_path, self.data, fmt='%.6f', delimiter=' ', @@ -1293,3 +1419,23 @@ comments='', encoding=None ) + + +def postprocessing(data, sigma, order, curvature): + """Post-processing procedure on data.""" + if order == 0: + return gaussian_filter(data, sigma, order) + elif order == 1: + return data**3/gaussian_gradient_magnitude(data, sigma) + elif order == 2: + if isinstance(sigma, (list, tuple, np.ndarray)): + return gaussian_laplace(data, sigma) + else: + if curvature is not None: + dev1pwr2 = gaussian_filter(data, sigma, order=1)**2 + dev2 = gaussian_filter(data, sigma, order=2) + curv_max = curvature*abs( + np.nanmax(dev1pwr2) - np.nanmin(dev1pwr2)) + return dev2*np.power((curv_max + dev1pwr2), -1.5) + else: + return gaussian_filter(data, sigma, order) diff -Nru navarp-1.0.0/navarp/utils/kinterp.py navarp-1.3.0/navarp/utils/kinterp.py --- navarp-1.0.0/navarp/utils/kinterp.py 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/navarp/utils/kinterp.py 2021-12-15 13:48:00.000000000 +0000 @@ -441,7 +441,7 @@ isoscan, kbins, kind="cubic", - fill_value="extrapolate", + fill_value=np.nan, assume_sorted=True ): """Interpolate isoscan on the generated uniform binned k vector @@ -500,7 +500,7 @@ energies, isoscan, kind="nearest", - fill_value="extrapolate", + fill_value=np.nan, assume_sorted=True ): """Interpolate isoscan on the k vector diff -Nru navarp-1.0.0/navarp/utils/navfile.py navarp-1.3.0/navarp/utils/navfile.py --- navarp-1.0.0/navarp/utils/navfile.py 2021-06-09 16:23:35.000000000 +0000 +++ navarp-1.3.0/navarp/utils/navfile.py 2021-12-15 13:48:00.000000000 +0000 @@ -53,6 +53,10 @@ def decode_h5py(string): + """Get only the string in the case of np.ndarray or byte.""" + if isinstance(string, np.ndarray): + string = string[0] + try: string = string.decode("utf-8") except (UnicodeDecodeError, AttributeError): @@ -61,7 +65,7 @@ class NavAnalyzer: - """NavAnalyzer is the class for the analyzer and its geometry + """NavAnalyzer is the class for the analyzer and its geometry. NavAnalyzer is defined from the NavEntry, and it considers the experimental set-ups of Lorea/ALBA(ES), I05/Diamond(GB), SXARPES-ADRESS/PSI(CH) and @@ -73,8 +77,6 @@ phi_ap (float): Angle between analyzer axis (a) and photons (p) along the plane perpendicular to the slit (phi, so the name "phi_ap"); work_fun (float): analyzer work function; - deflector (Boolean): If True, the analyzer is using a deflector, so it - can collect electrons out from the slit plane; scan_type (str): Acquisition method. _set_def_lorea_alba: Set defaul values for Lorea/ALBA(ES) @@ -83,54 +85,47 @@ _set_def_antares_soleil: Set defaul values for Antares/Soleil(FR) """ - def __init__(self, tht_ap=50, phi_ap=0, work_fun=4.5, deflector=False): + def __init__(self, tht_ap=50, phi_ap=0, work_fun=4.5): self.tht_ap = tht_ap self.phi_ap = phi_ap self.work_fun = work_fun - self.deflector = deflector def get_attr(self): - return self.tht_ap, self.phi_ap, self.work_fun, self.deflector + return self.tht_ap, self.phi_ap, self.work_fun - def set_attr(self, tht_ap, phi_ap, work_fun, deflector): + def set_attr(self, tht_ap, phi_ap, work_fun): self.tht_ap = tht_ap self.phi_ap = phi_ap self.work_fun = work_fun - self.deflector = deflector def _set_def_lorea_alba(self): self.tht_ap = 55 self.phi_ap = 0 self.work_fun = 4.6 - self.deflector = True def _set_def_i05_diamond(self): self.tht_ap = 0 self.phi_ap = 50 self.work_fun = 4.5 - self.deflector = False def _set_def_sxarpes_psi(self): self.tht_ap = -70 self.phi_ap = 0 self.work_fun = 4.5 - self.deflector = False def _set_def_antares_soleil(self): self.tht_ap = 55 self.phi_ap = 0 self.work_fun = 4.5 - self.deflector = True def _set_def_cassiopee_soleil(self): self.tht_ap = 0 self.phi_ap = 50 self.work_fun = 4.5 - self.deflector = False class NavEntry: - """NavEntry is the class for the data to be explored by NavARP + """NavEntry is the class for the data to be explored by NavARP. Args: scans (ndarray): scan axis of the acquisition method; @@ -184,10 +179,19 @@ def __init__(self, scans, angles, energies, data, scan_type, hv, defl_angles=0, analyzer=NavAnalyzer(), file_note="", file_path=""): + """Class initialization.""" self.scans = scans - self.angles = angles self.energies = energies - self.data = data + # energies and angles cannot have the same dimension otherwise the + # code cannot recognize automatically recognize them in the plots + # showing sometimes transposed data showing wrongly exchanged axes + # so check if angles and energies has the same length + if len(angles) == len(energies): # if true remove last angle value + self.angles = angles[:-1] + self.data = data[:, :-1, :] + else: + self.angles = angles + self.data = data self.scan_type = scan_type self.hv = hv self.defl_angles = defl_angles @@ -202,8 +206,7 @@ self.valid_kspace = False def init_ebins(self): - """Initialize the fermi level (efermi) and the binding enrgies (ebins). - """ + """Initialize fermi level (efermi) and binding energies (ebins).""" # get fermi level and binding energies if (self.scan_type == "hv") or (self.scan_type == "repeated"): self.energies_init = np.copy(self.energies) @@ -258,13 +261,13 @@ self.ebins = self.energies - self.efermi def autoset_efermi( - self, - energy_range=None, - angle_range=None, - scan_range=None, - print_out=True + self, + energy_range=None, + angle_range=None, + scan_range=None, + print_out=True ): - """Find fermi level using logaritmic derivative and then fit + """Find fermi level using logaritmic derivative and then fit. Args: energy_range (ndarray): Energy range where to find fermi level @@ -275,7 +278,6 @@ [min, max]; print_out (boolean, optional): If True, print the obtained values. """ - self.efermi_fit_input = [energy_range, angle_range, scan_range] if angle_range is not None: angle_ind = np.where( @@ -355,15 +357,14 @@ ) def plt_efermi_fit(self, axfit=None, scan_i=0): - """Plot the fermi level fit result + """Plot the fermi level fit result. Args: axfit (matplotlib.axes, optional): Axes, if None it is created - inside the function + inside the function; scan_i (integer): scans index, in the case of efermi fit for - each image along the scan axis; + each image along the scan axis. """ - try: [energy_range, angle_range, scan_range] = self.efermi_fit_input except AttributeError: @@ -438,7 +439,7 @@ hv_p=None, print_out=True ): - """Calculates angle between analyzer axis (a) and normal (n) to the + """Set angle between analyzer axis (a) and normal (n) to the surface along the plane of the slit (theta, so the name "tht_an"). Note: @@ -458,7 +459,6 @@ requested if p_hv==True; print_out (boolean, optional): If True, print the obtained values. """ - if hv_p is None: hv_p = self.hv @@ -488,7 +488,7 @@ k_perp_slit_for_kz=0, print_out=True ): - """Calculates tht_an, phi_an, scans_0 and phi. + """Set tht_an, phi_an, scans_0 and phi. Args: tht_p (float): Angular value of the reference point along the @@ -505,7 +505,6 @@ requested if p_hv==True; print_out (boolean, optional): If True, print the obtained values. """ - if hv_p is None: hv_p = self.hv @@ -655,12 +654,11 @@ curvature ) else: - raise AttributeError( - 'No valid kspace, do set_kspace() first') + raise AttributeError('No valid kspace, do set_kspace() first') def load(file_path): - """The function define NavEntry from file_path. + """Load the NavEntry from file_path. The function loads entry from: * NXarpes file from LOREA/ALBA(ES) and I05/Diamond(GB); @@ -702,7 +700,6 @@ Returns: NavEntry (class): the class for the data to be explored by NavARP. """ - error_msg = ( 'Data format error.\n' + 'Unknown file structure, the only supported data are:\n' + @@ -797,7 +794,7 @@ def load_sxarpes_adress(h5f, file_path): - """Load data from SXARPES-ADRESS/PSI(CH) + """Load data from SXARPES-ADRESS/PSI(CH). Args: h5f: The HDF5 file-object from h5py.File. @@ -806,14 +803,12 @@ Returns: NavEntry (class): the class for the data to be explored by NavARP. """ - # analyzer analyzer = NavAnalyzer() analyzer._set_def_sxarpes_psi() # deflector angles - if not analyzer.deflector: - defl_angles = 0 + defl_angles = 0 # data h5f_data = h5f["/Matrix"] @@ -921,7 +916,7 @@ def load_nxarpes(h5f, file_path): - """Load NXARPES data from LOREA/ALBA(ES) and I05/Diamond(GB) + """Load NXARPES data from LOREA/ALBA(ES) and I05/Diamond(GB). Args: h5f: The HDF5 file-object from h5py.File. @@ -929,7 +924,6 @@ Returns: NavEntry (class): the class for the data to be explored by NavARP. """ - # analyzer analyzer = NavAnalyzer() instrument_name = h5f["entry1/instrument/name"][()] @@ -947,9 +941,6 @@ return entry h5fdic = { - 'pol': ( - "entry1/instrument/insertion_device/beam/final_polarisation_label" - ), 'hv': "entry1/instrument/monochromator/energy", 'slit': "entry1/instrument/monochromator/exit_slit_size", 'lens_mode': "entry1/instrument/analyser/lens_mode", @@ -960,7 +951,6 @@ 'x': "entry1/instrument/manipulator/sax", 'y': "entry1/instrument/manipulator/say", 'z': "entry1/instrument/manipulator/saz", - 't_frame': "entry1/instrument/analyser/time_for_frames", 't_channel': "entry1/instrument/analyser/time_per_channel", } @@ -968,11 +958,21 @@ for key in h5fdic: params[key] = h5f[h5fdic[key]][()] + # polarisation angles + if "lorea" in instrument_name: + params['pol'] = h5f[ + "entry1/instrument/insertion_device/beam/final_polarisation" + ][()] + elif "i05" in instrument_name: + params['pol'] = h5f[ + "entry1/instrument/insertion_device/beam/final_polarisation_label" + ][()] + # deflector angles - if not analyzer.deflector: - params['deflector'] = np.array([0.]) - else: + if "lorea" in instrument_name: params['deflector'] = h5f["entry1/instrument/analyser/defl_angles"][()] + elif "i05" in instrument_name: + params['deflector'] = np.array([0.]) # angles angles = h5f["entry1/instrument/analyser/angles"][()] @@ -1041,7 +1041,7 @@ energies, data, scan_type, - params[key], + params['hv'], params['deflector'], analyzer, file_note, @@ -1050,7 +1050,7 @@ def load_nxarpes_simulated(h5f, file_path): - """Load NXARPES example + """Load NXARPES example. Args: h5f: The HDF5 file-object from h5py.File. @@ -1058,7 +1058,6 @@ Returns: NavEntry (class): the class for the data to be explored by NavARP. """ - analyzer = NavAnalyzer() analyzer._set_def_lorea_alba() @@ -1100,7 +1099,7 @@ def load_nxarpes_generic(h5f, file_path): - """Load generic NXARPES as saved by save_nxarpes_generic + """Load generic NXARPES as saved by save_nxarpes_generic. Args: h5f: The HDF5 file-object from h5py.File. @@ -1160,7 +1159,7 @@ def load_nxsantares(h5f, file_path): - """Load NEXUS file from Antares/Soleil(FR) + """Load NEXUS file from Antares/Soleil(FR). Args: h5f: The HDF5 file-object from h5py.File. @@ -1168,7 +1167,6 @@ Returns: NavEntry (class): the class for the data to be explored by NavARP. """ - # analyzer analyzer = NavAnalyzer() analyzer._set_def_antares_soleil() @@ -1176,10 +1174,7 @@ fst_grp = list(h5f.keys())[0] # deflector angles - if not analyzer.deflector: - defl_angles = 0 - else: - defl_angles = h5f[fst_grp+"/scan_data/actuator_1_1"][()] + defl_angles = h5f[fst_grp+"/scan_data/actuator_1_1"][()] # scans and scan_type scans = defl_angles @@ -1247,7 +1242,7 @@ def load_cassiopee(file_path): - """Load ARPES data from Cassiopee/Soleil(FR) + """Load ARPES data from Cassiopee/Soleil(FR). Args: path: file path of a ROI-file in the folder. @@ -1255,14 +1250,12 @@ Returns: NavEntry (class): the class for the data to be explored by NavARP. """ - # analyzer analyzer = NavAnalyzer() analyzer._set_def_cassiopee_soleil() # deflector angles - if not analyzer.deflector: - defl_angles = 0 + defl_angles = 0 file_dir = os.path.abspath(os.path.dirname(file_path)) @@ -1414,9 +1407,8 @@ Returns: NavEntry (class): the class for the data to be explored by NavARP. """ - # analyzer - analyzer = NavAnalyzer(tht_ap=50, phi_ap=0, work_fun=4.5, deflector=True) + analyzer = NavAnalyzer(tht_ap=50, phi_ap=0, work_fun=4.5) # Load the zip file entry_zip = np.load(file_path) @@ -1506,7 +1498,6 @@ Returns: NavEntry (class): the class for the data to be explored by NavARP. """ - # Select the correct loading function depending on the first line with open(file_path) as fdat: line = fdat.readline() @@ -1528,7 +1519,6 @@ Returns: NavEntry (class): the class for the data to be explored by NavARP. """ - # Load the txt-file params = {} with open(file_path) as fdat: @@ -1558,13 +1548,17 @@ energies = np.array( params["Dimension 1 scale"].replace(',', '.').split() ).astype(np.float) - hv = np.array([ - float(params['Excitation Energy'].replace(',', '.'))]) + if 'Excitation Energy' in params: + hv = np.array([ + float(params['Excitation Energy'].replace(',', '.'))]) + else: + # WARNING: can't find photon energy (hv), using default of 123 + hv = np.array([123]) len_ang = len(angles) len_en = len(energies) - if "Dimension 3 size": + if "Dimension 3 size" in params: defl_angles = np.array( params["Dimension 3 scale"].replace(',', '.').split() ).astype(np.float) @@ -1660,7 +1654,7 @@ NavEntry (class): the class for the data to be explored by NavARP. """ # analyzer - analyzer = NavAnalyzer(tht_ap=50, phi_ap=0, work_fun=4.5, deflector=False) + analyzer = NavAnalyzer(tht_ap=50, phi_ap=0, work_fun=4.5) # Load the sp2-file params = {} @@ -1722,33 +1716,48 @@ Returns: NavEntry (class): the class for the data to be explored by NavARP. """ - # analyzer - analyzer = NavAnalyzer(tht_ap=50, phi_ap=0, work_fun=4.6, deflector=False) + analyzer = NavAnalyzer(tht_ap=50, phi_ap=0, work_fun=4.6) file_open = open(file_path, 'rb') # first 4-bytes integer is 3-times the number of images len_scan = int.from_bytes(file_open.read(4), "little")//3 + file_starts = int.from_bytes(file_open.read(4), "little") + if file_starts == 0: + is64bit = True + else: + is64bit = False + # going back before reading the file_start + file_open.seek(4) # the point array and size (pas) of the images are in the following bytes nums = len_scan*3 - pas = np.frombuffer(file_open.read(nums*4), dtype=' 1: params[linattr_sp[0]] = linattr_sp[1] - x_scale = np.linspace( - float(params['XScaleMin']), - float(params['XScaleMax']), - int(params['NoS']) - ) e_kin = np.linspace( float(params['Start K.E.']), float(params['End K.E.']), int(params['No. Steps']) ) - defl_angles = np.linspace( - float(params['YScaleMin']), - float(params['YScaleMax']), - int(len_scan) - ) + + if is64bit: + x_scale = np.linspace( + float(params['ScaleMin']), + float(params['ScaleMax']), + int(params['NoS']) + ) + if len_scan != 1: + defl_angles = np.linspace( + float(params['MapStartX']), + float(params['MapEndX']), + int(len_scan) + ) + else: + x_scale = np.linspace( + float(params['XScaleMin']), + float(params['XScaleMax']), + int(params['NoS']) + ) + if len_scan != 1: + defl_angles = np.linspace( + float(params['YScaleMin']), + float(params['YScaleMax']), + int(len_scan) + ) # reading all the images for i in range(len_scan): # going in the image position using the pointer - file_open.seek(pas[i*3]*4) + if is64bit: + file_open.seek(pas[i*3]*4) + else: + file_open.seek(pas[i*3]*4) data[i, :, :] = np.frombuffer( file_open.read((len_en*len_ang)*4), dtype='