commit a222072b2838a685236c37196cfe3c3d7e4b5ea0 Author: dominik Date: Tue Mar 8 10:27:40 2022 +0100 First commit diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..8c9b2d5 --- /dev/null +++ b/Makefile @@ -0,0 +1,42 @@ +.PHONY: clean + +#binaries +PYUIC = pyuic5 +PYRCC = pyrcc5 + +#Directory with ui files +RESOURCE_DIR = resources/_ui + +#Directory for compiled resources +COMPILED_DIR = nmreval/gui_qt/_py + +#UI files to compile, uses every *.ui found in RESOURCE_DIR +UI_FILES = $(foreach dir, $(RESOURCE_DIR), $(notdir $(wildcard $(dir)/*.ui))) +COMPILED_UI = $(UI_FILES:%.ui=$(COMPILED_DIR)/%.py) + +SVG_FILES = $(foreach dir, $(RCC_DIR), $(notdir $(wildcard $(dir)/*.svg))) +PNG_FILES = $(SVG_FILES:%.svg=$(RCC_DIR)/%.png) + +all : ui + +ui : $(COMPILED_UI) + +rcc: $(PNG_FILES) + + +$(COMPILED_DIR)/%.py : $(RESOURCE_DIR)/%.ui + $(PYUIC) $< -o $@ +# replace import of ressource to correct path +# @sed -i s/images_rc/nmrevalqt.$(COMPILED_DIR).images_rc/g $@ +# @sed -i /images_rc/d $@ + +$(RCC_DIR)/%.png : $(RCC_DIR)/%.svg + convert -background none $< $@ + $(PYRCC) $(RCC_DIR)/images.qrc -o $(COMPILED_DIR)/images_rc.py + +clean: + find . -name '*.pyc' -exec rm -f {} + + find . -name '*.pyo' -exec rm -f {} + + find . -name '*~' -exec rm -f {} + + find . -name '__pycache__' -exec rm -fr {} + + diff --git a/__init__.py b/__init__.py new file mode 100755 index 0000000..6860c71 --- /dev/null +++ b/__init__.py @@ -0,0 +1,2 @@ + +from .version import __version__, __releasename__ diff --git a/bin/evaluate.py b/bin/evaluate.py new file mode 100755 index 0000000..7fbd533 --- /dev/null +++ b/bin/evaluate.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +import sys +# pyqtgraph warns on Mac if QApplication is created when it is imported +import pyqtgraph + +from nmreval.lib.logger import handle_exception +sys.excepthook = handle_exception + +from nmreval.gui_qt import App +from nmreval.gui_qt.main.mainwindow import NMRMainWindow + +app = App([]) + +mplQt = NMRMainWindow() +mplQt.show() + +sys.exit(app.exec()) diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..6cfe3d2 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= /autohome/dominik/miniconda3/bin/sphinx-build +SOURCEDIR = /autohome/dominik/nmreval/docs/source +BUILDDIR = /autohome/dominik/nmreval/docs/build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..9534b01 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/source/_static/fit_dialog.png b/docs/source/_static/fit_dialog.png new file mode 100644 index 0000000..559aa14 Binary files /dev/null and b/docs/source/_static/fit_dialog.png differ diff --git a/docs/source/_static/logo.png b/docs/source/_static/logo.png new file mode 100644 index 0000000..9cab63d Binary files /dev/null and b/docs/source/_static/logo.png differ diff --git a/docs/source/_templates/autosummary.rst b/docs/source/_templates/autosummary.rst new file mode 100644 index 0000000..0f54333 --- /dev/null +++ b/docs/source/_templates/autosummary.rst @@ -0,0 +1,25 @@ +{{ fullname | escape | underline }} + + +.. currentmodule:: {{ module }} + + +{% if objtype in ['class'] %} + +Inheritance diagram + +.. inheritance-diagram:: {{ objname }} + :parts: 1 + +{{ objtype }} + +.. auto{{ objtype }}:: {{ objname }} + :special-members: __call__ + :members: + :undoc-members: + +{% else %} +.. auto{{ objtype }}:: {{ objname }} + +{% endif %} + diff --git a/docs/source/api/data.rst b/docs/source/api/data.rst new file mode 100644 index 0000000..616a808 --- /dev/null +++ b/docs/source/api/data.rst @@ -0,0 +1,23 @@ +************** +Data container +************** + +.. automodule:: nmreval.data + :no-members: + :no-undoc-members: + + +.. contents:: Table of Contents + :depth: 3 + :local: + :backlinks: entry + + +.. autosummary:: + :toctree: generated/ + :template: autosummary.rst + :nosignatures: + + nmreval.data.Points + nmreval.data.Signal + nmreval.data.BDS diff --git a/docs/source/api/distributions/index.rst b/docs/source/api/distributions/index.rst new file mode 100644 index 0000000..cf1fadd --- /dev/null +++ b/docs/source/api/distributions/index.rst @@ -0,0 +1,29 @@ +********************************* +Distribution of correlation times +********************************* + +List of all implemented distributions and the associated correlation functions, spectral densities, susceptibilies + +.. contents:: Table of Contents + :depth: 3 + :local: + :backlinks: entry + +Cole-Cole +--------- + +.. automodule:: nmreval.distributions.colecole + :members: + + +Cole-Davidson +------------- + +.. automodule:: nmreval.distributions.coledavidson + :members: + +Havriliak-Negami +---------------- + +.. automodule:: nmreval.distributions.havriliaknegami + :members: diff --git a/docs/source/api/generated/nmreval.data.BDS.rst b/docs/source/api/generated/nmreval.data.BDS.rst new file mode 100644 index 0000000..0818b3b --- /dev/null +++ b/docs/source/api/generated/nmreval.data.BDS.rst @@ -0,0 +1,23 @@ +nmreval.data.BDS +================ + + +.. currentmodule:: nmreval.data + + + + +Inheritance diagram + +.. inheritance-diagram:: BDS + :parts: 1 + +class + +.. autoclass:: BDS + :special-members: __call__ + :members: + :undoc-members: + + + \ No newline at end of file diff --git a/docs/source/api/generated/nmreval.data.Points.rst b/docs/source/api/generated/nmreval.data.Points.rst new file mode 100644 index 0000000..16d7d60 --- /dev/null +++ b/docs/source/api/generated/nmreval.data.Points.rst @@ -0,0 +1,23 @@ +nmreval.data.Points +=================== + + +.. currentmodule:: nmreval.data + + + + +Inheritance diagram + +.. inheritance-diagram:: Points + :parts: 1 + +class + +.. autoclass:: Points + :special-members: __call__ + :members: + :undoc-members: + + + \ No newline at end of file diff --git a/docs/source/api/generated/nmreval.data.Signal.rst b/docs/source/api/generated/nmreval.data.Signal.rst new file mode 100644 index 0000000..c913f1d --- /dev/null +++ b/docs/source/api/generated/nmreval.data.Signal.rst @@ -0,0 +1,23 @@ +nmreval.data.Signal +=================== + + +.. currentmodule:: nmreval.data + + + + +Inheritance diagram + +.. inheritance-diagram:: Signal + :parts: 1 + +class + +.. autoclass:: Signal + :special-members: __call__ + :members: + :undoc-members: + + + \ No newline at end of file diff --git a/docs/source/api/index.rst b/docs/source/api/index.rst new file mode 100644 index 0000000..acbad32 --- /dev/null +++ b/docs/source/api/index.rst @@ -0,0 +1,12 @@ +========== +References +========== + +.. toctree:: + :caption: Table of contents + :maxdepth: 2 + :glob: + + data.rst + models/index.rst + distributions/index.rst diff --git a/docs/source/api/models/basic.rst b/docs/source/api/models/basic.rst new file mode 100644 index 0000000..e87e570 --- /dev/null +++ b/docs/source/api/models/basic.rst @@ -0,0 +1,6 @@ +************************ +``nmreval.models.basic`` +************************ + +.. automodule:: nmreval.models.basic + :members: \ No newline at end of file diff --git a/docs/source/api/models/index.rst b/docs/source/api/models/index.rst new file mode 100644 index 0000000..006cb95 --- /dev/null +++ b/docs/source/api/models/index.rst @@ -0,0 +1,31 @@ +************** +Model function +************** + +List of all implemented functions + +.. contents:: Table of Contents + :depth: 3 + :local: + :backlinks: entry + +Basic functions +--------------- + +.. currentmodule:: nmreval + +.. autosummary:: + :toctree: + + nmreval.models.basic + + + + +NMR relaxation functions +------------------------ + +.. automodule:: nmreval.models.relaxation + :members: + + diff --git a/docs/source/api/models/nmreval.models.basic.rst b/docs/source/api/models/nmreval.models.basic.rst new file mode 100644 index 0000000..17cfa50 --- /dev/null +++ b/docs/source/api/models/nmreval.models.basic.rst @@ -0,0 +1,37 @@ +nmreval.models.basic +==================== + +.. automodule:: nmreval.models.basic + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + Constant + ExpFunc + Linear + Log + MittagLeffler + Parabola + PowerLaw + PowerLawCross + Sine + + + + + + + + + diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..3d36539 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,424 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# 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 sys +import sphinx_bootstrap_theme +sys.path.append('/autohome/dominik/nmreval') +import nmreval + + +# -- Project information ----------------------------------------------------- +project = 'NMREval' +author = 'Dominik Demuth' +copyright = '2022, Dominik Demuth' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version +release = nmreval.__version__ +# The full version, including alpha/beta/rc tags. +version = release + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.inheritance_diagram', + 'sphinx.ext.napoleon', + 'sphinx.ext.viewcode', + 'sphinx.ext.intersphinx', +] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# +# today = '' +# +# Else, today_fmt is used as the format for a strftime call. +# +# today_fmt = '%B %d, %Y' + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# +add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# +add_module_names = False + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# +# show_authors = False + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +# html_theme = 'bootstrap' +html_theme = 'pydata_sphinx_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = { +# # 'source_link_position': "footer", +# 'bootswatch_theme': "cosmo", +# 'navbar_title': "Welcome to hell", +# 'navbar_sidebarrel': True, +# 'nosidebar': False, +# 'body_max_width': '100%', +# 'navbar_links': [ +# ('User guide', 'user_guide/index'), +# ('References', 'api/index'), +# ], +# } +html_theme_options = { + 'collapse_navigation': False, + 'show_prev_next': False, + 'navbar_end': ['navbar-icon-links.html', 'search-field.html'], + 'show_toc_level': 3 +} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() + +# The name for this set of Sphinx documents. +# " v documentation" by default. +# +# html_title = u'NMREval v0.0.1' + +# 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, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# (Optional) Logo. Should be small enough to fit the navbar (ideally 24x24). +# Path should be relative to the ``_static`` files directory. +html_logo = '_static/logo.png' + +# Custom sidebar templates, maps document names to template names. +html_sidebars = {'**': ['sidebar-nav-bs.html']} +# html_sidebars = { +# '**': ['localtoc.html', 'relations.html', 'sourcelink.html', 'searchbox.html'], +# } + +# If true, links to the reST sources are added to the pages. +html_show_sourcelink = False + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +html_last_updated_fmt = '' + +# Additional templates that should be rendered to pages, maps page names to +# template names. +html_additional_pages = {} + +# If false, no module index is generated. +html_domain_indices = False + +# If false, no index is generated. +html_use_index = True + +# If true, the index is split into individual pages for each letter. +html_split_index = False + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +html_file_suffix = None + +# Output file base name for HTML help builder. +# htmlhelp_basename = 'pydoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'NMREval.tex', u'NMREval Documentation', + u'Dominik Demuth', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# +# latex_use_parts = False + +# If true, show page references after internal links. +# +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# +# latex_appendices = [] + +# It false, will not define \strong, \code, itleref, \crossref ... but only +# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added +# packages. +# +# latex_keep_old_macro_names = True + +# If false, no module index is generated. +# +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'nmreval', u'NMREval Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +# +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'NMREval', u'NMREval Documentation', + author, 'NMREval', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +# +# texinfo_appendices = [] + +# If false, no module index is generated. +# +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# +# texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project +epub_author = author +epub_publisher = author +epub_copyright = copyright + +# The basename for the epub file. It defaults to the project name. +# epub_basename = project + +# The HTML theme for the epub output. Since the default themes are not +# optimized for small screen space, using the same theme for HTML and epub +# output is usually not wise. This defaults to 'epub', a theme designed to save +# visual space. +# +# epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or 'en' if the language is not set. +# +# epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +# epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +# +# epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +# +# epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +# +# epub_pre_files = [] + +# HTML files that should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +# +# epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +# +# epub_tocdepth = 3 + +# Allow duplicate toc entries. +# +# epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +# +# epub_tocscope = 'default' + +# Fix unsupported image types using the Pillow. +# +# epub_fix_images = False + +# Scale large images. +# +# epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# epub_show_urls = 'inline' + +# If false, no index is generated. +# +# epub_use_index = True + + +# configuration for intersphinx +intersphinx_mapping = { + 'Pillow': ('https://pillow.readthedocs.io/en/stable/', None), + 'cycler': ('https://matplotlib.org/cycler/', None), + 'dateutil': ('https://dateutil.readthedocs.io/en/stable/', None), + 'ipykernel': ('https://ipykernel.readthedocs.io/en/latest/', None), + 'numpy': ('https://numpy.org/doc/stable/', None), + 'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None), + 'pytest': ('https://pytest.org/en/stable/', None), + 'python': ('https://docs.python.org/3/', None), + 'scipy': ('https://docs.scipy.org/doc/scipy/', None), + 'tornado': ('https://www.tornadoweb.org/en/stable/', None), + 'xarray': ('https://xarray.pydata.org/en/stable/', None), + 'PyQt': ('https://www.riverbankcomputing.com/static/Docs/PyQt5/', None), +} + +# autodoc options +autodoc_typehints = 'none' +autodoc_class_signature = 'separated' +autoclass_content = 'class' + +# autosummay options +autosummary_generate = True + diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..98a6339 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,26 @@ +.. NMREval documentation master file, created by + sphinx-quickstart on Sun Feb 20 17:26:03 2022. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +################################### +NMREval documentation +################################### + +.. toctree:: + :maxdepth: 1 + + user_guide/index + + nmr/index + + api/index + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/source/nmr/depake.png b/docs/source/nmr/depake.png new file mode 100644 index 0000000..feafb28 Binary files /dev/null and b/docs/source/nmr/depake.png differ diff --git a/docs/source/nmr/index.rst b/docs/source/nmr/index.rst new file mode 100644 index 0000000..acbe480 --- /dev/null +++ b/docs/source/nmr/index.rst @@ -0,0 +1,8 @@ +============= +NMR specifics +============= + +.. toctree:: + :maxdepth: 2 + + pake \ No newline at end of file diff --git a/docs/source/nmr/pake.rst b/docs/source/nmr/pake.rst new file mode 100644 index 0000000..1e66f6d --- /dev/null +++ b/docs/source/nmr/pake.rst @@ -0,0 +1,43 @@ +.. _nmr.pake: + +Wideline spectra +^^^^^^^^^^^^^^^^ + +Calculation of spectra +---------------------- + +In general, time signals are calculated by integration of all orientations (see also :ref:`list.orienations`): + +.. math:: + g(t) = \int f[\omega_\text{int}(\theta, \phi)t]\sin\theta\,\mathrm{d}\theta\,\mathrm{d}\phi + +with :math:`f(\theta, \phi, t) = \cos[\omega_\text{int}(\theta, \phi) t]` or :math:`\exp[i\omega_\text{int}(\theta) t]` and fourier transform for a spectrum. +However, summation over :math:`\theta`, :math:`\phi`, and calculating :math:`f(\theta, \phi, t)` for each orientation is time consuming. + +Alternatively, if the orientations are equidistant in :math:`\cos\theta`, one can get to the spectrum directly by creating a histogram of :math:`\omega_\text{int}(\theta, \phi)`, thus circumventing a lot of calculations. + + +De-Paked spectra +---------------- + +A superposition of different Pake spectra complicates the evaluation of relaxation times or similar. +The idea is to deconvolute these broad spectra into one line corresponding to relative orientation :math:`\theta = 0` [mccabe97]_. + +For :math:`\omega_\text{int}(\theta) \propto (3\cos^2\theta -1)/2 = P_2(\cos\theta)`, the property :math:`\omega_\text{int}(\theta) = \omega_\text{int}(0) \omega_\text{int}(\theta)` is used to write + +.. math:: + g(t) = \int_0^{1} f[0, \omega_\text{int}(\theta)t]\,\mathrm{d}\cos\theta. + +This way, the integration is not over orientations at one time :math:`t`, but over times at one orientation 0. +After some integrations, rearrangenments, and substitutions, a spectrum can be calculated by + +.. math:: + F(-2\omega) = \sqrt{\frac{3|\omega |}{2\pi}}(1\pm i) \text{FT}[g(t)\sqrt{t}] + +with :math:`1+i` for :math:`\omega > 0` and :math:`1-i` for :math:`\omega > 0`. + +.. figure:: depake.png + :scale: 50 % + + +.. [mccabe97] M.A. McCabe, S.R. Wassail: Rapid deconvolution of NMR powder spectra by weighted fast Fourier transformation, Solid State Nuclear Magnetic Resonance (1997). https://doi.org/10.1016/S0926-2040(97)00024-6 \ No newline at end of file diff --git a/docs/source/user_guide/fit.rst b/docs/source/user_guide/fit.rst new file mode 100644 index 0000000..959e836 --- /dev/null +++ b/docs/source/user_guide/fit.rst @@ -0,0 +1,43 @@ +.. _user_guide.fit: + +============ +Fitting data +============ + +.. image:: ../_static/fit_dialog.png + :scale: 80% + :align: center + +The picture gives an example of dialog to setup and start fits. +First, there is the possibiity to fit different functions, called models to differentiate from the functions inside each +model, to different data simultaneously. +In the given example, two models were would be used during fit: +test1 and test3 use the default model, in this case model a, +while test2 uses model b. + +In the middle column, the functions of model a are currently given in a tree structure: +It is comprised of three functions: a constant, a sine curve, which is a child of the constant, and free diffusion. +Functions can be dragged by mouse to each position, including a child position, and it is possible to switch between the +four basic arithmetic operations (+, -, \*, /) by striking the corresponding key. +Function at the same level, e.g., constant and free diffusion, are evaluated in the given order. +Children of a function take precedence over the following functions. +This means for the given example, that model a is something like + +.. math:: + f(x) = [\text{constant} / \text{sine}] + \text{diffusion} + +It is possible to skip functions by de-selecting it. +This choice alse affects children, even if they are selected. + +The right column gives access to the parameter of selected function, in this case of the free diffusion function. +Here, the parameter :math:`M_0` is linked to the parameter :math:`C` of another constant function of model b +(identifiable by the number behind the name). +Linkage links not only parameter between function but all settings, e.g., if :math:`C` is fixed, :math:`M_0` is fixed. +Some parameters like gradient :math:`g` are predefined as fixed parameters and are lacking any options besides their value. +Upper and lower bounds may be given. +If one or two of the bounds are not given, this parameter is unbounded on the respective side. + +If a parameter has one entry, this value is initial parameter for all data sets. +If the number of entries is greater than the number of data sets, the first :math:`n` values are used. +Here, test1 uses 1 as parameter for :math:`t_{ev}` and test3 uses 3. +If the number of entries is less than the number of data sets, the last value will be used for each additional set. \ No newline at end of file diff --git a/docs/source/user_guide/index.rst b/docs/source/user_guide/index.rst new file mode 100644 index 0000000..2ec252f --- /dev/null +++ b/docs/source/user_guide/index.rst @@ -0,0 +1,11 @@ +========== +User Guide +========== + + +.. toctree:: + :maxdepth: 2 + + read + fit + shift_scale diff --git a/docs/source/user_guide/read.rst b/docs/source/user_guide/read.rst new file mode 100644 index 0000000..a423962 --- /dev/null +++ b/docs/source/user_guide/read.rst @@ -0,0 +1,19 @@ +.. _user_guide.read: + +************* +Reading files +************* + +Supported filetypes are + + * Text files, + * DAMARIS HDF5 files, + * Grace images. + * HP alpha-analyzer EPS files + * NTNMR .tnt files + +DAMARIS HDF files +================= + +After scanning the selected file the program shows a list of the available data. + diff --git a/docs/source/user_guide/shift_scale.rst b/docs/source/user_guide/shift_scale.rst new file mode 100644 index 0000000..45e4b4e --- /dev/null +++ b/docs/source/user_guide/shift_scale.rst @@ -0,0 +1,16 @@ +.. _usage.shift_scale: + +Moving and scaling +^^^^^^^^^^^^^^^^^^ + +Values are always used and displayed in scientific notation *x.yyyyez* where x is a signed single digit larger than 0. +The relative stepsize (by default 0.0001) increases or decreases is always of the same magnitude as the current value, e.g., +1.2345e0 changes by 0.0001, but 1.2345e20 changes by 0.0001e20. +If the step results in a new order of magnitude the value will be adjusted accordingly, i.e., a step from 9.9999e1 to 10.0000e1 will become 1.0000e2. + +.. note:: + This behaviour leads almost always to values different from zero when using the arrow buttons. Please enter it directly to get a value of zero. + +Boxes :guilabel:`log x` and :guilabel:`log y` change the respective axis from a linear to logarithmic scaling and vice versa. + +Every selected set will be recalculated according to :math:`new = scale \cdot old + offset`. \ No newline at end of file diff --git a/nmreval/__init__.py b/nmreval/__init__.py new file mode 100644 index 0000000..d18f409 --- /dev/null +++ b/nmreval/__init__.py @@ -0,0 +1 @@ +__version__ = '0.0.2' diff --git a/nmreval/bds/__init__.py b/nmreval/bds/__init__.py new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/nmreval/bds/__init__.py @@ -0,0 +1 @@ + diff --git a/nmreval/configs.py b/nmreval/configs.py new file mode 100644 index 0000000..84f1a83 --- /dev/null +++ b/nmreval/configs.py @@ -0,0 +1,69 @@ +import configparser +import pathlib +import pickle +import logging.handlers + + +__all__ = ['config_paths', 'read_configuration', 'write_configuration', 'allowed_values', 'write_state', 'read_state'] + + +def config_paths() -> pathlib.Path: + # TODO adjust for different OS + searchpaths = ['~/.local/share/auswerten', '~/.auswerten', '/usr/share/nmreval'] + path = None + for p in searchpaths: + path = pathlib.Path(p).expanduser() + if path.exists(): + break + + if path is None: + raise FileNotFoundError('No valid configuration path found') + + return path + + +def read_configuration() -> configparser.ConfigParser: + try: + config_file = config_paths() / 'nmreval.cfg' + if not config_file.exists(): + write_configuration({'GUI': {'theme': 'normal', 'color': 'light'}}) + # raise FileNotFoundError('Configuration file not found') + # + except FileNotFoundError as e: + raise e + + parser = configparser.ConfigParser() + parser.read(config_file) + + return parser + + +def write_configuration(opts: dict): + config_file = config_paths() / 'nmreval.cfg' + + parser = configparser.ConfigParser() + parser.read_dict(opts) + + with config_file.open('w') as f: + parser.write(f) + + +allowed_values = { + ('GUI', 'theme'): ['normal', 'pokemon'], + ('GUI', 'color'): ['light', 'dark'], +} + + +def write_state(opts: dict): + config_file = config_paths() / 'guistate.ini' + with config_file.open('wb') as f: + pickle.dump(opts, f) + + +def read_state() -> dict: + config_file = config_paths() / 'guistate.ini' + if not config_file.exists(): + return {} + + with config_file.open('rb') as f: + return pickle.load(f) diff --git a/nmreval/data/__init__.py b/nmreval/data/__init__.py new file mode 100755 index 0000000..7b73355 --- /dev/null +++ b/nmreval/data/__init__.py @@ -0,0 +1,5 @@ +from .points import Points +from .signals import Signal +from .bds import BDS +from .dsc import DSC +from .nmr import FID, Spectrum diff --git a/nmreval/data/bds.py b/nmreval/data/bds.py new file mode 100644 index 0000000..086313a --- /dev/null +++ b/nmreval/data/bds.py @@ -0,0 +1,47 @@ +from typing import Any + +import numpy as np +from scipy.signal import savgol_filter + +from . import Points +from .signals import Signal + + +class BDS(Signal): + """ + Extension of Signal for dielectric spectroscopy purposes. + """ + + def __init__(self, x, y, **kwargs: Any): + super().__init__(x, y, **kwargs) + + if np.all(self._x > 0) and not np.allclose(np.diff(self._x), self._x[1]-self._x[0]): + self.dx = self.x[1] / self.x[0] + else: + self.dx = self._x[1] - self._x[0] + + def __repr__(self) -> str: + return f"{self.meta['mode']}: {self.name}" + + def derivative(self, window_length=9) -> Points: + """ + Calculates the derivative :math:`-\\frac{\\pi}{2}\\frac{d\\epsilon'}{d\\ln\\omega}`. + To reduce :func:`scipy.signal.savgol_filter` + + Args: + window_length (int) + + Returns: + Points + New Points instance with + + References: + Wübbenhorst, M.; van Turnhout, J.: Analysis of complex dielectric spectra. + I. One-dimensional derivative techniques and three-dimensional modelling. + J. Non-Cryst. Solid. 305 (2002) https://doi.org/10.1016/s0022-3093(02)01086-4 + + """ + y = -savgol_filter(self.y[self.mask].real, window_length, 2, deriv=1) * np.pi / 2 + data = Points(x=self.x[self.mask], y=y) + data.update(self.meta) + return data diff --git a/nmreval/data/dsc.py b/nmreval/data/dsc.py new file mode 100644 index 0000000..429ddcd --- /dev/null +++ b/nmreval/data/dsc.py @@ -0,0 +1,6 @@ +from .points import Points + + +class DSC(Points): + def __init__(self, x, y, **kwargs): + super().__init__(x, y, **kwargs) diff --git a/nmreval/data/nmr.py b/nmreval/data/nmr.py new file mode 100644 index 0000000..79dc663 --- /dev/null +++ b/nmreval/data/nmr.py @@ -0,0 +1,179 @@ +import warnings +from typing import Union + +import numpy as np + +from .signals import Signal + + +class FID(Signal): + def __init__(self, x, y, **kwargs): + super().__init__(x, y, **kwargs) + + self.meta['apod'] = [] + self.meta['zf'] = 0 + + def __repr__(self): + return f"FID: {self.name}" + + def baseline(self, percentage=0.12): + self._y -= self._y[int(-percentage * self.length):].mean() + + return self + + def apod(self, p, method=None): + try: + self._y *= method.apod(self._x, *p) + self.meta['apod'].append((str(method), p)) + except KeyError: + print(f'Unknown apodization {method}') + + def zerofill(self, pad: int = 1): + _max_x = self._x.max() + + factor = 2**pad + if factor < 1: + self._x = self._x[:int(self.length*factor)] + self._y = self._y[:int(self.length*factor)] + self._y_err = self._y_err[:int(self.length*factor)] + self.mask = self.mask[:int(self.length*factor)] + + elif factor > 1: + add_length = int((factor-1) * self.length) + self._y = np.concatenate((self._y, np.zeros(add_length))) + self._y_err = np.concatenate((self._y_err, np.zeros(add_length))) + self.mask = np.concatenate((self.mask, np.ones(add_length, dtype=bool))) + + _temp_x = np.arange(1, add_length+1) * self.dx + np.max(self._x) + self._x = np.concatenate((self._x, _temp_x)) + + self.meta['zf'] += pad + + return self + + def fourier(self): + ft = np.fft.fftshift(np.fft.fft(self._y)) / self.dx + freq = np.fft.fftshift(np.fft.fftfreq(self.length, self.dx)) + + spec = Spectrum(freq, ft, dx=self.dx) + spec.update(self.meta) + + return spec + + def fft_depake(self, scale: bool = False): + """ + Calculate deconvoluted Pake spectra + M.A. McCabe, S.R. Wassail: + Rapid deconvolution of NMR powder spectra by weighted fast Fourier transformation, + SSNMR (1997), Vol.10, Nr.1-2, pp. 53-61, + """ + _y = self._y + 0 + # Perform FFT depaking + _y *= np.sqrt(self._x) + + # built halves + right = np.fft.fftshift(np.fft.fft(_y)) * (1 + 1j) + left = np.fft.fftshift(np.fft.fft(_y)) * (1 - 1j) + + freq = np.fft.fftshift(np.fft.fftfreq(self.length, self.dx)) + + if scale: + # fourier transform should be multiplied with \sqrt(|omega|) + # but lines at omega=0 are suppressed, so sometimes not a good idea + right *= np.sqrt(np.abs(freq)) + left *= np.sqrt(np.abs(freq)) + + # built depaked spectrum + new_spc = np.concatenate([left[:(self.length//2)], right[(self.length//2):]]) + + spec = Spectrum(2*freq, new_spc, dx=self.dx) + spec.update(self.meta) + + return spec + + def convert(self): + spec = Spectrum(self._x, self._y, dx=self.dx) + self.update(self.meta) + + return spec + + def _calc_noise(self): + # noise per channel, so divide by sqrt(2) + self._y_err = np.std(self._y[-int(0.1*self.length):])/1.41 + return self._y_err * np.ones(self.length) + + def shift(self, points: Union[str, float], mode: str = 'pts'): + """ + + Args: + points : shift value, + mode (str): + + Returns: + + """ + if mode == 'pts': + super().shift(points) + else: + pts = int(points//self.dx) + super().shift(pts) + + +class Spectrum(Signal): + def __init__(self, x, y, dx=None, **kwargs): + super().__init__(x, y, **kwargs) + if dx is None: + if 2 * abs(self._x[0])/len(self._x) - abs(self._x[1]-self._x[0]) < 1e-9: + self.dx = 1/(2 * abs(self._x[0])) + else: + self.dx = 1 + else: + self.dx = dx + + def __repr__(self): + return f"Spectrum: {self.name}" + + def baseline(self, percentage: float = 0.12): + corr = np.mean([self._y[int(-percentage*self.length):], self._y[:int(percentage*self.length)]]) + self._y -= corr + + return self + + def fourier(self): + ft = np.fft.ifft(np.fft.ifftshift(self._y * self.dx)) + t = np.arange(len(ft))*self.dx + shifted = np.fft.ifftshift(self._x)[0] + if shifted != 0: + warnings.warn(f'Shift of {shifted}: Spectrum is not zero-centered and FFT may give wrong results!') + ft *= np.exp(1j * shifted * 2*np.pi*t) + + fid = FID(t, ft) + fid.update(self.meta) + + return fid + + def convert(self): + fid = FID(self._x, self._y) + fid.update(self.meta) + + return fid + + def _calc_noise(self): + step = int(0.05 * self.length) + start = np.argmin(abs(self._x - max(self._x.min(), -2e5))) + stop = np.argmin(abs(self._x - min(self._x.max(), 2e5))) + if start > stop: + stop, start = start, stop + stop -= step + self._y_err = np.inf + for i in range(start, stop): + # scan regions to find minimum noise (undisturbed by signals) + self._y_err = min(np.std(self._y[i:i + step])/np.sqrt(2), self._y_err) + + return self._y_err * np.ones(self.length) + + def shift(self, points, mode='pts'): + if mode == 'pts': + super().shift(points) + else: + return self diff --git a/nmreval/data/points.py b/nmreval/data/points.py new file mode 100644 index 0000000..c143151 --- /dev/null +++ b/nmreval/data/points.py @@ -0,0 +1,665 @@ +import copy +from numbers import Number, Real +from pathlib import Path +from typing import Any, List, Optional, Tuple, TypeVar, Union + +import numpy as np +try: + from scipy.integrate import simpson, cumulative_trapezoid +except ImportError: + from scipy.integrate import simps as simpson, cumtrapz as cumulative_trapezoid + +from ..lib.utils import ArrayLike +from ..utils import NUMBER_RE + +PointLike = TypeVar('PointLike', bound='Points') + +""" +This is a test for all and everything +""" + + +class Points: + """ + Base class for all datatypes + + Args: + x (array_like): x values + y (array_like): y values + y_err (array_like, optional): errors + + """ + def __init__(self, x: ArrayLike, y: ArrayLike, y_err: Optional[ArrayLike] = None, **kwargs: Any): + + self._x, self._y, self._y_err, self.mask = self._prepare_xy(x, y, y_err=y_err) + + name = str(kwargs.pop('name', '')) + value = kwargs.pop('value', None) + self.meta = { + 'group': '', + 'name': name.split('/')[-1] + } + self.meta.update(kwargs) + + if isinstance(value, str): + for m in NUMBER_RE.finditer(value): + value = float(m.group().replace('p', '.')) + + try: + value = float(value) + except ValueError: + value = None + + if value is None: + for m in NUMBER_RE.finditer(name): + value = float(m.group().replace('p', '.')) + if not value: + value = 0.0 + + self.meta['value'] = value + if self.name == '': + self.name = str(value) + + @staticmethod + def _prepare_xy(x: ArrayLike, y: ArrayLike, y_err: Optional[ArrayLike] = None): + x = np.atleast_1d(x).astype(float) + if x.ndim > 1: + raise TypeError('x axis cannot be multidimensional') + + y = np.atleast_1d(y) + if not np.iscomplexobj(y): + y = y.astype(float) + + if x.shape != y.shape: + # remove ugly 1-length dims + x = np.squeeze(x) + y = np.squeeze(y) + if x.shape != y.shape: + raise ValueError(f'x ({x.shape}) and y ({y.shape}) have different shapes') + + mask = np.ones_like(x, dtype=bool) + + if y_err is None: + y_err = np.zeros(y.shape, dtype=float) + + elif isinstance(y_err, Real): + y_err = np.ones(y.shape, dtype=float) * y_err + else: + y_err = np.atleast_1d(y_err) + if y_err.shape != y.shape: + raise ValueError(f'y_err ({y_err.shape}) and y ({y.shape}) have different shapes') + + return x, y, y_err, mask + + @property + def x(self) -> np.ndarray: + return self._x + + @x.setter + def x(self, value: ArrayLike): + value = np.asarray(value, dtype=float) + if value.shape == self._x.shape: + self._x = value + elif value.shape == self._x[self.mask].shape: + self._x = value + self._y = self._y[self.mask] + self._y_err = self._y_err[self.mask] + else: + raise ValueError('Shape mismatch in setting x') + + @property + def y(self) -> np.ndarray: + return self._y + + @y.setter + def y(self, value: ArrayLike): + """ + Set new y values. If the length of the new array equals that of original y including masked points + this is equivalent to a simple assignment. If the length equals the masked points then masked points are + discarded. + + Args: + value: array of the same length as full or masked y + + Returns: + + """ + value = np.asarray(value, dtype=self._y.dtype) + if value.shape == self._y.shape: + self._y = value + elif value.shape == self._y[self.mask].shape: + self._y[self.mask] = value + self._x = self._x[self.mask] + self._y_err = self._y_err[self.mask] + else: + raise ValueError('Shape mismatch in setting y') + + @property + def y_err(self) -> np.ndarray: + return self._y_err + + @y_err.setter + def y_err(self, value: ArrayLike): + value = np.asarray(value, dtype=float) + if value.shape == self._y_err.shape: + self._y_err = value + elif value.shape == self._y_err[self.mask].shape: + self._y[self.mask] = value + else: + raise ValueError('Shape mismatch in setting y_err') + + def __len__(self) -> int: + return len(self._x[self.mask]) + + def __repr__(self) -> str: + return f'Point: {self.name}' + + def __getitem__(self, item: str) -> Any: + try: + return self.meta[item] + except KeyError: + KeyError(f'{item} not found') + + def __setitem__(self, key: str, value: Any): + self.meta[key] = value + + def __delitem__(self, key: str): + del self.meta[key] + + def update(self, opts: dict) -> None: + """ + Update metadata + + Args: + opts: + + Returns: + + """ + self.meta.update(opts) + + def __lshift__(self, other): + if isinstance(other, Real): + _tempx = self._x - other + ret = type(self)(_tempx, self._y) + self.update(self.meta) + + return ret + else: + raise TypeError(f'{other} is not a number') + + def __rshift__(self, other): + return self.__lshift__(-other) + + def __ilshift__(self, other): + if isinstance(other, Real): + self._x -= other + return self + else: + raise TypeError(f'{other} is not a number') + + def __irshift__(self, other): + return self.__ilshift__(-other) + + def __add__(self, other): + """ + Implements self + other + """ + if isinstance(other, Number): + _tempy = self._y + other + ret = type(self)(self._x, _tempy) + ret.update(self.meta) + return ret + elif isinstance(other, self.__class__): + if np.equal(self._x, other.x).all(): + _tempy = self._y + other.y + ret = type(self)(self._x, _tempy) + ret.update(self.meta) + + return ret + else: + raise ValueError('Objects have different x values') + + def __radd__(self, other): + """ + Implements other + self + """ + return self.__add__(other) + + def __iadd__(self, other): + """ + Implements self += other + """ + if isinstance(other, Number): + self._y += other + return self + elif isinstance(other, self.__class__): + # restrict to same x values + if np.equal(self._x, other.x).all(): + self._y += other.y + else: + raise ValueError('Objects have different x values') + return self + + def __neg__(self): + """ + Implements -self + """ + ret = type(self)(self._x, self._y * (-1)) + ret.update(self.meta) + + return ret + + @property + def value(self): + return self.meta['value'] + + @property + def group(self): + return self.meta['group'] + + @group.setter + def group(self, value: str): + self.meta['group'] = str(value) + + @value.setter + def value(self, value: float): + self.meta['value'] = float(value) + + @property + def name(self): + return self.meta['name'] + + @name.setter + def name(self, value): + self.meta['name'] = str(value) + + @property + def length(self): + return len(self._x) + + def points(self, idx: Optional[list] = None, special: Optional[str] = None, + avg_range: Tuple[int, int] = (0, 0), avg_mode: str = 'mean', + pts: Optional[list] = None) -> List[tuple]: + """ + Return (x, y) values at specific positions. + + Args: + idx (list, optional) : List of indexes to evaluate. + special (str, {'max', 'min', 'absmax', 'absmin'}, optional) : + Special positions to extract. + + `max` : Selects position of the maximum of y, or real part if y is complex. + + 'min' : Selects position of the minimum of y, or real part if y is complex. + + 'absmax' : Selects position at the maximum of the absolute value of y. + + 'absmin' : Selects position at the minimum of the absolute value of y. + + avg_range (tuple of int) : + Region for average of y values. Tuple (a, b) uses ``y[i-a:i+b+1]`` around index `i`. Default is (0, 0). + avg_mode (str {'mean', 'sum', 'integral'} , optional) : + Averaging type + + `mean` : Arithmetic average + + `sum`: Sum over y values + + 'integral`: Integration over range using Simpson's rule + + pts (list, optional) : + If given, points will be appended. + + Returns : + list of tuples (x, y, y_err) + """ + + if (idx is None) and (special is None): + raise ValueError('Either `idx` or `special` must be given') + + if avg_mode not in ['mean', 'sum', 'integral']: + raise ValueError(f'Parameter `avg_mode` is `mean`, `sum`, `integral`, not `{avg_mode}`' ) + + if pts is None: + pts = [] + + for x in idx: + if isinstance(x, tuple): + x_idx = np.argmin(np.abs(self._x[self.mask] - (x[0]+x[1])/2)) + left_b = np.argmin(np.abs(self._x[self.mask] - x[0])) + right_b = np.argmin(np.abs(self._x[self.mask] - x[1])) + else: + x_idx = np.argmin(np.abs(self._x[self.mask]-x)) + left_b = int(max(0, x_idx - avg_range[0])) + right_b = int(min(len(self), x_idx + avg_range[1] + 1)) + + if left_b < right_b: + pts.append([self._x[x_idx], *self._average(avg_mode, x_idx, left_b, right_b)]) + else: + pts.append([self._x[x_idx], self._y[x_idx], self._y_err[x_idx]]) + + if special is not None: + if special not in ['max', 'min', 'absmax', 'absmin']: + raise ValueError('Parameter "special" must be "max", "min", "absmax", "absmin".') + + if special == 'max': + x_idx = np.argmax(self._y.real[self.mask]) + elif special == 'min': + x_idx = np.argmax(self._y.real[self.mask]) + elif special == 'absmax': + x_idx = np.argmax(np.abs(self._y[self.mask])) + else: + x_idx = np.argmin(np.abs(self._y[self.mask])) + + left_b = int(max(0, x_idx - avg_range[0])) + right_b = int(min(len(self), x_idx + avg_range[1] + 1)) + + pts.append([self._x[self.mask][x_idx], *self._average(avg_mode, x_idx, left_b, right_b)]) + + return pts + + def _average(self, mode: str, idx, left: int, right: int) -> Tuple[float, float]: + if mode == 'mean': + y_mean = np.mean(self._y[self.mask][left:right].real) + y_err = np.linalg.norm(self._y_err[self.mask][left:right]) / (right - left) + + elif mode == 'sum': + y_mean = np.sum(self._y[self.mask][left:right].real) + y_err = np.linalg.norm(self._y_err[self.mask][left:right]) + + elif mode == 'integral': + y_mean = simpson(self._y[self.mask][left:right].real, x=self._x[left:right]) + y_err = np.linalg.norm(cumulative_trapezoid(self._y_err[self.mask][left:right].real, x=self._x[left:right])) + + else: + y_mean = self._y[self.mask][idx].real + y_err = self._y_err[self.mask][idx] + + return y_mean, y_err + + def concatenate(self, other): + """ + Add the values of an object of the same + + Args: + other: Dataset of same type + + """ + if isinstance(other, self.__class__): + self._x = np.r_[self._x, other.x] + self._y = np.r_[self._y, other.y] + self.mask = np.r_[self.mask, other.mask] + self._y_err = np.r_[self._y_err, other.y_err] + else: + raise TypeError(f'{other} is of type {type(other)}') + + return self + + def integrate(self, log: bool = False, limits: Tuple[float, float] = None) -> PointLike: + new_data = self.copy() + + if limits is not None: + new_data.cut(*limits) + + if log: + new_data.y = cumulative_trapezoid(y=new_data.y, x=np.log(new_data.x), initial=0) + else: + new_data.y = cumulative_trapezoid(y=new_data.y, x=new_data.x, initial=0) + + return new_data + + def diff(self, log: bool = False, limits: Optional[Tuple[float, float]] = None) -> PointLike: + """ + + Args: + log: + limits: + + Returns: + + """ + + new_data = self.copy() + + if limits is not None: + new_data.cut(*limits) + + if log: + new_data.y = np.gradient(new_data.y, np.log(new_data.x)) + else: + new_data.y = np.gradient(new_data.y, new_data.x) + + return new_data + + def magnitude(self) -> PointLike: + new_data = self.copy() + new_data.y.real = np.abs(self.y) + if np.iscomplexobj(new_data.y): + new_data.y.imag = 0. + + return new_data + + def copy(self) -> PointLike: + """ + Copy the object + + Returns: + A copy of the object + """ + return copy.deepcopy(self) + + def get_values(self, idx: int) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + """ + Return values at a given index + + Args: + idx (int) : Index value + + Returns: + Tuple of (`x[idx]`, `y[idx]` , `y_err[idx]`) + """ + return self._x[idx], self._y[idx], self._y_err[idx] + + def set_values(self, idx: int, value: Union[list, tuple, np.ndarray]) -> PointLike: + if not (isinstance(value, (list, tuple, np.ndarray)) and (len(value) in [2, 3])): + raise TypeError('Values should be list type of length 2 or 3') + + self._x[idx] = value[0] + self._y[idx] = value[1] + + if len(value) == 3: + self._y_err[idx] = value[2] + else: + self._y_err[idx] = 0 + + return self + + def set_data(self, + x: Optional[np.ndarray] = None, + y: Optional[np.ndarray] = None, + y_err: Optional[np.ndarray] = None) -> PointLike: + if x is None: + x = self._x + if y is None: + y = self._y + if y_err is not None: + y_err = self._y_err + + self._x, self._y, self._y_err, self.mask = self._prepare_xy(x, y, y_err) + + return self + + def append(self, x: ArrayLike, y: ArrayLike, y_err: Optional[ArrayLike] = None): + x, y, y_err, mask = self._prepare_xy(x, y, y_err) + + self._x = np.r_[self._x, x] + self._y = np.r_[self._y, y] + self._y_err = np.r_[self._y_err, y_err] + self.mask = np.r_[self.mask, mask] + + return self + + def remove(self, idx): + self._x = np.delete(self._x, idx) + self._y = np.delete(self._y, idx) + self.mask = np.delete(self.mask, idx) + self._y_err = np.delete(self._y_err, idx) + + return self + + def cut(self, *limits): + if len(limits) != 2: + raise ValueError('Two arguments are needed') + + low_lim, high_lim = limits + if low_lim is None: + low_lim = np.min(self._x) + + if high_lim is None: + high_lim = np.max(self._x) + + _mask = np.ma.masked_inside(self._x, low_lim, high_lim).mask + + self._x = self._x[_mask] + self._y = self._y[_mask] + self._y_err = self._y_err[_mask] + self.mask = self.mask[_mask] + + return self + + def shift(self, points: int) -> PointLike: + """ + Move y values `points` indexes, remove invalid indexes and fill remaining with zeros + Negative `points` shift to the left, positive `points` shift to the right + + Args: + points (int) : shift value + + Example: + >>> pts = Points(x=[0., 1., 2., 3.], y=[1., 2., 3., 4.]) + >>> pts.shift(2) + >>> pts.x + array([0., 1., 2., 3.]) + >>> pts.y + array([3., 4., 0., 0.]) + + Returns: + The original object with shifted values. + """ + if points > 0: + self._y = np.roll(self._y, -int(points)) + self._y[-int(points)-1:] = 0 + else: + self._y = np.roll(self._y, int(points)) + self._y[:-int(points)] = 0 + + self.meta['shift'] += points + + return self + + def sort(self, axis=0): + if axis == 0: + sort_order = np.argsort(self._x) + else: + sort_order = np.argsort(self._y) + self._x = self._x[sort_order] + self._y = self._y[sort_order] + self._y_err = self._y_err[sort_order] + self.mask = self.mask[sort_order] + + return self + + def normalize(self, mode): + if mode == 'first': + scale = self._y[0].real + elif mode == 'last': + scale = self._y[-1].real + elif mode == 'max': + scale = np.max(self._y.real) + elif mode == 'maxabs': + scale = np.max(np.abs(self._y)) + elif mode == 'area': + try: + from scipy.integrate import simpson + except ImportError: + from scipy.integrate import simps as simpson + scale = simpson(self._y.real, x=self._x) + else: + raise ValueError(f'Unknown normalize mode {mode}') + + self._y /= scale + self._y_err /= scale + + return scale + + def toarray(self, err=True): + if np.count_nonzero(self._y_err) == 0 or not err: + return np.c_[self._x, self._y] + else: + return np.c_[self._x, self._y, self._y_err] + + def tohdf(self, hdffile): + grp = hdffile + grp2_name = self.name + + try: + dset = grp.create_dataset(grp2_name, shape=(len(self._x),), + dtype=np.dtype([('x', 'f'), ('y', 'f')]), + compression='gzip') + except RuntimeError: + dset = grp[grp2_name] + + dset['x'] = self._x + dset['y'] = self._y + dset.attrs['TITLE'] = self.group + '/' + self.name + dset.attrs['damaris_type'] = 'MeasurementResult' + + def savetxt(self, fname, err=False): + path = Path(fname) + + if not path.parent.exists(): + path.parent.mkdir(parents=True) + + header = [] + for k, v in self.meta.items(): + header.append('%s: %s' % (k, str(v))) + header = '\n'.join(header) + + if np.all(self.mask): + np.savetxt(path, self.toarray(err=err), header=header, fmt='%.10f') + else: + with path.open('w') as f: + f.write(header) + for i, l in enumerate(self.toarray(err=err)): + if self.mask[i]: + f.write('\t'.join(map(str, l.tolist())) + '\n') + else: + f.write('#' + '\t'.join(map(str, l.tolist())) + '\n') + + def get_state(self) -> dict: + ret_dic = {'x': self._x.tolist(), + 'y': self._y.tolist(), + 'mask': (np.where(~self.mask)[0]).tolist()} + + if np.all(self._y_err == 0): + ret_dic['y_err'] = 0.0 + else: + ret_dic['y_err'] = self._y_err.tolist() + + ret_dic.update(self.meta) + + return ret_dic + + @classmethod + def set_state(cls, state: dict): + _x = state.pop('x') + _y = state.pop('y') + _yerr = state.pop('y_err') + data = cls(x=_x, y=_y, y_err=_yerr) + _m = state.pop('mask') + data.mask[_m] = False + data.meta.update(state) + + return data + diff --git a/nmreval/data/signals.py b/nmreval/data/signals.py new file mode 100644 index 0000000..222d03e --- /dev/null +++ b/nmreval/data/signals.py @@ -0,0 +1,100 @@ +import numpy as np + + +from .points import Points + + +class Signal(Points): + """ + Extension of Points for complex y values. + """ + + def __init__(self, x, y, **kwargs): + y = np.atleast_1d(y) + if (y.ndim == 1) or y.shape[0] == 1: + y = y.astype(complex) + else: + y = y[0, :] + 1j * y[1, :] + + super().__init__(x, y, **kwargs) + + self.dx = kwargs.get('dx', abs(self._x[1] - self._x[0])) + self.meta.update({'phase': [], 'shift': 0}) + + def __repr__(self): + return 'Signal: ' + self.name + + def swap(self): + """ + + Swaps real and imaginary part of y + + """ + self._y.real, self._y.imag = self._y.imag, self._y.real + + return self + + def phase(self, method: str = 'manual', **kwargs): + if method == 'manual': + self.manual_phase(**kwargs) + elif method == 'simple': + self.simple_phase(**kwargs) + else: + raise KeyError(f'Not implemented method {method}') + + return self + + def manual_phase(self, ph0: float = 0., ph1: float = 0., pvt: float = 0): + self._y *= np.exp(1j * ph0 * np.pi / 180.) + if ph1 != 0: + x = (self._x - pvt) / max(self._x) + self._y *= np.exp(1j * x * ph1 * np.pi / 180.) + self.meta['phase'].append((ph0, ph1, pvt)) + + return self + + def simple_phase(self, pos: int = 0, avg: int = 0): + ph = np.mean(np.angle(self._y)[pos-avg:pos+avg+1]) + self._y *= np.exp(-1j*ph) + + self.meta['phase'].append((ph, 0, 0)) + + return self + + def baseline_spline(self, line): + self._y -= line + + return self + + def divide(self, part): + if part: + self.cut(0.01*self._x[0], self._x[int(self.length//2)+1]) + else: + self.cut(self._x[int(self.length//2)], 10*self._x[-1]) + + return self + + def toarray(self, err=False): + if not err or np.all(self._y_err == 0.): + return np.c_[self._x, self._y.real, self._y.imag] + else: + return np.c_[self._x, self._y.real, self._y.imag, self._y_err] + + def tohdf(self, hdffile): + grp = hdffile + try: + grp2 = grp.create_group(self.name) + is_empty = True + except ValueError: + is_empty = False + grp2 = grp[self.name] + grp2.attrs['damaris_type'] = 'Accumulation' + grp2.attrs['TITLE'] = self.group + '/' + self.name + if is_empty: + grp2.create_dataset('accu_data', data=np.c_[self._y.real, self._y.imag], + compression='gzip') + idx = grp2.create_dataset('indices', (1,), dtype=np.dtype([('dwelltime', 'f')])) + idx['dwelltime'] = self.dx + else: + grp2['accu_data'][...] = np.c_[self._y.real, self._y.imag] + grp2['indices']['dwelltime'] = self.dx diff --git a/nmreval/distributions/__init__.py b/nmreval/distributions/__init__.py new file mode 100644 index 0000000..55d58aa --- /dev/null +++ b/nmreval/distributions/__init__.py @@ -0,0 +1,7 @@ + +from .havriliaknegami import HavriliakNegami +from .colecole import ColeCole +from .coledavidson import ColeDavidson +from .debye import Debye +from .kww import KWW +from .loggaussian import LogGaussian diff --git a/nmreval/distributions/base.py b/nmreval/distributions/base.py new file mode 100644 index 0000000..d89a326 --- /dev/null +++ b/nmreval/distributions/base.py @@ -0,0 +1,85 @@ +import abc +from warnings import warn + +import numpy as np + + +class Distribution(abc.ABC): + name = 'Abstract distribution' + parameter = None + bounds = None + + @classmethod + def __repr__(cls): + return cls.name + + @staticmethod + @abc.abstractmethod + def distribution(taus, tau0, *args): + pass + + @staticmethod + @abc.abstractmethod + def susceptibility(omega, tau, *args): + pass + + @classmethod + def specdens(cls, omega, tau, *args): + return -cls.susceptibility(omega, tau, *args).imag / omega + + @staticmethod + @abc.abstractmethod + def correlation(t, tau0, *args): + pass + + @classmethod + def mean_value(cls, *args, mode='mean'): + if mode == 'mean': + return cls.mean(*args) + if mode == 'logmean': + return np.exp(cls.logmean(*args)) + if mode in ['max', 'peak']: + return cls.max(*args) + + return args[0] + + @classmethod + def convert(cls, *args, from_='raw', to_='mean'): + if from_ == to_: + return args[0] + + if from_ == 'raw': + return cls.mean_value(*args, mode=to_) + else: + # makes only sense as long as mean/peak is given by = factor * x + factor = cls.mean_value(1, *args[1:], mode=from_) + try: + raw = args[0] / factor + except ZeroDivisionError: + raise ZeroDivisionError('Conversion between mean values impossible') + + if to_ == 'raw': + return raw + else: + return cls.mean_value(raw, *args[1:], mode=to_) + + @staticmethod + def logmean(*args): + """ + Return mean logarithmic tau + + Args: + *args: + + Returns: + + """ + return np.log(args[0]) + + @staticmethod + def mean(*args): + return args[0] + + @staticmethod + def max(*args): + return args[0] diff --git a/nmreval/distributions/colecole.py b/nmreval/distributions/colecole.py new file mode 100644 index 0000000..e85c58a --- /dev/null +++ b/nmreval/distributions/colecole.py @@ -0,0 +1,105 @@ +import numpy as np + +from .base import Distribution +from ..math.mittagleffler import mlf + + +class ColeCole(Distribution): + """ + Functions based on Cole-Cole distribution + """ + name = 'Cole-Cole' + parameter = [r'\alpha'] + bounds = [(0, 1)] + + @staticmethod + def distribution(taus, tau0, alpha): + """ + Distribution of correlation times + + .. math:: + G(\ln\\tau) = \\frac{1}{2\pi} \\frac{\\sin(\\pi\\alpha)}{\cosh[\\alpha\ln(\\tau/\\tau_0)] + \cos(\\alpha \pi))} + + Args: + taus: + tau0: + alpha: + """ + z = np.log(taus/tau0) + return np.sin(np.pi*alpha)/(np.cosh(z*alpha) + np.cos(alpha*np.pi))/(2*np.pi) + + @staticmethod + def susceptibility(omega, tau, alpha): + """ + Susceptibility + + .. math:: + \chi(\omega, \\tau, \\alpha) = \\frac{1}{1-(i\omega\\tau_0)^\\alpha} + + Args: + omega: + tau: + alpha: + """ + _tau = np.atleast_1d(tau) + _omega = np.atleast_1d(omega) + val = 1/(1+(1j*_omega[:, None]*_tau[None, :])**alpha) + return np.conjugate(val).squeeze() + + @staticmethod + def specdens(omega, tau, alpha): + """ + Spectral density + + .. math:: + J(\omega, \\tau, \\alpha) = \\frac{\sin(\\alpha\pi/2)(\omega\\tau)^\\alpha}{\omega[1+(\omega\\tau)^{2\\alpha} + 2\\pi\cos(\\alpha\pi/2)(\omega\\tau)^\\alpha]} + + Args: + omega: + tau: + alpha: + """ + _tau = np.atleast_1d(tau) + _omega = np.atleast_1d(omega) + omtau = (_omega*_tau)**alpha + return np.sin(alpha*np.pi/2) * omtau / (1 + omtau**2 + 2*np.cos(alpha*np.pi/2)*omtau) / omega + + @staticmethod + def correlation(t, tau0, alpha): + """ + Correlation function :math:`C(t)` + + .. math:: + C(t) = E_\\alpha[-(t/\\tau_0)^\\alpha] + + with Mittag-Leffler function :math:`E_a(x)` + + Args: + t: + tau0: + alpha: + """ + return mlf(-(t/tau0)**alpha, alpha) + + +if __name__ == '__main__': + import matplotlib.pyplot as plt + + x = np.logspace(-3, 3, num=61) + + fig, ax = plt.subplots(2, 2) + ax[0, 0].set_title('Distribution') + ax[0, 1].set_title('Correlation func.') + ax[1, 0].set_title('Spectral density') + ax[1, 1].set_title('Susceptibility') + + for a in [0.4, 0.6, 0.8]: + ax[0, 0].loglog(x, ColeCole.distribution(x, 1, a)) + ax[0, 1].semilogx(x, ColeCole.correlation(x, 1, a)) + ax[1, 0].loglog(x, ColeCole.specdens(x, 1, a)) + g = ax[1, 1].loglog(x, ColeCole.susceptibility(x, 1, a).imag) + ax[1, 1].loglog(x, ColeCole.susceptibility(x, 1, a).real, '--', color=g[0].get_color()) + + fig.tight_layout() + + plt.show() diff --git a/nmreval/distributions/coledavidson.py b/nmreval/distributions/coledavidson.py new file mode 100644 index 0000000..8d2fab6 --- /dev/null +++ b/nmreval/distributions/coledavidson.py @@ -0,0 +1,179 @@ +import numbers + +import numpy as np +from scipy.special import psi, gammaincc + +from .base import Distribution +from ..utils.constants import Eu + + +class ColeDavidson(Distribution): + """ + Functions based on Cole-Davidson distribution + """ + name = 'Cole-Davidson' + parameter = [r'\gamma'] + bounds = [(0, 1)] + + @staticmethod + def susceptibility(omega, tau, gamma): + """ + Susceptibility + + .. math:: + \chi(\omega, \\tau, \\gamma) = \\frac{1}{(1-i\omega\\tau_0)^\\gamma} + + Args: + omega: + tau: + gamma: + """ + return (1/(1+1j*omega*tau)**gamma).conjugate() + + @staticmethod + def specdens(omega, tau,gamma): + """ + Spectral density + + .. math:: + J(\omega, \\tau, \\gamma) = \\frac{\sin[\\gamma\\arctan(\\omega\\tau)]}{\omega[1+(\omega\\tau)^2]^{\\gamma/2}} + + Args: + omega: + tau: + gamma: + """ + gam = gamma + _w = np.atleast_1d(omega) + _t = np.atleast_1d(tau) + omtau = _w[:, None] * _t[None, :] + + ret_val = np.sin(gam*np.arctan2(omtau, 1)) / (1 + omtau**2)**(gam/2.) / _w[:, None] + ret_val[_w == 0, :] = gam*_t + + return np.squeeze(ret_val) + + @staticmethod + def mean(tau, gamma): + """ + Mean tau + + .. math:: + \\langle \\tau \\rangle = \\gamma \\tau + + Args: + tau: + gamma: + + """ + + return tau*gamma + + @staticmethod + def logmean(tau, gamma): + """ + Mean logarithm of tau + + .. math:: + \\langle \ln \\tau \\rangle = \ln\\tau + \psi(\gamma) + \mathrm{Eu} + + with the Euler's constant :math:`\mathrm{Eu} \\approx 0.57721567\ldots` and the digamma function + + .. math:: + \psi(x) = \\frac{d}{dx} \ln(\Gamma(x)) + + Args: + tau: + gamma: + + References: + R. Zorn: Logartihmic moments of relaxation time distribution. J. Chem. Phys. (2002). http://dx.doi.org/10.1063/1.1446035 + + """ + return np.log(tau) + psi(gamma) + Eu + + @staticmethod + def max(tau, gamma): + """ + Calculate :math:`\\tau_\\text{peak}`, i.e. the inverse of the maximum frequency of the imaginary part of the susceptibility + + .. math:: + \\tau_\\text{peak} = \\frac{\\tau}{\\tan[\\pi/(2\gamma+2)]} + + Args: + tau: + gamma: + + References: + R. Dı́az-Calleja: Comment on the Maximum in the Loss Permittivity for the Havriliak-Negami Equation. + Macromolecules (2000). https://doi.org/10.1021/ma991082i + + """ + + return tau/np.tan(np.pi/(2*gamma+2)) + + @staticmethod + def distribution(tau, tau0, gamma): + """ + Distribution of correlation times + + .. math:: + G(\ln\\tau) = + \\begin{cases} + \\frac{\sin(\pi\gamma)}{\pi} \\Big(\\frac{\\tau}{\\tau_0 - \\tau}\\Big)^\gamma & \\tau < \\tau_0 \\\\ + 0 & \\text{else} + \end{cases} + + Args: + tau: + tau0: + gamma: + """ + + if isinstance(tau, numbers.Number): + return np.sin(np.pi*gamma) / np.pi * (1 / (tau0/tau - 1))**gamma if tau < tau0 else 0 + + ret_val = np.zeros_like(tau) + ret_val[tau < tau0] = np.sin(np.pi*gamma) / np.pi * (1 / (tau0/tau[tau < tau0] - 1))**gamma + + return ret_val + + @staticmethod + def correlation(t, tau0, gamma): + r""" + Correlation function + + .. math:: + C(t, \tau_0, \gamma) = \frac{\Gamma(\gamma, t/\tau_0)}{\Gamma(\gamma)} + + with incomplete Gamma function + + .. math:: + \Gamma(\gamma, t/\tau_0) = \frac{1}{\Gamma(\gamma)}\int_{t/\tau_0}^\infty x^{\gamma-1}\text{e}^{-x}\,\mathrm{d}x + + Args: + t: + tau0: + gamma: + + References: + R. Hilfer: H-function representations for stretched exponential relaxation and non-Debye susceptibilities in glassy systems. Phys. Rev. E (2002) https://doi.org/10.1103/PhysRevE.65.061510 + + """ + return gammaincc(gamma, t / tau0) + + +if __name__ == '__main__': + import matplotlib.pyplot as plt + + x = np.logspace(-3, 3, num=61) + + fig, ax = plt.subplots(2, 2) + + for g in [0.4, 0.6, 0.8]: + ax[0, 0].loglog(x, ColeDavidson.distribution(x, 1, g)) + ax[0, 1].semilogx(x, ColeDavidson.correlation(x, 1, g)) + ax[1, 0].loglog(x, ColeDavidson.specdens(x, 1, g)) + gr = ax[1, 1].loglog(x, ColeDavidson.susceptibility(x, 1, g).imag) + ax[1, 1].loglog(x, ColeDavidson.susceptibility(x, 1, g).real, '--', color=gr[0].get_color()) + plt.show() diff --git a/nmreval/distributions/debye.py b/nmreval/distributions/debye.py new file mode 100644 index 0000000..dc76bd4 --- /dev/null +++ b/nmreval/distributions/debye.py @@ -0,0 +1,30 @@ +import numbers + +import numpy as np + +from .base import Distribution + + +class Debye(Distribution): + name = 'Debye' + + @staticmethod + def correlation(t, tau0, *args): + return np.exp(-t/tau0) + + @staticmethod + def susceptibility(omega, tau0, *args): + return 1/(1 + 1j*omega*tau0) + + @staticmethod + def specdens(omega, tau0, *args): + return tau0 / (1 + (omega*tau0)**2) + + @staticmethod + def distribution(taus, tau0, *args): + if isinstance(taus, numbers.Number): + return 1 if taus == tau0 else 0 + + ret_val = np.zeros_like(taus) + ret_val[np.argmin(abs(taus - tau0))] = 1 + return ret_val diff --git a/nmreval/distributions/energy.py b/nmreval/distributions/energy.py new file mode 100644 index 0000000..41e9d53 --- /dev/null +++ b/nmreval/distributions/energy.py @@ -0,0 +1,124 @@ +from itertools import product + +import numpy as np +from scipy.integrate import simps as simpson + +from .base import Distribution +from ..utils.constants import kB + + +class EnergyBarriers(Distribution): + name = 'Energy barriers' + parameter = [r'\tau_{0}', r'E_{m}', r'\Delta E'] + + @staticmethod + def distribution(tau, temperature, *args): + t0, em, sigma = args + m = np.exp(em / (kB * temperature)) * t0 + return temperature * np.exp(-0.5 * (np.log(tau/m)*kB*temperature/sigma)**2) / np.sqrt(2*np.pi)/sigma + + @staticmethod + def rate(t0, e_a, te): + return np.exp(-e_a / (kB * te)) / t0 + + @staticmethod + def energydistribution(e_a, mu, sigma): + return np.exp(-0.5 * ((mu-e_a) / sigma) ** 2) / (np.sqrt(2 * np.pi) * sigma) + + @staticmethod + def correlation(t, temperature, *args): + tau0, e_m, e_b = args + + def integrand(e_a, ti, t0, mu, sigma, te): + # correlation time would go to inf for higher energies, so we use rate + return np.exp(-ti*EnergyBarriers.rate(t0, e_a, te)) * EnergyBarriers.energydistribution(e_a, mu, sigma) + + t = np.atleast_1d(t) + temperature = np.atleast_1d(temperature) + + e_axis = np.linspace(max(0, e_m-50*e_b), e_m+50*e_b, num=5001) + + ret_val = np.array([simpson(integrand(e_axis, o, tau0, e_m, e_b, tt), e_axis) + for o in t for tt in temperature]) + + return ret_val + + @staticmethod + def susceptibility(omega, temperature, *args): + # in contrast to other spectral densities, it's omega and temperature + tau0, e_m, e_b = args + + def integrand_real(e_a, w, t0, mu, sigma, t): + r = EnergyBarriers.rate(t0, e_a, t) + return 1/(r**2 + w**2) * EnergyBarriers.energydistribution(e_a, mu, sigma) + + def integrand_imag(e_a, w, t0, mu, sigma, t): + r = EnergyBarriers.rate(t0, e_a, t) + return w*r/(r**2 + w**2) * EnergyBarriers.energydistribution(e_a, mu, sigma) + + omega = np.atleast_1d(omega) + temperature = np.atleast_1d(temperature) + + e_axis = np.linspace(max(0, e_m-50*e_b), e_m+50*e_b, num=5001) + ret_val = [] + for o, tt in product(omega, temperature): + ret_val.append(simpson(integrand_real(e_axis, o, tau0, e_m, e_b, tt), e_axis) - + 1j * simpson(integrand_imag(e_axis, o, tau0, e_m, e_b, tt), e_axis)) + + return np.array(ret_val) + + @staticmethod + def specdens(omega, temperature, *args): + # in contrast to other spectral densities, it's omega and temperature + tau0, e_m, e_b = args + + def integrand(e_a, w, t0, mu, sigma, t): + r = EnergyBarriers.rate(t0, e_a, t) + return r/(r**2 + w**2) * EnergyBarriers.energydistribution(e_a, mu, sigma) + + omega = np.atleast_1d(omega) + temperature = np.atleast_1d(temperature) + + e_axis = np.linspace(max(0, e_m-50*e_b), e_m+50*e_b, num=5001) + + ret_val = np.array([simpson(integrand(e_axis, o, tau0, e_m, e_b, tt), e_axis) + for o in omega for tt in temperature]) + + return ret_val + + @staticmethod + def mean(*args): + return args[1]*np.exp(args[2]/(kB*args[0])) + + @staticmethod + def logmean(*args): + return args[1] + args[2] / (kB * args[0]) + + @staticmethod + def max(*args): + return args[1] * np.exp(args[2] / (kB * args[0])) + + +if __name__ == '__main__': + import matplotlib.pyplot as plt + + x = np.logspace(-12, 12, num=601) + + fig, ax = plt.subplots(2, 2) + ax[0, 0].set_title('Distribution') + ax[0, 1].set_title('Correlation func.') + ax[1, 0].set_title('Spectral density') + ax[1, 1].set_title('Susceptibility') + + p = [1e-12, 0.3, 0.02] + + for a in [100, 150, 300]: + ax[0, 0].semilogx(x, EnergyBarriers.distribution(x, a, *p)) + ax[0, 1].semilogx(x, EnergyBarriers.correlation(x, a, *p)) + ax[1, 0].loglog(x, EnergyBarriers.specdens(x, a, *p)) + g = ax[1, 1].loglog(x, -EnergyBarriers.susceptibility(x, a, *p).imag) + ax[1, 1].loglog(x, EnergyBarriers.susceptibility(x, a, *p).real, '--', color=g[0].get_color()) + + fig.tight_layout() + + plt.show() diff --git a/nmreval/distributions/gengamma.py b/nmreval/distributions/gengamma.py new file mode 100644 index 0000000..3c96063 --- /dev/null +++ b/nmreval/distributions/gengamma.py @@ -0,0 +1,111 @@ +from typing import Union + +import numpy as np +from scipy.integrate import simps +from scipy.special import gammaln + +from .base import Distribution + + +class GGAlpha(Distribution): + name = r'General \Gamma (\alpha-process)' + parameter = [r'\alpha', r'\beta'] + + @staticmethod + def correlation(t, tau0, *args): + logtau0 = np.log(tau0) + logtau = np.linspace(logtau0-20, logtau0+20, num=4001) + taus = np.exp(logtau) + gtau = GGAlpha.distribution(taus, tau0, *args) + ret_val = np.array([simps(np.exp(-xvals/taus)*gtau, logtau) for xvals in t]) + return ret_val + + @staticmethod + def susceptibility(omega, tau0, *args): + logtau0 = np.log(tau0) + logtau = np.linspace(logtau0 - 20, logtau0 + 20, num=4001) + taus = np.exp(logtau) + gtau = GGAlpha.distribution(taus, tau0, *args) + ret_val = np.array([simps(1/(1+1j*xvals*taus) * gtau, logtau) for xvals in omega]) + return ret_val + + @staticmethod + def distribution(taus: Union[float, np.ndarray], tau: float, *args) -> Union[float, np.ndarray]: + alpha, beta = args + b_to_a = beta / alpha + norm = np.exp(gammaln(b_to_a) - b_to_a * np.log(b_to_a)) / alpha + t_to_t0 = taus / tau + ret_val = np.exp(-b_to_a * t_to_t0 ** alpha) * t_to_t0 ** beta + + return ret_val / norm + + +class GGAlphaEW(Distribution): + name = r'General \Gamma (\alpha-process + EW)' + parameter = [r'\alpha', r'\beta'] + + @staticmethod + def correlation(t, tau0, *args): + logtau0 = np.log(tau0) + logtau = np.linspace(logtau0-20, logtau0+20, num=4001) + taus = np.exp(logtau) + gtau = GGAlphaEW.distribution(taus, tau0, *args) + # wir integrieren ueber lntau, nicht tau + ret_val = np.array([simps(np.exp(-xvals/taus)*gtau, logtau) for xvals in t]) + return ret_val + + @staticmethod + def susceptibility(omega, tau0, *args): + logtau0 = np.log(tau0) + logtau = np.linspace(logtau0 - 20, logtau0 + 20, num=4001) + taus = np.exp(logtau) + gtau = GGAlphaEW.distribution(taus, tau0, *args) + ret_val = np.array([simps(1/(1+1j*xvals*taus) * gtau, logtau) for xvals in omega]) + return ret_val + + @staticmethod + def distribution(tau: Union[float, np.ndarray], tau0: float, *args) -> Union[float, np.ndarray]: + alpha, beta, sigma, gamma = args + if gamma == beta: + return GGAlpha.distribution(tau, tau0, alpha, beta) + b_to_a = beta / alpha + g_to_a = gamma / alpha + t_to_t0 = tau / tau0 + norm = (np.exp(gammaln(b_to_a)) + sigma**(gamma-beta) * + np.exp(gammaln(g_to_a) + (b_to_a-g_to_a)*np.log(b_to_a))) / np.exp(b_to_a*np.log(b_to_a)) / alpha + + ret_val = np.exp(-b_to_a * t_to_t0**alpha) * t_to_t0**beta * (1 + (t_to_t0*sigma)**(gamma-beta)) + + return ret_val / norm + + +class GGBeta(Distribution): + name = r'General \Gamma (\beta-process)' + parameter = [r'\alpha', r'\beta'] + + @staticmethod + def correlation(t, tau0, *args): + logtau0 = np.log(tau0) + logtau = np.linspace(logtau0-20, logtau0+20, num=4001) + taus = np.exp(logtau) + gtau = GGBeta.distribution(taus, tau0, *args) + # wir integrieren ueber lntau, nicht tau + ret_val = np.array([simps(np.exp(-xvals/taus)*gtau, logtau) for xvals in t]) + return ret_val + + @staticmethod + def susceptibility(omega, tau0, *args): + logtau0 = np.log(tau0) + logtau = np.linspace(logtau0 - 20, logtau0 + 20, num=4001) + taus = np.exp(logtau) + gtau = GGBeta.distribution(taus, tau0, *args) + ret_val = np.array([simps(1/(1+1j*xvals*taus) * gtau, logtau) for xvals in omega]) + return ret_val + + @staticmethod + def distribution(tau: Union[float, np.ndarray], tau0: float, *args) -> Union[float, np.ndarray]: + a, b = args + norm = a * (1+b) * np.sin(np.pi*b/(1+b)) * b**(b/(1+b)) / np.pi + ret_val = b * (tau/tau0)**a + (tau/tau0)**(-a*b) + + return norm / ret_val diff --git a/nmreval/distributions/havriliaknegami.py b/nmreval/distributions/havriliaknegami.py new file mode 100644 index 0000000..5e771a3 --- /dev/null +++ b/nmreval/distributions/havriliaknegami.py @@ -0,0 +1,106 @@ +import numpy as np +from scipy.special import psi + +from .base import Distribution +from ..math.mittagleffler import mlf +from ..utils import Eu + + +class HavriliakNegami(Distribution): + """ + Functions based on Cole-Davidson distribution + """ + + name = 'Havriliak-Negami' + parameter = [r'\alpha', r'\gamma'] + bounds = [(0, 1), (0, 1)] + + @staticmethod + def correlation(t, tau0, alpha, gamma): + r""" + Correlation function + + .. math:: + C(t, \tau_0, \alpha, \gamma) = 1 - \left(\frac{t}{\tau_0}\right)^{\alpha\gamma} \text{E}_{\alpha,\alpha\gamma+1}^\gamma\left[-\left(\frac{t}{\tau_0}\right)^\alpha\right] + + with incomplete Gamma function + + .. math:: + \Gamma(\gamma, t/\tau_0) = \frac{1}{\Gamma(\gamma)}\int_{t/\tau_0}^\infty x^{\gamma-1}\text{e}^{-x}\,\mathrm{d}x + + Args: + t: + tau0: + alpha: + gamma: + + References: + R. Hilfer: H-function representations for stretched exponential relaxation and non-Debye susceptibilities in glassy systems. Phys. Rev. E (2002) https://doi.org/10.1103/PhysRevE.65.061510 + + """ + return 1 - (t/tau0)**(alpha*gamma) * mlf(-(t/tau0)**alpha, alpha, alpha*gamma+1, gamma) + + @staticmethod + def susceptibility(omega, tau, alpha, gamma): + return np.conjugate(1/(1 + (1j*omega[:, None]*tau[None, :])**alpha)**gamma).squeeze() + + @staticmethod + def specdens(omega, tau, alpha, gamma): + omtau = (omega[:, None]*tau[None, :])**alpha + + zaehler = np.sin(gamma * np.arctan2(omtau*np.sin(0.5*alpha*np.pi), 1 + omtau*np.cos(0.5*alpha*np.pi))) + nenner = (1 + 2*omtau * np.cos(0.5*alpha*np.pi) + omtau**2)**(0.5*gamma) + + return ((1 / omega) * (zaehler/nenner)).squeeze() + + @staticmethod + def distribution(tau, tau0, alpha, gamma): + if alpha == 1: + from .coledavidson import ColeDavidson + return ColeDavidson.distribution(tau, tau0, gamma) + elif gamma == 1: + from .colecole import ColeCole + return ColeCole.distribution(tau, tau0, alpha) + else: + _y = tau/tau0 + om_y = (1 + 2*np.cos(np.pi*alpha)*(_y**alpha) + _y**(2*alpha))**(-gamma/2) + theta_y = np.arctan2(np.sin(np.pi * alpha), _y**alpha + np.cos(np.pi*alpha)) + + return np.sin(gamma*theta_y) * om_y * (_y**(alpha*gamma)) / np.pi + + @staticmethod + def max(tau, alpha, gamma): + return tau*(np.sin(0.5*np.pi*alpha*gamma/(gamma+1)) / np.sin(0.5*np.pi*alpha/(gamma+1)))**(1/alpha) + + @staticmethod + def logmean(tau, alpha, gamma): + r""" + Calculate mean logarithm of tau + + .. math:: + \langle \ln \tau \rangle = \ln \tau + \frac{\Psi(\gamma) + \text{Eu}}{\alpha} + + Args: + tau: + alpha: + gamma: + + Returns: + + """ + return np.log(tau) + (psi(gamma)+Eu)/alpha + + @staticmethod + def mean(tau, alpha, gamma): + # approximation according to Th. Bauer et al., J. Chem. Phys. 133, 144509 (2010). + return tau * alpha*gamma + + +if __name__ == '__main__': + import matplotlib.pyplot as plt + + x = np.logspace(-7, 3) + y = HavriliakNegami.correlation(x, 1, 0.8, 0.26) + + plt.semilogx(x, y) + plt.show() diff --git a/nmreval/distributions/intermolecular.py b/nmreval/distributions/intermolecular.py new file mode 100644 index 0000000..8a20ce4 --- /dev/null +++ b/nmreval/distributions/intermolecular.py @@ -0,0 +1,99 @@ +import numpy as np +from scipy.integrate import quad + +from .base import Distribution + + +class FFHS(Distribution): + name = 'Intermolecular (FFHS)' + parameter = None + + @staticmethod + def distribution(taus, tau0, *args): + # Distribution over tau, not log(tau), like in other cases + z = taus / tau0 + return 54 * np.sqrt(z) / (162*z**3 + 18*z**2 - 4*z + 2) / np.pi / tau0 + + @staticmethod + def correlation(t, tau0, *args): + def integrand(u, tt, tau0): + return FFHS.distribution(u, tau0) * np.exp(-tt/u) / u + + ret_val = np.array([quad(integrand, 0, np.infty, args=(tt, tau0), epsabs=1e-12, epsrel=1e-12)[0] for tt in t]) + + return ret_val + + @staticmethod + def specdens(omega, tau0, *args): + def integrand(u, o, tau0): + return FFHS.distribution(u, tau0) * u / (1+o**2 * u**2) + + ret_val = np.array([quad(integrand, 0, np.infty, args=(o, tau0), epsabs=1e-12, epsrel=1e-12)[0] for o in omega]) + + return ret_val + + @staticmethod + def susceptibility(omega, tau0, *args): + def integrand_real(u, o, tau0): + return FFHS.distribution(u, tau0) / (1+o**2 * u**2) + + def integrand_imag(u, o, tau0): + return FFHS.distribution(u, tau0) * o*u / (1+o**2 * u**2) + + ret_val = np.array([quad(integrand_real, 0, np.infty, args=(o, tau0), + epsabs=1e-12, epsrel=1e-12)[0] for o in omega], dtype=complex) + + ret_val.imag += np.array([quad(integrand_imag, 0, np.infty, args=(o, tau0), + epsabs=1e-12, epsrel=1e-12)[0] for o in omega]) + + return ret_val + + +# class Bessel(Distribution): +# name = 'Intermolecular (Bessel)' +# parameter = None +# +# @staticmethod +# def distribution(taus, tau0, *args): +# x = np.sqrt(tau0 / taus) +# return special.jv(1.5, x)**2 / tau0 / 2 +# +# @staticmethod +# def correlation(t, tau0, *args): +# def integrand(lx, tt): +# x = np.exp(lx) +# return Bessel.distribution(x, tau0)*np.exp(-tt/lx) +# +# logaxis = np.linspace(-20+np.log(tau0), 20+np.log(tau0), num=5001) +# +# ret_val = np.array([simps(integrand(logaxis, tt), logaxis) for tt in t]) +# +# return ret_val +# +# @staticmethod +# def susceptibility(omega, tau0, *args): +# def integrand(lx, o): +# x = np.exp(lx) +# return Bessel.distribution(x, tau0) * 1/(1+1j*omega*x) +# +# logaxis = np.linspace(-20 + np.log(tau0), 20 + np.log(tau0), num=5001) +# +# ret_val = np.array([simps(integrand(logaxis, o), logaxis) for o in omega]) +# +# return ret_val + + +if __name__ == '__main__': + import matplotlib.pyplot as plt + + x = np.logspace(-3, 3, num=61) + + fig, ax = plt.subplots(2, 2) + + ax[0, 0].loglog(x, FFHS.distribution(x, 1)) + ax[0, 1].semilogx(x, FFHS.correlation(x, 1)) + ax[1, 0].loglog(x, FFHS.specdens(x, 1)) + ax[1, 1].loglog(x, FFHS.susceptibility(x, 1).real, + x, -FFHS.susceptibility(x, 1).imag) + fig.tight_layout() + plt.show() diff --git a/nmreval/distributions/kww.py b/nmreval/distributions/kww.py new file mode 100644 index 0000000..87ee238 --- /dev/null +++ b/nmreval/distributions/kww.py @@ -0,0 +1,84 @@ +import numpy as np +from scipy.interpolate import interp1d +from scipy.special import gamma + +from .base import Distribution +from ..math.kww import kww_cos, kww_sin +from ..utils.constants import Eu + + +class KWW(Distribution): + name = 'KWW' + parameter = [r'\beta'] + boounds = [(0, 1)] + + @staticmethod + def distribution(taus, tau, *args): + b = args[0] + assert 0.1 <= b <= 0.9 + b_supp = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9] + B_supp = [0.145, 0.197, 0.243, 0.285, 0.382, 0.306, 0.360, 0.435, 0.700] + C_supp = [0.89, 0.50, 0.35, 0.25, 0, 0.13, 0.22, 0.4015, 0.32] + + B = interp1d(b_supp, B_supp)(b) + C = interp1d(b_supp, C_supp)(b) + + tt = tau/taus + + delta = b * abs(b-0.5) / (1-b) + if b > 0.5: + f = 1 + C * tt**delta + else: + f = 1 / (1 + C * tt**delta) + ret_val = tau * B * np.exp(-(1-b) * b**(b/(1-b)) / tt**(b/(1-b))) / tt**((1-0.5*b)/(1-b)) + + return ret_val * f / taus + + @staticmethod + def correlation(t, tau, *args): + return np.exp(-(t/tau)**args[0]) + + @staticmethod + def susceptibility(omega, tau, *args): + return 1-omega*kww_sin(omega, tau, args[0]) + 1j*omega*kww_cos(omega, tau, args[0]) + + @staticmethod + def specdens(omega, tau, *args): + return kww_cos(omega, tau, args[0]) + + @staticmethod + def mean(*args): + tau, beta = args + return tau/beta * gamma(1 / beta) + + @staticmethod + def logmean(*args): + tau, beta = args + return (1-1/beta) * Eu + np.log(tau) + + @staticmethod + def max(*args): + tau, beta = args + return (1.7851 - 0.87052*beta - 0.028836*beta**2 + 0.11391*beta**3) * tau + + +if __name__ == '__main__': + import matplotlib.pyplot as plt + + x = np.logspace(-3, 3, num=61) + + fig, ax = plt.subplots(2, 2) + ax[0, 0].set_title('Distribution') + ax[0, 1].set_title('Correlation func.') + ax[1, 0].set_title('Spectral density') + ax[1, 1].set_title('Susceptibility') + + for g in [0.3, 0.5, 0.7, 0.9]: + ax[0, 0].semilogx(x, KWW.distribution(x, 1, g)) + ax[0, 1].semilogx(x, KWW.correlation(x, 1, g)) + ax[1, 0].loglog(x, KWW.specdens(x, 1, g)) + a = ax[1, 1].loglog(x, KWW.susceptibility(x, 1, g).imag) + ax[1, 1].loglog(x, KWW.susceptibility(x, 1, g).real, '--', color=a[0].get_color()) + + fig.tight_layout() + plt.show() diff --git a/nmreval/distributions/loggaussian.py b/nmreval/distributions/loggaussian.py new file mode 100644 index 0000000..065eacc --- /dev/null +++ b/nmreval/distributions/loggaussian.py @@ -0,0 +1,138 @@ +from multiprocessing import Pool, cpu_count +from itertools import product + +import numpy as np +try: + from scipy.integrate import simpson +except ImportError: + from scipy.integrate import simps as simpson +from scipy.integrate import quad + +from .base import Distribution + + +__all__ = ['LogGaussian'] + + +class LogGaussian(Distribution): + name = 'Log-Gaussian' + parameter = [r'\sigma'] + bounds = [(0, 10)] + + @staticmethod + def distribution(tau, tau0, *args): + sigma = args[0] + return np.exp(-0.5*(np.log(tau/tau0)/sigma)**2)/np.sqrt(2*np.pi)/sigma + + @staticmethod + def correlation(t, tau0, *args): + sigma = args[0] + _t = np.atleast_1d(t) + _tau = np.atleast_1d(tau0) + + pool = Pool(processes=min(cpu_count(), 4)) + integration_ranges = [(omega_i, tau_j, sigma) for (omega_i, tau_j) in product(_t, _tau)] + + with np.errstate(divide='ignore'): + res = np.array(pool.map(_integrate_process_3, integration_ranges)) + ret_val = res.reshape((_t.shape[0], _tau.shape[0])) + + return ret_val.squeeze() + + @staticmethod + def susceptibility(omega, tau0, *args): + sigma = args[0] + _omega = np.atleast_1d(omega) + _tau = np.atleast_1d(tau0) + + pool = Pool(processes=min(cpu_count(), 4)) + integration_ranges = [(omega_i, tau_j, sigma) for (omega_i, tau_j) in product(_omega, _tau)] + + with np.errstate(divide='ignore'): + res_real = np.array(pool.map(_integrate_process_1, integration_ranges)) + res_imag = np.array(pool.map(_integrate_process_2, integration_ranges)) + ret_val = (res_real+1j*res_imag).reshape((_omega.shape[0], _tau.shape[0])) + + return ret_val.squeeze() + + @staticmethod + def specdens(omega, tau0, *args): + sigma = args[0] + _omega = np.atleast_1d(omega) + _tau = np.atleast_1d(tau0) + + pool = Pool(processes=min(cpu_count(), 4)) + integration_ranges = [(omega_i, tau_j, sigma) for (omega_i, tau_j) in product(_omega, _tau)] + + with np.errstate(divide='ignore'): + res = np.array(pool.map(_integrate_process_1, integration_ranges)) + ret_val = res.reshape((_omega.shape[0], _tau.shape[0])) + + ret_val /= _omega[:, None] + + return ret_val.squeeze() + + def mean(*args): + return args[0]*np.exp(args[1]**2 / 2) + + +def _integrate_process_1(args): + omega_i, tau_j, sigma = args + area = quad(_integrand_freq_imag_high, 0, 50, args=(omega_i, tau_j, sigma))[0] + area += quad(_integrand_freq_imag_low, -50, 0, args=(omega_i, tau_j, sigma))[0] + + return area + + +def _integrate_process_2(args): + omega_i, tau_j, sigma = args + area = quad(_integrand_freq_real_high, 0, 50, args=(omega_i, tau_j, sigma))[0] + area += quad(_integrand_freq_real_low, -50, 0, args=(omega_i, tau_j, sigma))[0] + + return area + + +def _integrate_process_3(args): + omega_i, tau_j, sigma = args + return quad(_integrand_time, -50, 50, args=(omega_i, tau_j, sigma))[0] + + +def _integrand_time(u, t, tau, sigma): + uu = np.exp(u) + return LogGaussian.distribution(uu, tau, sigma) * np.exp(-t/uu) + + +def _integrand_freq_imag_low(u, omega, tau, sigma): + uu = np.exp(u) + return LogGaussian.distribution(uu, tau, sigma) * omega * uu / (1 + (omega*uu)**2) + + +def _integrand_freq_imag_high(u, omega, tau, sigma): + uu = np.exp(-u) + return LogGaussian.distribution(1/uu, tau, sigma) * omega * uu / (uu**2 + omega**2) + + +def _integrand_freq_real_low(u, omega, tau, sigma): + uu = np.exp(u) + return LogGaussian.distribution(uu, tau, sigma) / (1 + (omega*uu)**2) + + +def _integrand_freq_real_high(u, omega, tau, sigma): + uu = np.exp(-2*u) + return LogGaussian.distribution(np.exp(u), tau, sigma) * uu / (uu + omega**2) + + +if __name__ == '__main__': + import matplotlib.pyplot as plt + + x = np.logspace(-3, 3, num=61) + + fig, ax = plt.subplots(2, 2) + + for g in [1, 2, 5]: + ax[0, 0].loglog(x, LogGaussian.distribution(x, 1, g)) + ax[0, 1].semilogx(x, LogGaussian.correlation(x, 1, g)) + ax[1, 0].loglog(x, LogGaussian.specdens(1, x, g)) + gr = ax[1, 1].loglog(x, -LogGaussian.susceptibility(x, 1, g).imag) + ax[1, 1].loglog(x, LogGaussian.susceptibility(x, 1, g).real, '--', color=gr[0].get_color()) + plt.show() diff --git a/nmreval/dsc/calibration.py b/nmreval/dsc/calibration.py new file mode 100644 index 0000000..965605f --- /dev/null +++ b/nmreval/dsc/calibration.py @@ -0,0 +1,290 @@ +__version__ = '0.1.3' + +import os +import argparse +import sys + +import numpy as np +import matplotlib.pyplot as plt +import scipy.interpolate +from scipy.integrate import simps + +from nmreval.io.dsc import DSCSample, Cyclohexane + +parser = argparse.ArgumentParser(description='Calibrate DSC data') +parser.add_argument('sample', type=str, help='filename of DSC sample') +parser.add_argument('empty', type=str, help='filename of empty pan') +parser.add_argument('reference', help='filename of reference', type=str) +parser.add_argument('--cooling', help='Show figure of found cooling rates', action='store_true') + + +def evaluate(sample, empty, reference, ref_points=Cyclohexane, show_cooling=False): + sample = DSCSample(sample) + empty = DSCSample(empty) + reference = DSCSample(reference) + + if show_cooling: + fig, ax = plt.subplots() + print('\n') + for k, v in sample.heating.items(): + print('Plot run {} with cooling rate {} K/min'.format(k, v)) + c = sample.flow_data(v, mode='c') + ax.plot(c[0], c[1], label=str(v)+' K/min') + ax.set_xlabel('T / K') + plt.legend() + plt.show() + + return + + run_list = [] + if len(sample.heating) > 1: + run = None + print('\nMultiple heat rates found:') + for k, v in sample.heating.items(): + print(' run {}: {} K/min'.format(k, v)) + while run not in sample.heating: + # choose your own adventure!!! + value = input('\nPlease select a run (press Enter for all heat rates): ') + if value == '': + run_list = list(sample.heating.keys()) + break + else: + run = int(value) + run_list = [run] + else: + run_list = list(sample.heating.keys()) + + for run in run_list: + rate = sample.heating[run] + + print('\nProcessing heat rate {} K/min'.format(rate)) + + print('Load data of heating data') + len_sample = sample.length(run) + + # sanity checks + try: + reference_data = reference.flow_data(rate) + except IndexError: + print('ERROR: Reference measurement has no heat rate {} K/min'.format(rate)) + print('Stop evaluation') + sys.exit() + + try: + run_baseline = empty.get_run(rate) + except ValueError: + print('ERROR: Empty measurement has no heat rate {} K/min'.format(rate)) + print('Stop evaluation') + sys.exit() + + len_baseline = empty.length(run_baseline) + if len_baseline != len_sample: + print('WARNING: measurements differ by {} points'.format(abs(len_baseline - len_sample))) + # max_length = min(len_baseline, len_sample) + + sample_data = sample.flow_data(rate, length=None) + empty_data = empty.flow_data(rate, length=None) + + # plot input data + fig1, ax1 = plt.subplots(2, 3, **{'figsize': (10, 6)}) + ax1[0, 0].set_title('raw data') + ax1[0, 0].set_xlabel('T / K') + + ax1[0, 0].plot(sample_data[0], sample_data[1], 'k-', label='Sample') + ax1[0, 0].plot(empty_data[0], empty_data[1], 'b-', label='Empty') + ax1[0, 0].plot(reference_data[0], reference_data[1], 'r-', label='Reference') + ax1[0, 0].legend() + + print('Substract empty data\n') + sample_baseline = sample_data.copy() + empty_y = empty_data[1] + if len_sample != len_baseline: + with np.errstate(all='ignore'): + empty_y = scipy.interpolate.interp1d(empty_data[0], empty_data[1], + fill_value='extrapolate')(sample_data[0]) + sample_baseline[1] = sample_data[1] - empty_y + + # plot baseline correction + ax1[0, 1].set_title('baseline correction') + ax1[0, 1].set_xlabel('T / K') + + ax1[0, 1].plot(sample_data[0], sample_data[1], 'k--', label='Raw') + ax1[0, 1].plot(sample_baseline[0], sample_baseline[1], 'k-', label='Baseline corrected') + ax1[0, 1].plot(empty_data[0], empty_data[1], 'b-', label='Empty') + ax1[0, 1].legend() + + print('Load isothermal data around heat rate') + mean_isotherms = [] + for offset, where, ls in [(-1, 'low', '-'), (1, 'high', '--')]: + # read isotherms and baseline correct + len_baseline = empty.length(run_baseline+offset) + len_sample = sample.length(run+offset) + if len_baseline != len_sample: + print('WARNING: {} T isotherms differ by {} points'.format(where, abs(len_baseline-len_sample))) + + max_length = min(len_baseline, len_sample) + isotherm_sample = sample.isotherm_data(run_baseline+offset, length=max_length) + isotherm_empty = empty.isotherm_data(run+offset, length=max_length) + + isotherm_sample[1] -= isotherm_empty[1] + + # get mean isotherm value + m = np.polyfit(isotherm_sample[0, 200:-200], isotherm_sample[1, 200:-200], 0)[0] + mean_isotherms.append(m) + print('Calculated {} heat flow: {:.4} mW'.format(where, m)) + + ax1[0, 2].plot(isotherm_sample[0], isotherm_sample[1], 'k--') + + # calculate slope from difference between isotherms + slope = (mean_isotherms[1]-mean_isotherms[0]) / (sample_data[2, -1] - empty_data[2, 0]) + print('Heat flow slope from isotherms: {:.4} per minute'.format(slope*60)) + + # calculate mean slope of heat flow at points in the beginning + slope_baseline = np.gradient(sample_baseline[1, int(4000/rate):int(9000/rate)], + sample_baseline[2, 300]-sample_baseline[2, 299]).mean() + print('Heat flow slope from initial heating: {:.4f} per minute\n'.format(slope_baseline*60)) + + drift_corrected = sample_baseline[1] - mean_isotherms[0] - (sample_baseline[2]-empty_data[2, 0])*slope + drift_from_slope = sample_baseline[1] - mean_isotherms[0] - (sample_baseline[2]-empty_data[2, 0])*slope_baseline + + # plot + ax1[0, 2].axhline(mean_isotherms[0], linestyle=':') + ax1[0, 2].axhline(mean_isotherms[1], linestyle=':') + + ax1[0, 2].plot(sample_baseline[2], sample_baseline[1], 'k-', label='Baseline corrected') + ax1[0, 2].plot(sample_baseline[2], drift_corrected, 'g-', label='Corrected (isotherm)') + ax1[0, 2].plot(sample_baseline[2], drift_from_slope, 'b-', label='Corrected (heating)') + + ax1[0, 2].plot(sample_baseline[2], mean_isotherms[0] + (sample_baseline[2]-empty_data[2, 0])*slope, 'g--') + ax1[0, 2].plot(sample_baseline[2], mean_isotherms[0] + slope_baseline*(sample_baseline[2]-empty_data[2, 0]), + 'b--') + + ax1[0, 2].plot(sample_baseline[2, int(4000/rate):int(9000/rate)], + sample_baseline[1, int(4000/rate):int(9000/rate)], 'r--') + + ax1[0, 2].set_title('time dependence') + ax1[0, 2].set_xlabel('t / s') + ax1[0, 2].legend() + + melts = [] + for i, (ref_temp, enthalpy) in enumerate(ref_points.transitions): + # region around reference peaks + t_low_lim = ref_temp - 15 + t_high_lim = ref_temp + 15 + low_border = np.argmin(np.abs(reference_data[0]-t_low_lim)) + high_border = np.argmin(np.abs(reference_data[0]-t_high_lim)) + ref_zoom = reference_data[:, low_border:high_border] + x_val = np.array([[ref_zoom[0, 0], 1], + [ref_zoom[0, -1], 1]]) + y_val = np.array([ref_zoom[1, 0], + ref_zoom[1, -1]]) + print('Baseline correct reference of %.2f transition' % ref_temp) + sol = np.linalg.solve(x_val, y_val) + ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1]) + peak_max = ref_zoom[:, np.argmax(ref_zoom[1])] + integration_limit = np.argmin(abs(ref_zoom[0]-peak_max[0]+3)), np.argmin(abs(ref_zoom[0]-peak_max[0]-3)) + + # substract baseline around reference peaks + x_val = np.array([[ref_zoom[0, integration_limit[0]], 1], + [ref_zoom[0, integration_limit[1]], 1]]) + y_val = np.array([ref_zoom[1, integration_limit[0]], + ref_zoom[1, integration_limit[1]]]) + + print('Baseline correct reference of %.2f transition' % ref_temp) + sol = np.linalg.solve(x_val, y_val) + ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1]) + + # calculate onset slope (use points at position of maximum gradient +/- 100/rate) + ref_grad = np.gradient(ref_zoom[1]) + max_grad = np.argmax(ref_grad) + + x_val = np.array([[ref_zoom[0, max_grad-int(100/rate)], 1], + [ref_zoom[0, max_grad+int(100/rate)+1], 1]]) + y_val = np.array([ref_zoom[1, max_grad-int(100/rate)], + ref_zoom[1, max_grad+int(100/rate)+1]]) + sol = np.linalg.solve(x_val, y_val) + onset = sol[0]*ref_zoom[0] + sol[1] + + melts.append(-sol[1]/sol[0]) + + # plot + ax1[1, i].set_title(f'reference: {ref_temp:.2f}') + ax1[1, i].set_xlabel('T / K') + + ax1[1, i].plot(reference_data[0], reference_data[1], 'r-') + ax1[1, i].plot(ref_zoom[0, max_grad], ref_zoom[0, max_grad], 'kx') + ax1[1, i].plot(ref_zoom[0], onset, 'k--') + ax1[1, i].axhline(0, color='k', linestyle='--') + + ax1[1, i].set_xlim(ref_zoom[0, integration_limit[0]], ref_zoom[0, integration_limit[1]]) + ax1[1, i].set_ylim(-max(ref_zoom[1])/10, max(ref_zoom[1])*1.1) + + print('Onset of transition: %.2f K found at %.2f' % (ref_temp, melts[-1])) + if enthalpy is not None: + # integrate over low temperature peak to calibrate y axis + # delta H in J/g: Integrate Peak over time and divide by weight + area = 1e-3 * simps(ref_zoom[1, integration_limit[0]:integration_limit[1]], + ref_zoom[2, integration_limit[0]:integration_limit[1]], + even='avg') + calib_y_axis = enthalpy / (area / reference.weight) + print("Calibration factor of peak: %f\n" % calib_y_axis) + + sample_baseline[1] *= calib_y_axis + + fig1.delaxes(ax1[1, 2]) + fig1.tight_layout() + + plt.show() + + # give a choice how to compensate for long-time drift + mode = None + while mode not in ['i', 'h']: + mode = input('\nUse [i]sotherms or initial [h]eating for long-time correction? (Default: i) ') + if mode == '': + mode = 'i' + + if mode == 'h': + print('\nCorrect slope from initial heating') + sample_baseline[1] = drift_from_slope + else: + print('\nCorrect slope from isotherm') + sample_baseline[1] = drift_corrected + + # calibrate T axis + print('\nCalibrate temperature') + real_trans = np.array([temp for (temp, _) in ref_points.transitions]) + t_vals = np.array([[melts[0], 1], + [melts[1], 1]]) + calibration_temp = np.linalg.solve(t_vals, real_trans) + print('T_real = {:.4f} * T_meas {:+.4f}'.format(*calibration_temp)) + + sample_baseline[0] = calibration_temp[0] * sample_baseline[0] + calibration_temp[1] + + print('Convert to capacity') + cp = sample_baseline[1] * 60. / rate / sample.weight / 1000. + if sample.weight is None: + raise ValueError('No sample weight given') + + # plot final results in separate figure + fig2, ax2 = plt.subplots() + ax2.set_title('{} K/min: Heat flow vs. heat capacity (close to cont.)'.format(rate)) + ax2.set_xlabel('Temperature / K') + + ax2.plot(sample_baseline[0], sample_baseline[1], label='heat flow') + ax2.plot(sample_baseline[0], cp, label='heat capacity') + + plt.legend() + plt.show() + + outname = os.path.splitext(sample.name)[0] + '_' + str(rate) + 'K-min.dat' + header = 'Made with version: {}\n'.format(__version__) + header += 'T/K\tCp/J/(gK)\theat flow/mW' + + print() + print('Save to', outname) + np.savetxt(outname, np.c_[sample_baseline[0], cp, sample_baseline[1]], header=header) + + +if __name__ == '__main__': + args = parser.parse_args() + evaluate(args.sample, args.empty, args.reference, show_cooling=args.cooling) diff --git a/nmreval/dsc/dsc_calibration_fast_neu.py b/nmreval/dsc/dsc_calibration_fast_neu.py new file mode 100644 index 0000000..0575213 --- /dev/null +++ b/nmreval/dsc/dsc_calibration_fast_neu.py @@ -0,0 +1,292 @@ +from __future__ import annotations + +__version__ = '0.1.2' + +import os +from argparse import ArgumentParser +from pathlib import Path +import sys +import numpy as np +import matplotlib.pyplot as plt +from scipy.integrate import simps + +from nmreval.io.dsc import DSCReader, Cyclohexane, ReferenceValue + +parser = ArgumentParser(description='Calibrate DSC data') +parser.add_argument('sample', type=str, help='filename of DSC sample') +parser.add_argument('empty', type=str, help='filename of empty pan') +parser.add_argument('reference', help='filename of reference', type=str) +parser.add_argument('--cooling', help='Plot found cooling rates', action='store_true') + + +def evaluate(sample: str|Path, empty: str|Path, reference: str|Path, + ref_points: ReferenceValue = Cyclohexane, show_cooling: bool = False): + + sample = DSCReader(sample) + empty = DSCReader(empty) + reference = DSCReader(reference) + print(sample) + + if show_cooling: + fig, ax = plt.subplots() + print('\n') + for k, v in sample.cooling.items(): + print('Plot run {} with cooling rate {} K/min'.format(k, v)) + c = sample.flow_data(v, mode='c') + ax.plot(c[0], c[1], label=str(v)+' K/min') + ax.set_xlabel('T / K') + plt.legend() + plt.show() + + return + + run_list = [] + if len(sample.heating) > 1: + run = None + print('\nMultiple heat rates found:') + for k, v in sample.heating.items(): + print(' run {}: {} K/min'.format(k, v)) + while run not in sample.heating: + # choose your own adventure!!! + value = input('\nPlease select a run (press Enter for all heat rates): ') + if value == '': + run_list = list(sample.heating.keys()) + break + else: + run = int(value) + run_list = [run] + else: + run_list = list(sample.heating.keys()) + + for run in run_list: + rate = sample.heating[run] + + print('\nProcessing heat rate {} K/min'.format(rate)) + + print('Load data of heating data') + len_sample = sample.length(run) + + # sanity checks + try: + reference_data = reference.flow_data(rate) + except IndexError: + print('ERROR: Reference measurement has no heat rate {} K/min'.format(rate)) + print('Stop evaluation') + sys.exit() + + try: + run_baseline = empty.get_run(rate) + except ValueError: + print('ERROR: Empty measurement has no heat rate {} K/min'.format(rate)) + print('Stop evaluation') + sys.exit() + + len_baseline = empty.length(run_baseline) + max_length = None + if len_baseline != len_sample: + print('WARNING: measurements differ by {} points'.format(abs(len_baseline - len_sample))) + max_length = min(len_baseline, len_sample) + + sample_data = sample.flow_data(rate, length=max_length) + empty_data = empty.flow_data(rate, length=max_length) + + # plot input data + fig1, ax1 = plt.subplots(2, 3, **{'figsize': (10, 6)}) + ax1[0, 0].set_title('raw data') + ax1[0, 0].set_xlabel('T / K') + + ax1[0, 0].plot(sample_data[0], sample_data[1], 'k-', label='Sample') + ax1[0, 0].plot(empty_data[0], empty_data[1], 'b-', label='Empty') + ax1[0, 0].plot(reference_data[0], reference_data[1], 'r-', label='Reference') + ax1[0, 0].legend() + + print('Substract empty data') + sample_baseline = sample_data.copy() + sample_baseline[1] = sample_data[1] - empty_data[1] + + # plot baseline correction + ax1[0, 1].set_title('baseline correction') + ax1[0, 1].set_xlabel('T / K') + + ax1[0, 1].plot(sample_data[0], sample_data[1], 'k--', label='Raw') + ax1[0, 1].plot(sample_baseline[0], sample_baseline[1], 'k-', label='Baseline corrected') + ax1[0, 1].plot(empty_data[0], empty_data[1], 'b-', label='Empty') + ax1[0, 1].legend() + + print('Load isothermal data around heat rate') + mean_isotherms = [] + for offset, where, ls in [(-1, 'low', '-'), (1, 'high', '--')]: + # read isotherms and baseline correct + len_baseline = empty.length(run_baseline+offset) + len_sample = sample.length(run+offset) + if len_baseline != len_sample: + print('WARNING: {} T isotherms differ by {} points'.format(where, abs(len_baseline-len_sample))) + + max_length = min(len_baseline, len_sample) + isotherm_sample = sample.isotherm_data(run_baseline+offset, length=max_length) + isotherm_empty = empty.isotherm_data(run+offset, length=max_length) + + isotherm_sample[1] -= isotherm_empty[1] + + # get mean isotherm value + m = np.polyfit(isotherm_sample[0, 200:-200], isotherm_sample[1, 200:-200], 0)[0] + mean_isotherms.append(m) + print('Calculated {} heat flow: {} mW'.format(where, m)) + + ax1[0, 2].plot(isotherm_sample[0], isotherm_sample[1], 'k--') + + # calculate slope from difference between isotherms + slope = (mean_isotherms[1]-mean_isotherms[0]) / (sample_data[2, -1] - empty_data[2, 0]) + print('Heat flow slope from isotherms: {} per minute'.format(slope*60)) + + # calculate mean slope of heat flow at points in the beginning + slope_baseline = np.gradient(sample_baseline[1, int(4000/rate):int(9000/rate)], + sample_baseline[2, 300]-sample_baseline[2, 299]).mean() + print('Heat flow slope from initial heating: {} per minute'.format(slope_baseline*60)) + + drift_corrected = sample_baseline[1] - mean_isotherms[0] - (sample_baseline[2]-empty_data[2, 0])*slope + drift_from_slope = sample_baseline[1] - mean_isotherms[0] - (sample_baseline[2]-empty_data[2, 0])*slope_baseline + + # plot + ax1[0, 2].axhline(mean_isotherms[0], linestyle=':') + ax1[0, 2].axhline(mean_isotherms[1], linestyle=':') + + ax1[0, 2].plot(sample_baseline[2], sample_baseline[1], 'k-', label='Baseline corrected') + ax1[0, 2].plot(sample_baseline[2], drift_corrected, 'g-', label='Corrected (isotherm)') + ax1[0, 2].plot(sample_baseline[2], drift_from_slope, 'b-', label='Corrected (heating)') + + ax1[0, 2].plot(sample_baseline[2], mean_isotherms[0] + (sample_baseline[2]-empty_data[2, 0])*slope, 'g--') + ax1[0, 2].plot(sample_baseline[2], mean_isotherms[0] + slope_baseline*(sample_baseline[2]-empty_data[2, 0]), + 'b--') + + ax1[0, 2].plot(sample_baseline[2, int(4000/rate):int(9000/rate)], + sample_baseline[1, int(4000/rate):int(9000/rate)], 'r--') + + ax1[0, 2].set_title('time dependence') + ax1[0, 2].set_xlabel('t / s') + ax1[0, 2].legend() + + melts = [] + for i, (trans_temp, enthalpy) in enumerate(ref_points.transitions): + print(trans_temp, enthalpy) + + # region around reference peaks + # NOTE: limits are hard coded for cyclohexane, other references need other limits + low_border = np.argmin(abs(reference_data[0]-(trans_temp-15))) + high_border = np.argmin(abs(reference_data[0]-(trans_temp+15))) + ref_zoom = reference_data[:, low_border:high_border] + x_val = np.array([[ref_zoom[0, 0], 1], + [ref_zoom[0, -1], 1]]) + y_val = np.array([ref_zoom[1, 0], + ref_zoom[1, -1]]) + print('Baseline correct reference of {} transition'.format(trans_temp)) + sol = np.linalg.solve(x_val, y_val) + ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1]) + peak_max = ref_zoom[:, np.argmax(ref_zoom[1])] + integration_limit = np.argmin(abs(ref_zoom[0]-peak_max[0]+3)), np.argmin(abs(ref_zoom[0]-peak_max[0]-3)) + + # substract baseline around reference peaks + x_val = np.array([[ref_zoom[0, integration_limit[0]], 1], + [ref_zoom[0, integration_limit[1]], 1]]) + y_val = np.array([ref_zoom[1, integration_limit[0]], + ref_zoom[1, integration_limit[1]]]) + + print('Baseline correct reference of {} transition'.format(trans_temp)) + sol = np.linalg.solve(x_val, y_val) + ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1]) + + # calculate onset slope (use points at position of maximum gradient +/- 100/rate) + ref_grad = np.gradient(ref_zoom[1]) + max_grad = np.argmax(ref_grad) + + x_val = np.array([[ref_zoom[0, max_grad-int(100/rate)], 1], + [ref_zoom[0, max_grad+int(100/rate)+1], 1]]) + y_val = np.array([ref_zoom[1, max_grad-int(100/rate)], + ref_zoom[1, max_grad+int(100/rate)+1]]) + sol = np.linalg.solve(x_val, y_val) + onset = sol[0]*ref_zoom[0] + sol[1] + + melts.append(-sol[1]/sol[0]) + + # plot + ax1[1, i].set_title('reference: {:.2f} K'.format(trans_temp)) + ax1[1, i].set_xlabel('T / K') + + ax1[1, i].plot(reference_data[0], reference_data[1], 'r-') + ax1[1, i].plot(ref_zoom[0, max_grad], ref_zoom[0, max_grad], 'kx') + ax1[1, i].plot(ref_zoom[0], onset, 'k--') + ax1[1, i].axhline(0, color='k', linestyle='--') + + ax1[1, i].set_xlim(ref_zoom[0, integration_limit[0]], ref_zoom[0, integration_limit[1]]) + ax1[1, i].set_ylim(-max(ref_zoom[1])/10, max(ref_zoom[1])*1.1) + + print('Onset of transition: {:.2f} K, should be at {:.2f}'.format(melts[-1], trans_temp)) + if enthalpy is not None: + # integrate over low temperature peak to calibrate y axis + # NOTE: again, this is only valid for cyclohexane + # delta H in J/g: Integrate Peak over time and divide by weight + area = 1e-3 * simps(ref_zoom[1, integration_limit[0]:integration_limit[1]], + ref_zoom[2, integration_limit[0]:integration_limit[1]], + even='avg') + calib_y_axis = enthalpy / (area / reference.weight) + print("Calibration factor of peak: {}".format(calib_y_axis)) + + sample_baseline[1] *= calib_y_axis + + fig1.delaxes(ax1[1, 2]) + fig1.tight_layout() + + plt.show() + + # give a choice how to compensate for long-time drift + mode = None + while mode not in ['i', 'h']: + mode = input('\nUse [i]sotherms or initial [h]eating for long-time correction? (Default: i) ') + if mode == '': + mode = 'i' + + if mode == 'h': + print('\nCorrect slope from initial heating') + sample_baseline[1] = drift_from_slope + else: + print('\nCorrect slope from isotherm') + sample_baseline[1] = drift_corrected + + # calibrate T axis + print('\nCalibrate temperature') + real_trans = np.array([ref_points.transition1, ref_points.transition2]) + t_vals = np.array([[melts[0], 1], + [melts[1], 1]]) + calibration_temp = np.linalg.solve(t_vals, real_trans) + print('T_real = {:.4f} * T_meas {:+.4f}'.format(*calibration_temp)) + + sample_baseline[0] = calibration_temp[0] * sample_baseline[0] + calibration_temp[1] + + print('Convert to capacity') + cp = sample_baseline[1] * 60. / rate / sample.weight / 1000. + if sample.weight is None: + raise ValueError('No sample weight given') + + # plot final results in separate figure + fig2, ax2 = plt.subplots() + ax2.set_title('{} K/min: Heat flow vs. heat capacity (close to cont.)'.format(rate)) + ax2.set_xlabel('Temperature / K') + + ax2.plot(sample_baseline[0], sample_baseline[1], label='heat flow') + ax2.plot(sample_baseline[0], cp, label='heat capacity') + + plt.legend() + plt.show() + + outname = os.path.splitext(sample.name)[0] + '_' + str(rate) + 'K-min.dat' + header = 'Made with version: {}\n'.format(__version__) + header += 'T/K\tCp/J/(gK)\theat flow/mW' + + print() + print('Save to', outname) + np.savetxt(outname, np.c_[sample_baseline[0], cp, sample_baseline[1]], header=header) + + +if __name__ == '__main__': + args = parser.parse_args() + evaluate(args.sample, args.empty, args.reference, show_cooling=args.cooling) diff --git a/nmreval/fit/__init__.py b/nmreval/fit/__init__.py new file mode 100644 index 0000000..d311aa7 --- /dev/null +++ b/nmreval/fit/__init__.py @@ -0,0 +1,7 @@ +import numpy as np + +EPS = np.finfo(float).eps + + +class FitException(BaseException): + pass diff --git a/nmreval/fit/_meta.py b/nmreval/fit/_meta.py new file mode 100644 index 0000000..42e1d3f --- /dev/null +++ b/nmreval/fit/_meta.py @@ -0,0 +1,161 @@ +from typing import Union, Callable, Any +import operator + +from inspect import signature, Parameter + + +class ModelFactory: + + @staticmethod + def create_from_list(funcs: list, left=None, func_order=None, param_len=None, left_cnt=None): + if func_order is None: + func_order = [] + + if param_len is None: + param_len = [] + + for func in funcs: + if not func['active']: + continue + + func_order.append(func['cnt']) + param_len.append(len(func['func'].params)) + + if func['children']: + right, _, _ = ModelFactory.create_from_list(func['children'], left=func['func'], left_cnt=func['pos'], + func_order=func_order, param_len=param_len) + right_cnt = None + else: + right = func['func'] + right_cnt = func['pos'] + + if left is None: + left = right + left_cnt = right_cnt + else: + left = MultiModel(left, right, func['op'], + left_idx=left_cnt, right_idx=right_cnt) + + return left, func_order, param_len + + +class MultiModel: + op_repr = {operator.add: ' + ', operator.mul: ' * ', operator.sub: ' - ', operator.truediv: ' / '} + str_op = {'+': operator.add, '*': operator.mul, '-': operator.sub, '/': operator.truediv} + int_op = {0: operator.add, 1: operator.mul, 2: operator.sub, 3: operator.truediv} + + def __init__(self, left: Any, right: Any, op: Union[str, Callable, int] = '+', left_idx=0, right_idx=1): + self._left = left + self._right = right + + self._op = None + + if isinstance(op, str): + self._op = MultiModel.str_op.get(op, None) + elif isinstance(op, int): + self._op = MultiModel.int_op.get(op, None) + elif isinstance(op, Callable): + self._op = op + + if self._op is None: + raise ValueError('Invalid binary operator.') + + self.name = '(' + self.params = [] + self.bounds = [] + self._kwargs_right = {} + self._kwargs_left = {} + self._fun_kwargs = {} + + # mapping kwargs to kwargs of underlying functions + self._ext_int_kw = {} + + self._get_parameter(left, 'l', left_idx) + self._param_left = len(left.params) + + try: + self.name += MultiModel.op_repr[self._op] + except KeyError: + self.name += str(op) + + self._get_parameter(right, 'r', right_idx) + self.name += ')' + + self._param_len = len(self.params) + + def __str__(self): + return self.name + + def _get_parameter(self, func, pos, idx): + kw_dict = {'l': self._kwargs_left, 'r': self._kwargs_right}[pos] + + if isinstance(func, MultiModel): + strcnt = '' + kw_dict.update(func.fun_kwargs) + self._fun_kwargs.update({k: v for k, v in kw_dict.items()}) + self._ext_int_kw.update({k: k for k in kw_dict.keys()}) + + else: + temp_dic = {k: v.default for k, v in signature(func.func).parameters.items() + if v.default is not Parameter.empty} + + for k, v in temp_dic.items(): + key_ = '%s_%d' % (k, idx) + kw_dict[key_] = v + self._fun_kwargs[key_] = v + self._ext_int_kw[key_] = k + + strcnt = '(%d)' % idx + + self.params += [pp+strcnt for pp in func.params] + self.name += func.name + strcnt + + try: + self.bounds.extend(func.bounds) + except AttributeError: + self.bounds.extend([(None, None)]*len(func.params)) + + def _left_arguments(self, *args, **kwargs): + kw_left = {k_int: kwargs[k_ext] for k_ext, k_int in self._ext_int_kw.items() if k_ext in self._kwargs_left} + pl = args[:self._param_left] + + return pl, kw_left + + def _right_arguments(self, *args, **kwargs): + kw_right = {k_int: kwargs[k_ext] for k_ext, k_int in self._ext_int_kw.items() if k_ext in self._kwargs_right} + pr = args[self._param_left:self._param_len] + + return pr, kw_right + + def func(self, x, *args, **kwargs): + pl, kw_left = self._left_arguments(*args, **kwargs) + l_func = self._left.func(x, *pl, **kw_left) + + pr, kw_right = self._right_arguments(*args, **kwargs) + r_func = self._right.func(x, *pr, **kw_right) + + return self._op(l_func, r_func) + + def left_func(self, x, *args, **kwargs): + return self._left.func(x, *args, **kwargs) + + def right_func(self, x, *args, **kwargs): + return self._right.func(x, *args, **kwargs) + + @property + def fun_kwargs(self): + return self._fun_kwargs + + def subs(self, x, *args, **kwargs): + """ Iterator over all sub-functions (depth-first and left-to-right) """ + pl, kw_left = self._left_arguments(*args, **kwargs) + if isinstance(self._left, MultiModel): + yield from self._left.subs(x, *pl, **kw_left) + else: + yield self._left.func(x, *pl, **kw_left) + + pr, kw_right = self._right_arguments(*args, **kwargs) + if isinstance(self._right, MultiModel): + yield from self._right.subs(x, *pr, **kw_right) + else: + yield self._right.func(x, *pr, **kw_right) diff --git a/nmreval/fit/data.py b/nmreval/fit/data.py new file mode 100644 index 0000000..42b95bb --- /dev/null +++ b/nmreval/fit/data.py @@ -0,0 +1,149 @@ +import numpy as np + +from .model import Model +from .parameter import Parameters + + +class Data(object): + def __init__(self, x, y, we=None, idx=None): + self.x = np.asarray(x) + self.y = np.asarray(y) + if self.y.shape[0] != self.x.shape[0]: + raise ValueError(f'x and y have different lengths {self.x.shape[0]} and {self.y.shape[0]}') + + self.we = self._calc_weights(we) + self.idx = idx + self.model = None + self.minimizer = None + self.parameter = Parameters() + self.para_keys = None + self.fun_kwargs = {} + + def __len__(self): + return self.y.shape[0] + + def _calc_weights(self, we): + if we is None: + return 1. + + if isinstance(we, str): + if we == 'y2': + we_func = lambda yy: 1. / yy**2 + elif we.lower() == 'none': + we_func = lambda yy: np.ones_like(len(yy)) + else: + we_func = lambda yy: 1. / np.abs(yy) + + if np.iscomplexobj(self.y): + weights = we_func(np.r_[self.y.real, self.y.imag]) + else: + weights = we_func(self.y) + + else: + we = 1. / np.asarray(we) + if np.iscomplexobj(self.y): + if np.iscomplexobj(we): + weights = np.r_[we.real, we.imag] + else: + weights = np.tile(we) + else: + weights = we + + weights[weights == np.inf] = np.finfo(float).max + + return weights + + def set_model(self, func, *args, **kwargs): + if isinstance(func, Model): + self.model = func + else: + self.model = Model(func, *args) + + self.fun_kwargs.update(self.model.fun_kwargs) + self.fun_kwargs.update(kwargs) + self.parameter = Parameters() + + return self.model + + def get_model(self): + return self.model + + def set_parameter(self, parameter, var=None, ub=None, lb=None, + default_bounds=False, fun_kwargs=None): + """ + Creates parameter for this data. + If no Model is available, it falls back to the model + :param parameter: list of parameters + :param var: list of boolean or boolean; False fixes parameter at given list index. + Single value is broadcast to all parameter + :param ub: list of upper boundaries or float; Single value is broadcast to all parameter. + None means no bound. + :param lb: list of lower bounds or float; Single value is broadcast to all parameter. + None means no bound. + :param default_bounds: bool; If True, uses default_bounds of a Model if lb or ub are None + :param fun_kwargs: dict; key-word arguments for model, + :return: Parameters + """ + model = self.model + if model is None: + # Data has no unique + if self.minimizer is None: + model = None + else: + model = self.minimizer.fit_model + self.fun_kwargs.update(model.fun_kwargs) + + if model is None: + raise ValueError('No model found, please set model before parameters') + + if default_bounds: + if lb is None: + lb = model.lb + if ub is None: + ub = model.ub + + self.para_keys = self.parameter.add_parameter(parameter, var=var, lb=lb, ub=ub) + + if fun_kwargs is not None: + self.fun_kwargs.update(fun_kwargs) + + return self.para_keys + + def get_parameter(self, scaled: bool = False): + """ + Returns list of parameters if set. + :param scaled: If True, returns scaled values, otherwise unscaled + :return: parameter array + """ + if self.parameter is None: + return + + if scaled: + return [p.scaled_value for p in self.minimizer.parameters[self.parameter]] + else: + return [p.value for p in self.minimizer.parameters[self.parameter]] + + def cost(self, p): + """ + Cost function :math:`y-f(p, x)` + :param p: list of parameters + :return: + """ + y_pred = self.model.func(p, self.x, **self.fun_kwargs) + resid = y_pred - self.y + + if np.iscomplexobj(resid): + resid = np.r_[resid.real, resid.imag] + + resid *= self.we + + return resid + + def func(self, p, x): + """ + Function :math:`f(p, x)` + :param x: + :param p: list of parameters + :return: + """ + return self.model.func(p, x, **self.fun_kwargs) diff --git a/nmreval/fit/minimizer.py b/nmreval/fit/minimizer.py new file mode 100644 index 0000000..4d5dc05 --- /dev/null +++ b/nmreval/fit/minimizer.py @@ -0,0 +1,489 @@ +import warnings +from itertools import product + +import numpy as np +import scipy.linalg as la +from scipy import optimize +import scipy.odr as odr + +from .data import Data +from .model import Model +from . import EPS +from .parameter import Parameters +from .result import FitResultCreator + +__all__ = ['FitRoutine', 'FitAbortException'] + + +class FitAbortException(Exception): + pass + + +class FitRoutine(object): + def __init__(self, mode='lsq'): + self._fitmethod = mode + self.data = [] + self.fit_model = None + self._no_own_model = [] + self.parameter = Parameters() + self.result = [] + self.linked = [] + self._abort = False + + def add_data(self, x, y=None, we=None, idx=None): + if isinstance(x, Data): + d = x + + else: + _x = np.asarray(x) + if _x.ndim == 2 and _x.shape[1] == 2: + d = Data(*x, we=we) + + elif y is None: + raise ValueError('First argument must be of type Data, 2d-array, ' + 'or second argument must be given') + + else: + d = Data(x, y, we=we, idx=idx) + + if idx is not None: + d.idx = idx + d.minimizer = self + self.data.append(d) + self.result.append(None) + + return d + + def remove_data(self, data): + try: + idx = self.data.index(data) + _ = self.data.pop(idx) + self.result.pop(idx) + + except ValueError: + raise IndexError('Data {} not found'.format(data)) + + def set_model(self, func, *args, idx=None, **kwargs): + if isinstance(func, Model): + model = func + else: + model = Model(func, *args, **kwargs) + + if idx is not None: + for i, data in enumerate(self.data): + if data.idx == idx: + data.set_model(model) + else: + self.fit_model = model + + return self.fit_model + + def set_link_parameter(self, parameter: tuple, replacement: tuple): + if isinstance(replacement[0], Model): + if replacement[1] not in replacement[0].global_parameter: + raise KeyError(f'Parameter at pos {replacement[1]} of ' + f'model {str(replacement[0])} is not global') + + if isinstance(parameter[0], Model): + warnings.warn(f'Replaced parameter at pos {parameter[1]} in {str(parameter[0])} ' + f'becomes global with linkage.') + + self.linked.append((*parameter, *replacement)) + + def prepare_links(self): + self._no_own_model = [] + self.parameter = Parameters() + _found_models = {} + linked_sender = {} + + for v in self.data: + linked_sender[v] = set() + self.parameter.update(v.parameter.copy()) + + # set temporaray model + if v.model is None: + v.model = self.fit_model + self._no_own_model.append(v) + + # register model + if v.model not in _found_models: + _found_models[v.model] = [] + m_param = v.model.parameter.copy() + self.parameter.update(m_param) + + _found_models[v.model].append(v) + + if v.model not in linked_sender: + linked_sender[v.model] = set() + + linked_parameter = {} + for par, par_parm, repl, repl_par in self.linked: + if isinstance(par, Data): + if isinstance(repl, Data): + linked_parameter[par.para_keys[par_parm]] = repl.para_keys[repl_par] + else: + linked_parameter[par.para_keys[par_parm]] = repl.global_parameter[repl_par] + + else: + if isinstance(repl, Data): + par.global_parameter[par_parm] = repl.para_keys[repl_par] + else: + par.global_parameter[par_parm] = repl.global_parameter[repl_par] + + linked_sender[repl].add(par) + linked_sender[par].add(repl) + + for mm, m_data in _found_models.items(): + if mm.global_parameter: + for dd in m_data: + linked_sender[mm].add(dd) + linked_sender[dd].add(mm) + + coupled_data = [] + visited_data = [] + for s in linked_sender.keys(): + if s in visited_data: + continue + sub_graph = [] + self.find_paths(s, linked_sender, sub_graph, visited_data) + if sub_graph: + coupled_data.append(sub_graph) + + return coupled_data, linked_parameter + + def find_paths(self, start, graph, coupled_nodes=None, visited_nodes=None): + visited_nodes.append(start) + if isinstance(start, Data): + coupled_nodes.append(start) + + for neighbor in graph[start]: + if neighbor in visited_nodes: + continue + + self.find_paths(neighbor, graph, coupled_nodes, visited_nodes) + + def abort(self): + print('ABORT ???') + self._abort = True + + def run(self, mode='lsq'): + self._abort = False + self.parameter = Parameters() + + fit_groups, linked_parameter = self.prepare_links() + + for data_groups in fit_groups: + if len(data_groups) == 1 and not self.linked: + data = data_groups[0] + # get variable parameter for fitter + p0_k, lb_k, ub_k, var_pars_k = self._prep_data(data) + + if mode == 'lsq': + self._least_squares_single(data, p0_k, lb_k, ub_k, var_pars_k) + + elif mode == 'nm': + self._nm_single(data, p0_k, lb_k, ub_k, var_pars_k) + + elif mode == 'odr': + # ODR takes no bounds + self._odr_single(data, p0_k, var_pars_k) + + else: + data_pars, p0, lb, ub, var_pars = self._prep_global(data_groups, linked_parameter) + + if mode == 'lsq': + self._least_squares_global(data_groups, p0, lb, ub, var_pars, data_pars) + + elif mode == 'nm': + self._nm_global(data_groups, p0, lb, ub, var_pars, data_pars) + + elif mode == 'odr': + self._odr_global(data_groups, p0, var_pars, data_pars) + + self.unprep_run() + + return self.result + + def _prep_data(self, data): + if data.get_model() is None: + data._model = self.fit_model + self._no_own_model.append(data) + + return self._prep_parameter(data.parameter) + + @staticmethod + def _prep_parameter(parameter): + vals = [] + var_pars = [] + for p_k, v_k in parameter.items(): + if v_k.var: + vals.append([v_k.scaled_value, v_k.lb / v_k.scale, v_k.ub / v_k.scale]) + var_pars.append(p_k) + + pp, lb, ub = zip(*vals) + + return pp, lb, ub, var_pars + + def _prep_global(self, data_group, linked): + p0 = [] + lb = [] + ub = [] + var = [] + data_pars = [] + + # loopyloop over data that belong to one fit (linked or global) + for data in data_group: + actual_pars = [] + for i, (p_k, v_k) in enumerate(data.parameter.items()): + p_k_used = p_k + v_k_used = v_k + + # is parameter replaced by global parameter? + if i in data.model.global_parameter: + p_k_used = data.model.global_parameter[i] + v_k_used = self.parameter[p_k_used] + + # links trump global parameter + if p_k_used in linked: + p_k_used = linked[p_k_used] + v_k_used = self.parameter[p_k_used] + + actual_pars.append(p_k_used) + # parameter is variable and was not found before as shared parameter + if v_k_used.var and p_k_used not in var: + p0.append(v_k_used.scaled_value) + lb.append(v_k_used.lb / v_k_used.scale) + ub.append(v_k_used.ub / v_k_used.scale) + var.append(p_k_used) + + data_pars.append(actual_pars) + + return data_pars, p0, lb, ub, var + + def unprep_run(self): + for d in self._no_own_model: + d._model = None + + self._no_own_model = [] + + # COST FUNCTIONS: f(x) - y (least_square, minimize), and f(x) (ODR) + def __cost_scipy(self, p, data, varpars, used_pars): + for keys, values in zip(varpars, p): + self.parameter[keys].scaled_value = values + + actual_parameters = [self.parameter[keys].value for keys in used_pars] + return data.cost(actual_parameters) + + def __cost_odr(self, p, data, varpars, used_pars): + for keys, values in zip(varpars, p): + self.parameter[keys].scaled_value = values + + actual_parameters = [self.parameter[keys].value for keys in used_pars] + + return data.func(actual_parameters, data.x) + + def __cost_scipy_glob(self, p, data, varpars, used_pars): + # replace values + for keys, values in zip(varpars, p): + self.parameter[keys].scaled_value = values + + r = [] + # unpack parameter and calculate y values and concatenate all + for values, p_idx in zip(data, used_pars): + actual_parameters = [self.parameter[keys].value for keys in p_idx] + r = np.r_[r, values.cost(actual_parameters)] + + return r + + def __cost_odr_glob(self, p, data, varpars, used_pars): + # replace values + for keys, values in zip(varpars, p): + self.parameter[keys].scaled_value = values + + r = [] + # unpack parameter and calculate y values and concatenate all + for values, p_idx in zip(data, used_pars): + actual_parameters = [self.parameter[keys].value for keys in p_idx] + r = np.r_[r, values.func(actual_parameters, values.x)] + + return r + + def _least_squares_single(self, data, p0, lb, ub, var): + def cost(p): + if self._abort: + raise FitAbortException(f'Fit aborted by user') + + return self.__cost_scipy(p, data, var, data.para_keys) + + with np.errstate(all='ignore'): + res = optimize.least_squares(cost, p0, bounds=(lb, ub), max_nfev=1000 * len(p0)) + + err, corr, partial_corr = self._calc_error(res.jac, np.sum(res.fun**2), *res.jac.shape) + self.make_results(data, res.x, var, data.para_keys, res.jac.shape, + err=err, corr=corr, partial_corr=partial_corr) + + def _least_squares_global(self, data, p0, lb, ub, var, data_pars): + def cost(p): + if self._abort: + raise FitAbortException(f'Fit aborted by user') + return self.__cost_scipy_glob(p, data, var, data_pars) + + with np.errstate(all='ignore'): + res = optimize.least_squares(cost, p0, bounds=(lb, ub), max_nfev=1000 * len(p0)) + + err, corr, partial_corr = self._calc_error(res.jac, np.sum(res.fun**2), *res.jac.shape) + for v, var_pars_k in zip(data, data_pars): + self.make_results(v, res.x, var, var_pars_k, res.jac.shape, + err=err, corr=corr, partial_corr=partial_corr) + + def _nm_single(self, data, p0, lb, ub, var): + def cost(p): + if self._abort: + raise FitAbortException(f'Fit aborted by user') + return (self.__cost_scipy(p, data, var, data.para_keys)**2).sum() + + with np.errstate(all='ignore'): + res = optimize.minimize(cost, p0, bounds=[(b1, b2) for (b1, b2) in zip(lb, ub)], + method='Nelder-Mead', options={'maxiter': 1000 * len(p0)}) + + self.make_results(data, res.x, var, data.para_keys, (len(data), len(p0))) + + def _nm_global(self, data, p0, lb, ub, var, data_pars): + def cost(p): + if self._abort: + raise FitAbortException(f'Fit aborted by user') + return (self.__cost_scipy_glob(p, data, var, data_pars)**2).sum() + + with np.errstate(all='ignore'): + res = optimize.minimize(cost, p0, bounds=[(b1, b2) for (b1, b2) in zip(lb, ub)], + method='Nelder-Mead', options={'maxiter': 1000 * len(p0)}) + + for v, var_pars_k in zip(data, data_pars): + self.make_results(v, res.x, var, var_pars_k, (sum(len(d) for d in data), len(p0))) + + def _odr_single(self, data, p0, var_pars): + odr_data = odr.Data(data.x, data.y) + + def func(p, _): + if self._abort: + raise FitAbortException(f'Fit aborted by user') + return self.__cost_odr(p, data, var_pars, data.para_keys) + + odr_model = odr.Model(func) + + o = odr.ODR(odr_data, odr_model, beta0=p0) + res = o.run() + + corr = res.cov_beta / (res.sd_beta[:, None] * res.sd_beta[None, :]) * res.res_var + try: + corr_inv = np.linalg.inv(corr) + corr_inv_diag = np.diag(np.sqrt(1 / np.diag(corr_inv))) + partial_corr = -1. * np.dot(np.dot(corr_inv_diag, corr_inv), corr_inv_diag) # Partial correlation matrix + partial_corr[np.diag_indices_from(partial_corr)] = 1. + except np.linalg.LinAlgError: + partial_corr = corr + + self.make_results(data, res.beta, var_pars, data.para_keys, (len(data), len(p0)), + err=res.sd_beta, corr=corr, partial_corr=partial_corr) + + def _odr_global(self, data, p0, var, data_pars): + def func(p, _): + if self._abort: + raise FitAbortException(f'Fit aborted by user') + return self.__cost_odr_glob(p, data, var, data_pars) + + x = [] + y = [] + for d in data: + x = np.r_[x, d.x] + y = np.r_[y, d.y] + + odr_data = odr.Data(x, y) + odr_model = odr.Model(func) + + o = odr.ODR(odr_data, odr_model, beta0=p0, ifixb=var) + res = o.run() + + corr = res.cov_beta / (res.sd_beta[:, None] * res.sd_beta[None, :]) * res.res_var + try: + corr_inv = np.linalg.inv(corr) + corr_inv_diag = np.diag(np.sqrt(1 / np.diag(corr_inv))) + partial_corr = -1. * np.dot(np.dot(corr_inv_diag, corr_inv), corr_inv_diag) # Partial correlation matrix + partial_corr[np.diag_indices_from(partial_corr)] = 1. + except np.linalg.LinAlgError: + partial_corr = corr + + for v, var_pars_k in zip(data, data_pars): + self.make_results(v, res.beta, var, var_pars_k, (sum(len(d) for d in data), len(p0)), + err=res.sd_beta, corr=corr, partial_corr=partial_corr) + + def make_results(self, data, p, var_pars, used_pars, shape, + err=None, corr=None, partial_corr=None): + + if err is None: + err = [0] * len(p) + + # update parameter values + for keys, p_value, err_value in zip(var_pars, p, err): + self.parameter[keys].scaled_value = p_value + self.parameter[keys].scaled_error = err_value + + combinations = list(product(var_pars, var_pars)) + actual_parameters = [] + corr_idx = [] + + for i, p_i in enumerate(used_pars): + actual_parameters.append(self.parameter[p_i]) + for j, p_j in enumerate(used_pars): + try: + # find the position of the parameter combinations + corr_idx.append(combinations.index((p_i, p_j))) + except ValueError: + pass + + # reshape the correlation matrices + if corr is None: + actual_corr = None + actual_pcorr = None + else: + indexes = np.unravel_index(corr_idx, corr.shape) + dim_one = int(np.sqrt(len(corr_idx))) + actual_corr = corr[indexes].reshape((dim_one, -1)) + actual_pcorr = partial_corr[indexes].reshape((dim_one, -1)) + + idx = self.data.index(data) + model = data.get_model() + + self.result[idx] = FitResultCreator.make_with_model(model, data.x, data.y, + actual_parameters, data.fun_kwargs, data.idx, + *shape, corr=actual_corr, pcorr=actual_pcorr) + + return self.result + + @staticmethod + def _calc_error(jac, chi, nobs, nvars): + # copy of scipy.curve_fit to calculate covariance + # noinspection PyTupleAssignmentBalance + _, s, vt = la.svd(jac, full_matrices=False) + threshold = EPS * max(jac.shape) * s[0] + s = s[s > threshold] + vt = vt[:s.size] + pcov = np.dot(vt.T / s**2, vt) * chi / (nobs - nvars) + + if pcov is None: + _err = np.zeros(nvars) + corr = np.zeros((nvars, nvars)) + else: + _err = np.sqrt(np.diag(pcov)) + corr = pcov / (_err[:, None] * _err[None, :]) + + corr = corr.astype(np.float64) + try: + corr_inv = np.linalg.inv(corr) + corr_inv_diag = np.diag(np.sqrt(1 / np.diag(corr_inv))) + partial_corr = -1. * np.dot(np.dot(corr_inv_diag, corr_inv), corr_inv_diag) # Partial correlation matrix + partial_corr[np.diag_indices_from(partial_corr)] = 1. + except np.linalg.LinAlgError: + partial_corr = corr + + return _err, corr, partial_corr diff --git a/nmreval/fit/model.py b/nmreval/fit/model.py new file mode 100644 index 0000000..1df8fbf --- /dev/null +++ b/nmreval/fit/model.py @@ -0,0 +1,153 @@ +import inspect +from typing import Sized + +from numpy import inf + +from ._meta import MultiModel +from .parameter import Parameters + + +class Model(object): + def __init__(self, model, *args, **kwargs): + self.idx = kwargs.pop('idx', None) + + self.is_multi = False + if inspect.isclass(model) or isinstance(model, MultiModel): + self._init_from_class(model) + elif inspect.isfunction(model): + self._init_from_function(model) + else: + raise ValueError(f'No idea how to use datatype {model}.') + + self.lb = [i if i is not None else -inf for i in self.lb] + self.ub = [i if i is not None else inf for i in self.ub] + + self.parameter = Parameters() + self.global_parameter = {} + self.is_complex = None + self._complex_part = False + + if 'complex' in kwargs: + self.set_complex(kwargs.pop('complex')) + + if args: + self.fun_args = args + else: + self.fun_args = [] + + self.fun_kwargs.update(kwargs) + + def _init_from_function(self, func): + self.name = str(func) + self._int_func = func + self._int_iter = func + + self.params = [] + self.fun_kwargs = {} + for k, v in inspect.signature(func).parameters.items(): + if v.default != inspect.Parameter.empty: + self.fun_kwargs[k] = v.default + else: + self.params.append(k) + # first parameter is x + self.params.pop(0) + + self.lb = [None] * len(self.params) + self.ub = [None] * len(self.params) + + def _init_from_class(self, model): + self.name = model.name + self.params = model.params + self._int_func = model.func + if hasattr(model, 'subs'): + self._int_iter = model.subs + self.is_multi = True + else: + self._int_iter = model.func + + + try: + self.lb, self.ub = list(zip(*model.bounds)) + except AttributeError: + self.lb = [None] * len(self.params) + self.ub = [None] * len(self.params) + + if isinstance(model, MultiModel): + self.fun_kwargs = model.fun_kwargs + else: + self.fun_kwargs = {k: v.default for k, v in inspect.signature(model.func).parameters.items() + if v.default is not inspect.Parameter.empty} + + def set_complex(self, state): + if state not in [None, 'complex', 'real', 'imag']: + raise ValueError('"complex" argument is not None, "complex", "real", "imag"') + + self.is_complex = state + if state in ['real', 'imag']: + self._complex_part = state + else: + self._complex_part = False + + def set_global_parameter(self, idx, p, var=None, lb=None, ub=None, default_bounds=False): + if idx is None: + self.parameter = Parameters() + self.global_parameter = {} + return + + if default_bounds: + if lb is None: + lb = [self.lb[i] for i in idx] + if ub is None: + ub = [self.lb[i] for i in idx] + + gp = self.parameter.add_parameter(p, var=var, lb=lb, ub=ub) + for k, v in zip(idx, gp): + self.global_parameter[k] = v + + return gp + + @staticmethod + def _prep(param_len, val): + if isinstance(val, Sized): + if len(val) != param_len: + raise ValueError('Length mismatch for global parameter') + else: + return [val] * param_len + + def __str__(self): + msg = 'Model: ' + self.name + return msg + + def __len__(self): + return len(self.params) + + def func(self, p, x, **kwargs): + if not kwargs: + kwargs = self.fun_kwargs + + f = self._int_func(x, *p, *self.fun_args, **kwargs) + + if self._complex_part: + if self._complex_part == 'real': + return f.real + else: + return f.imag + + return f + + def sub(self, p, x, **kwargs): + if not self.is_multi: + return [self.func(p, x, **kwargs)] + + else: + print('multi model') + if not kwargs: + kwargs = self.fun_kwargs + + if self._complex_part: + if self._complex_part == 'real': + return [f.real for f in self._int_iter(x, *p, *self.fun_args, **kwargs)] + else: + return [f.imag for f in self._int_iter(x, *p, *self.fun_args, **kwargs)] + + return list(self._int_iter(x, *p, *self.fun_args, **kwargs)) diff --git a/nmreval/fit/parameter.py b/nmreval/fit/parameter.py new file mode 100644 index 0000000..c23cff1 --- /dev/null +++ b/nmreval/fit/parameter.py @@ -0,0 +1,155 @@ +from numbers import Number +from itertools import count + +import numpy as np + + +class Parameters(dict): + count = count() + + def __str__(self): + return 'Parameters:\n' + '\n'.join([str(k)+': '+str(v) for k, v in self.items()]) + + def __getitem__(self, item): + if isinstance(item, (list, tuple, np.ndarray)): + values = [] + for item_i in item: + values.append(super().__getitem__(item_i)) + return values + else: + return super().__getitem__(item) + + @staticmethod + def _prep_bounds(val, p_len: int) -> list: + # helper function to ensure that bounds and variable are of parameter shape + if isinstance(val, (Number, bool)) or val is None: + return [val] * p_len + + elif len(val) == p_len: + return val + + elif len(val) == 1: + return [val[0]] * p_len + + else: + raise ValueError('Input {} has wrong dimensions'.format(val)) + + def add_parameter(self, param, var=None, lb=None, ub=None): + if isinstance(param, Number): + param = [param] + + p_len = len(param) + + # make list if only single value is given + var = self._prep_bounds(var, p_len) + lb = self._prep_bounds(lb, p_len) + ub = self._prep_bounds(ub, p_len) + + new_keys = [] + for i in range(p_len): + new_idx = next(self.count) + new_keys.append(new_idx) + + self[new_idx] = Parameter(param[i], var=var[i], lb=lb[i], ub=ub[i]) + + return new_keys + + def copy(self): + p = Parameters() + for k, v in self.items(): + p[k] = Parameter(v.value, var=v.var, lb=v.lb, ub=v.ub) + + if len(p) == 0: + return p + + max_k = max(p.keys()) + c = next(p.count) + while c < max_k: + c = next(p.count) + + return p + + def get_state(self): + return {k: v.get_state() for k, v in self.items()} + + +class Parameter: + """ + Container for one parameter + """ + __slots__ = ['name', 'value', 'error', 'init_val', 'var', 'lb', 'ub', 'scale', 'function'] + + def __init__(self, value: float, var: bool = True, lb: float = -np.inf, ub: float = np.inf): + self.lb = lb if lb is not None else -np.inf + self.ub = ub if ub is not None else np.inf + + if self.lb <= value <= self.ub: + self.value = value + else: + raise ValueError('Value of parameter is outside bounds') + + self.init_val = value + + with np.errstate(divide='ignore'): + # throws RuntimeWarning for zeros + self.scale = 10**(np.floor(np.log10(np.abs(self.value)))) + + if self.scale == 0: + self.scale = 1. + + self.var = bool(var) if var is not None else True + self.error = None if self.var is False else 0.0 + self.name = '' + self.function = '' + + def __str__(self): + start = '' + if self.name: + if self.function: + start = f'{self.name} ({self.function}): ' + else: + start = self.name + ': ' + + if self.var: + return start + f'{self.value:.4g} +/- {self.error:.4g}, init={self.init_val}' + else: + return start + f'{self.value:} (fixed)' + + @property + def scaled_value(self): + return self.value / self.scale + + @scaled_value.setter + def scaled_value(self, value): + self.value = value * self.scale + + @property + def scaled_error(self): + if self.error is None: + return self.error + else: + return self.error / self.scale + + @scaled_error.setter + def scaled_error(self, value): + self.error = value * self.scale + + def get_state(self): + + return {slot: getattr(self, slot) for slot in self.__slots__} + + @staticmethod + def set_state(state: dict): + par = Parameter(state.pop('value')) + for k, v in state.items(): + setattr(par, k, v) + + return par + + @property + def full_name(self): + name = self.name + if self.function: + name += ' (' + self.function + ')' + + return name diff --git a/nmreval/fit/result.py b/nmreval/fit/result.py new file mode 100644 index 0000000..97a8a5f --- /dev/null +++ b/nmreval/fit/result.py @@ -0,0 +1,339 @@ +import pathlib +import re +from collections import OrderedDict + +import numpy as np +from scipy.stats import f as fdist +from scipy.interpolate import interp1d + +from ..data.points import Points +from .parameter import Parameter +from ..data.signals import Signal +from ..utils.text import convert + + +class FitResultCreator: + @staticmethod + def make_from_session(x_orig, y_orig, idx, kwargs) -> (dict, list): + params = OrderedDict() + + for key, pbest, err in zip(kwargs['pnames'], kwargs['parameter'], kwargs['error']): + params[key] = Parameter(pbest) + params[key].error = err + + _x = kwargs['x'] + _y = kwargs['y'] + + if len(_x) != len(x_orig): + f = interp1d(_x, _y) + rng = (x_orig >= np.min(_x)) * (x_orig <= np.max(_x)) + resid = f(x_orig[rng]) - y_orig[rng] + else: + resid = kwargs['y'] - y_orig + + stats = FitResultCreator.calc_statistics(resid, _y) + + return FitResult(kwargs['x'], kwargs['y'], x_orig, y_orig, params, dict(kwargs['choice']), resid, 0, 0, + kwargs['name'], stats, idx), [] + + @staticmethod + def make_with_model(model, x_orig, y_orig, p, fun_kwargs, idx, nobs, nvar, corr, pcorr) -> (dict, list): + if np.all(x_orig > 0) and (np.max(x_orig) > 100 * np.min(x_orig)): + islog = True + else: + islog = False + + if len(x_orig) < 51: + if islog: + _x = np.logspace(np.log10(np.min(x_orig)), np.log10(np.max(x_orig)), num=10*x_orig.size-9) + else: + _x = np.linspace(np.min(x_orig), np.max(x_orig), num=10*x_orig.size-9) + else: + _x = x_orig + + try: + pnames = model.pnames + except AttributeError: + pnames = model.params + + parameters = OrderedDict([(k, v) for k, v in zip(pnames, p)]) + p_final = [p.value for p in parameters.values()] + + part_functions = [] + + if model.is_multi: + for sub_y in model.sub(p_final, _x, **fun_kwargs): + if np.iscomplexobj(sub_y): + part_functions.append(Signal(_x, sub_y)) + else: + part_functions.append(Points(_x, sub_y)) + + _y = model.func(p_final, _x, **fun_kwargs) + resid = model.func(p_final, x_orig, **fun_kwargs) - y_orig + + stats = FitResultCreator.calc_statistics(_y, resid, nobs, nvar) + varied = [p.var for p in parameters.values()] + + if corr is None: + correlation = np.eye(len(p_final), len(p_final)) + partial_correlation = np.eye(len(p_final), len(p_final)) + + else: + if len(corr) < len(p_final): + correlation = np.eye(len(p_final), len(p_final)) + partial_correlation = np.eye(len(p_final), len(p_final)) + # probably some fixed variables + j = 0 + for i in range(len(corr)): + while not varied[j]: + j += 1 + correlation[j, varied] = corr[i] + partial_correlation[j, varied] = pcorr[i] + j += 1 + else: + correlation = corr + partial_correlation = pcorr + + return FitResult(_x, _y, x_orig, y_orig, parameters, fun_kwargs, resid, nobs, nvar, model.name, stats, + idx=idx, corr=correlation, pcorr=partial_correlation, islog=islog, iscomplex=model.is_complex), part_functions + + @staticmethod + def calc_statistics(y, residual, nobs=None, nvar=None): + chi = (residual**2).sum() + try: + r = 1 - chi/((y-np.mean(y))**2).sum() + except RuntimeWarning: + r = -9999 + + if nobs is None: + nobs = 1 + + if nvar is None: + nvar = 0 + + dof = nobs - nvar + loglikehood = nobs * np.log(chi / nobs) + + stats = { + 'chi^2': chi, + 'R^2': r, + 'AIC': loglikehood + 2 * nvar, + 'BIC': loglikehood + np.log(nobs) * nvar + } + + if dof != 0: + stats['adj. R^2'] = 1 - (nobs-1)/dof * (1-r) + stats['red. chi^2'] = chi / dof if dof != 0 else 0 + + if dof != 1: + stats['AICc'] = stats['AIC'] + 2*(nvar+1)*nvar / (dof-1) + + return stats + + +class FitResult(Points): + + def __init__(self, x, y, x_data, y_data, params, fun_kwargs, resid, nobs, nvar, name, stats, + idx=None, corr=None, pcorr=None, islog=False, iscomplex=None, + **kwargs): + + self.parameter, name = self._prepare_names(params, name) + + super().__init__(x=x, y=y, name=name, **kwargs) + + self.residual = resid + self.idx = idx + self.statistics = stats + self.nobs = nobs + self.nvar = nvar + self.fun_kwargs = fun_kwargs + self.correlation = corr + self.partial_correlation = pcorr + self.islog = islog + self.iscomplex = iscomplex + self.x_data = x_data + self.y_data = y_data + self._model_name = name + + @staticmethod + def _prepare_names(parameter: dict, modelname: str): + pattern = re.compile(r'(\\?\w[\\\w .-]*(?:_{[\w\\ .-]})?)(\(\d+\))') + + split_funcs = {g2: g1 for (g1, g2) in pattern.findall(modelname)} + + parameter_dic = {} + for pname, pvalue in parameter.items(): + nice_name = pname + nice_func = '' + m = pattern.match(pname) + if m: + func_number = m.group(2) + nice_name = m.group(1) + if func_number in split_funcs: + nice_func = split_funcs[func_number] + + pvalue.name = nice_name + pvalue.function = nice_func + parameter_dic[pname] = pvalue + + modelname = re.sub(r'\(\d+\)', '', modelname) + if modelname[0] == '(' and modelname[-1] == ')': + modelname = modelname[1:-1] + + return parameter_dic, modelname + + @property + def model_name(self): + return self._model_name + + def __len__(self): + return len(self.parameter) + + def __repr__(self): + try: + return 'Fit: ' + self.name + except AttributeError: + return 'FitObject' + + @property + def p_final(self): + return [pp.value for pp in self.parameter.values()] + + @property + def dof(self): + return self.nobs-self.nvar + + def pprint(self, statistics=True, correlations=True): + print('Fit result:') + print(' model :', self.name) + print(' #data :', self.nobs) + print(' #var :', self.nvar) + print('\nParameter') + print(self._parameter_string()) + if statistics: + print('Statistics') + for k, v in self.statistics.items(): + print(f' {k} : {v:.4f}') + + if correlations and self.correlation is not None: + print('\nCorrelation (partial corr.)') + print(self._correlation_string()) + print() + + def _parameter_string(self): + ret_val = '' + + for pval in self.parameter.values(): + ret_val += convert(str(pval), old='tex', new='str') + '\n' + + if self.fun_kwargs: + for k, v in self.fun_kwargs.items(): + ret_val += f' {k}: {v}\n' + + return ret_val + + def _correlation_string(self): + ret_val = '' + for p_i, p_j, corr_ij, pcorr_ij in self.correlation_list(): + ret_val += ' {} / {} : {:.4f} ({:.4f})\n'.format(convert(p_i, old='tex', new='str'), + convert(p_j, old='tex', new='str'), + corr_ij, pcorr_ij) + return ret_val + + def correlation_list(self, limit=0.1): + correlations = [] + + if self.correlation is not None: + pnames = list(self.parameter.keys()) + + corr = np.triu(self.correlation, k=1) + + for i, j in zip(*np.unravel_index(np.argsort(np.abs(corr), axis=None)[::-1], + self.correlation.shape)): + if i == j: + continue + + if abs(corr[i, j]) < limit: + break + + correlations.append((pnames[i], pnames[j], self.correlation[i, j], self.partial_correlation[i, j])) + + return correlations + + def savetxt(self, fname, err=True): + header = self.name + '\n' + for pval in self.parameter.values(): + header += '{}\t{}\t{}\n'.format(convert(pval.name, old='tex', new='str'), pval.value, pval.error) + if self.fun_kwargs: + for k, v in self.fun_kwargs.items(): + header += '{}\t{}\n'.format(convert(k, old='tex', new='str'), + convert(str(v), old='tex', new='str')) + + if self.iscomplex == 'complex': + np.savetxt(fname, np.c_[self.x, self.y.real, self.y.imag], header=header) + else: + np.savetxt(fname, np.c_[self.x, self.y], header=header) + + def save_parameter(self, fname: str, label: str = None, overwrite: bool = False): + path = pathlib.Path(fname) + if not path.is_file(): + overwrite = True + + writemode = 'w' if overwrite else 'a' + + if label is None: + label = self.value + + with path.open(writemode) as f: + if overwrite or not path.exists(): + f.write('# label(1)\t') + for i, pname in enumerate(self.parameter.keys()): + raw_name = convert(pname, old='tex', new='str') + f.write(f'{raw_name}({2*i+2})\t{raw_name}_err({2*i+3})\t') + f.write('\n') + + f.write(str(label).replace(' ', '') + '\t') + for p in self.parameter.values(): + if p.error is not None: + err = p.error + else: + err = 0. + f.write(f'{p.value:.8e}\t{err:.8e}\t') + + if self.fun_kwargs: + f.write('# ') + for k, v in self.fun_kwargs.items(): + f.write(f"{convert(k, old='tex', new='str')}: {convert(str(v), old='tex', new='str')}\t") + f.write('\n') + + def f_test(self, chi2: float, dof: float): + if 'red. chi^2' not in self.statistics or dof == self.dof: + f_value = 1e318 + else: + f_value = (chi2-self.statistics['chi^2']) / (dof-self.dof) / self.statistics['red. chi^2'] + return f_value, 1-fdist.cdf(f_value, dof-self.dof, self.dof) + + def get_state(self): + state = super().get_state() + + for attr in ['idx', 'fun_kwargs', 'nobs', 'nvar', + 'islog', 'iscomplex', 'x_data', 'y_data']: + state[attr] = getattr(self, attr) + + state['name'] = self._model_name + state['corr'] = self.correlation + state['pcorr'] = self.partial_correlation + state['stats'] = self.statistics + state['resid'] = self.residual + state['params'] = {k: v.get_state() for k, v in self.parameter.items()} + + state['mode'] = 'fit' + + return state + + @staticmethod + def set_state(state, **kwargs): + state['params'] = {k: Parameter.set_state(v) for k, v in state.pop('params').items()} + data = FitResult(**state) + + return data diff --git a/nmreval/gui_qt/Qt.py b/nmreval/gui_qt/Qt.py new file mode 100644 index 0000000..1a85709 --- /dev/null +++ b/nmreval/gui_qt/Qt.py @@ -0,0 +1,12 @@ + +from PyQt5 import QtCore, QtGui, QtWidgets, QtPrintSupport + +# from PySide2 import QtCore, QtGui, QtWidgets +# QtCore.pyqtSignal = QtCore.Signal +# QtCore.pyqtProperty = QtCore.Property +# QtCore.pyqtSlot = QtCore.Slot + +# import pyqtgraph as pg +# +# pg.setConfigOption('background', 'w') +# pg.setConfigOption('foreground', 'k') diff --git a/nmreval/gui_qt/__init__.py b/nmreval/gui_qt/__init__.py new file mode 100644 index 0000000..cd017b5 --- /dev/null +++ b/nmreval/gui_qt/__init__.py @@ -0,0 +1,17 @@ +from .Qt import QtWidgets +from .lib.styles import MyProxyStyle +from ..configs import read_configuration + + +class App(QtWidgets.QApplication): + color = 'light' + theme = 'normal' + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + configs = read_configuration() + App.theme = configs.get('GUI', 'Theme') + App.color = configs.get('GUI', 'Color') + + self.setStyle(MyProxyStyle(App.color)) diff --git a/nmreval/gui_qt/_py/__init__.py b/nmreval/gui_qt/_py/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nmreval/gui_qt/_py/agroptiondialog.py b/nmreval/gui_qt/_py/agroptiondialog.py new file mode 100644 index 0000000..7adeaf4 --- /dev/null +++ b/nmreval/gui_qt/_py/agroptiondialog.py @@ -0,0 +1,323 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file '_ui/agroptiondialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(513, 466) + self.verticalLayout = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout.setObjectName("verticalLayout") + self.tabWidget = QtWidgets.QTabWidget(Dialog) + self.tabWidget.setTabShape(QtWidgets.QTabWidget.Rounded) + self.tabWidget.setObjectName("tabWidget") + self.tabWidgetPage1 = QtWidgets.QWidget() + self.tabWidgetPage1.setObjectName("tabWidgetPage1") + self.gridLayout_2 = QtWidgets.QGridLayout(self.tabWidgetPage1) + self.gridLayout_2.setObjectName("gridLayout_2") + self.frame_2 = QtWidgets.QFrame(self.tabWidgetPage1) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth()) + self.frame_2.setSizePolicy(sizePolicy) + self.frame_2.setFrameShape(QtWidgets.QFrame.Panel) + self.frame_2.setFrameShadow(QtWidgets.QFrame.Plain) + self.frame_2.setLineWidth(3) + self.frame_2.setMidLineWidth(5) + self.frame_2.setObjectName("frame_2") + self.gridLayout_4 = QtWidgets.QGridLayout(self.frame_2) + self.gridLayout_4.setSpacing(3) + self.gridLayout_4.setObjectName("gridLayout_4") + self.bottomMarginDoubleSpinBox = QtWidgets.QDoubleSpinBox(self.frame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.bottomMarginDoubleSpinBox.sizePolicy().hasHeightForWidth()) + self.bottomMarginDoubleSpinBox.setSizePolicy(sizePolicy) + self.bottomMarginDoubleSpinBox.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.bottomMarginDoubleSpinBox.setObjectName("bottomMarginDoubleSpinBox") + self.gridLayout_4.addWidget(self.bottomMarginDoubleSpinBox, 5, 2, 1, 1) + self.bottomMarginLabel = QtWidgets.QLabel(self.frame_2) + self.bottomMarginLabel.setObjectName("bottomMarginLabel") + self.gridLayout_4.addWidget(self.bottomMarginLabel, 5, 1, 1, 1) + self.rightMarginLabel = QtWidgets.QLabel(self.frame_2) + self.rightMarginLabel.setAlignment(QtCore.Qt.AlignCenter) + self.rightMarginLabel.setObjectName("rightMarginLabel") + self.gridLayout_4.addWidget(self.rightMarginLabel, 2, 3, 1, 1) + self.rightMarginDoubleSpinBox = QtWidgets.QDoubleSpinBox(self.frame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.rightMarginDoubleSpinBox.sizePolicy().hasHeightForWidth()) + self.rightMarginDoubleSpinBox.setSizePolicy(sizePolicy) + self.rightMarginDoubleSpinBox.setObjectName("rightMarginDoubleSpinBox") + self.gridLayout_4.addWidget(self.rightMarginDoubleSpinBox, 3, 3, 1, 1) + self.leftMarginDoubleSpinBox = QtWidgets.QDoubleSpinBox(self.frame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.leftMarginDoubleSpinBox.sizePolicy().hasHeightForWidth()) + self.leftMarginDoubleSpinBox.setSizePolicy(sizePolicy) + self.leftMarginDoubleSpinBox.setObjectName("leftMarginDoubleSpinBox") + self.gridLayout_4.addWidget(self.leftMarginDoubleSpinBox, 3, 0, 1, 1) + self.leftMarginLabel = QtWidgets.QLabel(self.frame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.leftMarginLabel.sizePolicy().hasHeightForWidth()) + self.leftMarginLabel.setSizePolicy(sizePolicy) + self.leftMarginLabel.setAlignment(QtCore.Qt.AlignCenter) + self.leftMarginLabel.setObjectName("leftMarginLabel") + self.gridLayout_4.addWidget(self.leftMarginLabel, 2, 0, 1, 1) + self.topMarginLabel = QtWidgets.QLabel(self.frame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.topMarginLabel.sizePolicy().hasHeightForWidth()) + self.topMarginLabel.setSizePolicy(sizePolicy) + self.topMarginLabel.setObjectName("topMarginLabel") + self.gridLayout_4.addWidget(self.topMarginLabel, 0, 1, 1, 1) + self.topMarginDoubleSpinBox = QtWidgets.QDoubleSpinBox(self.frame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.topMarginDoubleSpinBox.sizePolicy().hasHeightForWidth()) + self.topMarginDoubleSpinBox.setSizePolicy(sizePolicy) + self.topMarginDoubleSpinBox.setObjectName("topMarginDoubleSpinBox") + self.gridLayout_4.addWidget(self.topMarginDoubleSpinBox, 0, 2, 1, 1) + self.frame = QtWidgets.QFrame(self.frame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame.sizePolicy().hasHeightForWidth()) + self.frame.setSizePolicy(sizePolicy) + self.frame.setFrameShape(QtWidgets.QFrame.WinPanel) + self.frame.setMidLineWidth(0) + self.frame.setObjectName("frame") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame) + self.verticalLayout_2.setSpacing(0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.gridLayout_4.addWidget(self.frame, 1, 1, 4, 2) + self.gridLayout_2.addWidget(self.frame_2, 1, 0, 2, 2) + self.verticalLayout_3 = QtWidgets.QVBoxLayout() + self.verticalLayout_3.setObjectName("verticalLayout_3") + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_3.addItem(spacerItem) + self.heightLabel = QtWidgets.QLabel(self.tabWidgetPage1) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.heightLabel.sizePolicy().hasHeightForWidth()) + self.heightLabel.setSizePolicy(sizePolicy) + self.heightLabel.setObjectName("heightLabel") + self.verticalLayout_3.addWidget(self.heightLabel) + self.heightDoubleSpinBox = QtWidgets.QDoubleSpinBox(self.tabWidgetPage1) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.heightDoubleSpinBox.sizePolicy().hasHeightForWidth()) + self.heightDoubleSpinBox.setSizePolicy(sizePolicy) + self.heightDoubleSpinBox.setObjectName("heightDoubleSpinBox") + self.verticalLayout_3.addWidget(self.heightDoubleSpinBox) + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_3.addItem(spacerItem1) + self.gridLayout_2.addLayout(self.verticalLayout_3, 1, 2, 2, 1) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem2) + self.widthLabel = QtWidgets.QLabel(self.tabWidgetPage1) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widthLabel.sizePolicy().hasHeightForWidth()) + self.widthLabel.setSizePolicy(sizePolicy) + self.widthLabel.setObjectName("widthLabel") + self.horizontalLayout.addWidget(self.widthLabel) + self.widthDoubleSpinBox = QtWidgets.QDoubleSpinBox(self.tabWidgetPage1) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widthDoubleSpinBox.sizePolicy().hasHeightForWidth()) + self.widthDoubleSpinBox.setSizePolicy(sizePolicy) + self.widthDoubleSpinBox.setObjectName("widthDoubleSpinBox") + self.horizontalLayout.addWidget(self.widthDoubleSpinBox) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem3) + self.gridLayout_2.addLayout(self.horizontalLayout, 0, 0, 1, 2) + self.tabWidget.addTab(self.tabWidgetPage1, "") + self.tab = QtWidgets.QWidget() + self.tab.setObjectName("tab") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.tab) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.label_11 = QtWidgets.QLabel(self.tab) + self.label_11.setObjectName("label_11") + self.verticalLayout_4.addWidget(self.label_11) + self.spinBox_2 = QtWidgets.QSpinBox(self.tab) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spinBox_2.sizePolicy().hasHeightForWidth()) + self.spinBox_2.setSizePolicy(sizePolicy) + self.spinBox_2.setMaximum(1000) + self.spinBox_2.setProperty("value", 100) + self.spinBox_2.setObjectName("spinBox_2") + self.verticalLayout_4.addWidget(self.spinBox_2) + self.legendLabel = QtWidgets.QLabel(self.tab) + self.legendLabel.setObjectName("legendLabel") + self.verticalLayout_4.addWidget(self.legendLabel) + self.spinBox = QtWidgets.QSpinBox(self.tab) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spinBox.sizePolicy().hasHeightForWidth()) + self.spinBox.setSizePolicy(sizePolicy) + self.spinBox.setMaximum(1000) + self.spinBox.setProperty("value", 100) + self.spinBox.setObjectName("spinBox") + self.verticalLayout_4.addWidget(self.spinBox) + self.groupBox_4 = QtWidgets.QGroupBox(self.tab) + self.groupBox_4.setObjectName("groupBox_4") + self.formLayout_2 = QtWidgets.QFormLayout(self.groupBox_4) + self.formLayout_2.setObjectName("formLayout_2") + self.verticalAxisTickLabel = QtWidgets.QLabel(self.groupBox_4) + self.verticalAxisTickLabel.setObjectName("verticalAxisTickLabel") + self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.verticalAxisTickLabel) + self.spinBox_5 = QtWidgets.QSpinBox(self.groupBox_4) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spinBox_5.sizePolicy().hasHeightForWidth()) + self.spinBox_5.setSizePolicy(sizePolicy) + self.spinBox_5.setMaximum(1000) + self.spinBox_5.setProperty("value", 100) + self.spinBox_5.setObjectName("spinBox_5") + self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.spinBox_5) + self.verticalAxisLabelSpinBox = QtWidgets.QSpinBox(self.groupBox_4) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.verticalAxisLabelSpinBox.sizePolicy().hasHeightForWidth()) + self.verticalAxisLabelSpinBox.setSizePolicy(sizePolicy) + self.verticalAxisLabelSpinBox.setMaximum(1000) + self.verticalAxisLabelSpinBox.setProperty("value", 100) + self.verticalAxisLabelSpinBox.setObjectName("verticalAxisLabelSpinBox") + self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.verticalAxisLabelSpinBox) + self.verticalAxisLabelLabel = QtWidgets.QLabel(self.groupBox_4) + self.verticalAxisLabelLabel.setObjectName("verticalAxisLabelLabel") + self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.verticalAxisLabelLabel) + self.verticalLayout_4.addWidget(self.groupBox_4) + self.groupBox_3 = QtWidgets.QGroupBox(self.tab) + self.groupBox_3.setObjectName("groupBox_3") + self.formLayout = QtWidgets.QFormLayout(self.groupBox_3) + self.formLayout.setObjectName("formLayout") + self.spinBox_4 = QtWidgets.QSpinBox(self.groupBox_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spinBox_4.sizePolicy().hasHeightForWidth()) + self.spinBox_4.setSizePolicy(sizePolicy) + self.spinBox_4.setMaximum(1000) + self.spinBox_4.setProperty("value", 100) + self.spinBox_4.setObjectName("spinBox_4") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.spinBox_4) + self.spinBox_3 = QtWidgets.QSpinBox(self.groupBox_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spinBox_3.sizePolicy().hasHeightForWidth()) + self.spinBox_3.setSizePolicy(sizePolicy) + self.spinBox_3.setMaximum(1000) + self.spinBox_3.setProperty("value", 100) + self.spinBox_3.setObjectName("spinBox_3") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.spinBox_3) + self.label_10 = QtWidgets.QLabel(self.groupBox_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_10.sizePolicy().hasHeightForWidth()) + self.label_10.setSizePolicy(sizePolicy) + self.label_10.setObjectName("label_10") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_10) + self.label_12 = QtWidgets.QLabel(self.groupBox_3) + self.label_12.setObjectName("label_12") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_12) + self.verticalLayout_4.addWidget(self.groupBox_3) + spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_4.addItem(spacerItem4) + self.tabWidget.addTab(self.tab, "") + self.tab_2 = QtWidgets.QWidget() + self.tab_2.setObjectName("tab_2") + self.gridLayout_3 = QtWidgets.QGridLayout(self.tab_2) + self.gridLayout_3.setObjectName("gridLayout_3") + self.spinBox_6 = QtWidgets.QSpinBox(self.tab_2) + self.spinBox_6.setMaximum(1000) + self.spinBox_6.setProperty("value", 100) + self.spinBox_6.setObjectName("spinBox_6") + self.gridLayout_3.addWidget(self.spinBox_6, 0, 1, 1, 1) + self.label_3 = QtWidgets.QLabel(self.tab_2) + self.label_3.setObjectName("label_3") + self.gridLayout_3.addWidget(self.label_3, 0, 0, 1, 1) + spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_3.addItem(spacerItem5, 2, 1, 1, 1) + self.doubleSpinBox_7 = QtWidgets.QDoubleSpinBox(self.tab_2) + self.doubleSpinBox_7.setDecimals(1) + self.doubleSpinBox_7.setMaximum(20.0) + self.doubleSpinBox_7.setSingleStep(0.5) + self.doubleSpinBox_7.setProperty("value", 1.0) + self.doubleSpinBox_7.setObjectName("doubleSpinBox_7") + self.gridLayout_3.addWidget(self.doubleSpinBox_7, 1, 1, 1, 1) + self.label_4 = QtWidgets.QLabel(self.tab_2) + self.label_4.setObjectName("label_4") + self.gridLayout_3.addWidget(self.label_4, 1, 0, 1, 1) + self.tabWidget.addTab(self.tab_2, "") + self.verticalLayout.addWidget(self.tabWidget) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + + self.retranslateUi(Dialog) + self.tabWidget.setCurrentIndex(0) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Grace settings")) + self.bottomMarginDoubleSpinBox.setSuffix(_translate("Dialog", " cm")) + self.bottomMarginLabel.setText(_translate("Dialog", "Bottom margin")) + self.rightMarginLabel.setText(_translate("Dialog", "Right margin")) + self.rightMarginDoubleSpinBox.setSuffix(_translate("Dialog", " cm")) + self.leftMarginDoubleSpinBox.setSuffix(_translate("Dialog", " cm")) + self.leftMarginLabel.setText(_translate("Dialog", "Left margin")) + self.topMarginLabel.setText(_translate("Dialog", "Top margin")) + self.topMarginDoubleSpinBox.setSuffix(_translate("Dialog", " cm")) + self.heightLabel.setText(_translate("Dialog", "Paper height")) + self.heightDoubleSpinBox.setSuffix(_translate("Dialog", " cm")) + self.widthLabel.setText(_translate("Dialog", "Paper width")) + self.widthDoubleSpinBox.setSuffix(_translate("Dialog", " cm")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabWidgetPage1), _translate("Dialog", "Dimensions")) + self.label_11.setText(_translate("Dialog", "Title")) + self.legendLabel.setText(_translate("Dialog", "Legend")) + self.groupBox_4.setTitle(_translate("Dialog", "Vertical axis")) + self.verticalAxisTickLabel.setText(_translate("Dialog", "tick")) + self.verticalAxisLabelLabel.setText(_translate("Dialog", "label")) + self.groupBox_3.setTitle(_translate("Dialog", "Horizontal axis")) + self.label_10.setText(_translate("Dialog", "tick")) + self.label_12.setText(_translate("Dialog", "label")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("Dialog", "Fonts")) + self.label_3.setText(_translate("Dialog", "Default symbol size")) + self.label_4.setText(_translate("Dialog", "Default line size")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("Dialog", "Symbol/Line")) diff --git a/nmreval/gui_qt/_py/apod_dialog.py b/nmreval/gui_qt/_py/apod_dialog.py new file mode 100644 index 0000000..3c985d9 --- /dev/null +++ b/nmreval/gui_qt/_py/apod_dialog.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file '_ui/apod_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_ApodEdit(object): + def setupUi(self, ApodEdit): + ApodEdit.setObjectName("ApodEdit") + ApodEdit.resize(784, 484) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(ApodEdit.sizePolicy().hasHeightForWidth()) + ApodEdit.setSizePolicy(sizePolicy) + self.gridLayout = QtWidgets.QGridLayout(ApodEdit) + self.gridLayout.setContentsMargins(3, 3, 3, 3) + self.gridLayout.setSpacing(3) + self.gridLayout.setObjectName("gridLayout") + self.graphicsView = PlotWidget(ApodEdit) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.graphicsView.sizePolicy().hasHeightForWidth()) + self.graphicsView.setSizePolicy(sizePolicy) + self.graphicsView.setObjectName("graphicsView") + self.gridLayout.addWidget(self.graphicsView, 2, 0, 1, 1) + self.graphicsView_2 = PlotWidget(ApodEdit) + self.graphicsView_2.setObjectName("graphicsView_2") + self.gridLayout.addWidget(self.graphicsView_2, 2, 1, 1, 1) + self.apodcombobox = QtWidgets.QComboBox(ApodEdit) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.apodcombobox.sizePolicy().hasHeightForWidth()) + self.apodcombobox.setSizePolicy(sizePolicy) + self.apodcombobox.setObjectName("apodcombobox") + self.gridLayout.addWidget(self.apodcombobox, 0, 0, 1, 1) + self.widget_layout = QtWidgets.QHBoxLayout() + self.widget_layout.setContentsMargins(-1, 6, -1, -1) + self.widget_layout.setSpacing(20) + self.widget_layout.setObjectName("widget_layout") + self.gridLayout.addLayout(self.widget_layout, 1, 0, 1, 2) + self.buttonBox = QtWidgets.QDialogButtonBox(ApodEdit) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 4, 0, 1, 2) + self.eqn_label = QtWidgets.QLabel(ApodEdit) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.eqn_label.sizePolicy().hasHeightForWidth()) + self.eqn_label.setSizePolicy(sizePolicy) + self.eqn_label.setIndent(3) + self.eqn_label.setObjectName("eqn_label") + self.gridLayout.addWidget(self.eqn_label, 0, 1, 1, 1) + + self.retranslateUi(ApodEdit) + self.buttonBox.accepted.connect(ApodEdit.accept) + self.buttonBox.rejected.connect(ApodEdit.close) + QtCore.QMetaObject.connectSlotsByName(ApodEdit) + + def retranslateUi(self, ApodEdit): + _translate = QtCore.QCoreApplication.translate + ApodEdit.setWindowTitle(_translate("ApodEdit", "Apodization")) + self.eqn_label.setText(_translate("ApodEdit", "TextLabel")) +from pyqtgraph import PlotWidget diff --git a/nmreval/gui_qt/_py/asciidialog.py b/nmreval/gui_qt/_py/asciidialog.py new file mode 100644 index 0000000..523ad06 --- /dev/null +++ b/nmreval/gui_qt/_py/asciidialog.py @@ -0,0 +1,203 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file '_ui/asciidialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_ascii_reader(object): + def setupUi(self, ascii_reader): + ascii_reader.setObjectName("ascii_reader") + ascii_reader.resize(667, 509) + self.verticalLayout = QtWidgets.QVBoxLayout(ascii_reader) + self.verticalLayout.setObjectName("verticalLayout") + self.tabWidget = QtWidgets.QTabWidget(ascii_reader) + self.tabWidget.setObjectName("tabWidget") + self.tabWidgetPage1 = QtWidgets.QWidget() + self.tabWidgetPage1.setObjectName("tabWidgetPage1") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.tabWidgetPage1) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.plainTextEdit_2 = QtWidgets.QPlainTextEdit(self.tabWidgetPage1) + self.plainTextEdit_2.setEnabled(False) + self.plainTextEdit_2.setMaximumSize(QtCore.QSize(16777215, 180)) + self.plainTextEdit_2.setObjectName("plainTextEdit_2") + self.verticalLayout_3.addWidget(self.plainTextEdit_2) + self.ascii_table = QtWidgets.QTableWidget(self.tabWidgetPage1) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.ascii_table.sizePolicy().hasHeightForWidth()) + self.ascii_table.setSizePolicy(sizePolicy) + self.ascii_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) + self.ascii_table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.ascii_table.setAlternatingRowColors(True) + self.ascii_table.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.ascii_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectColumns) + self.ascii_table.setObjectName("ascii_table") + self.ascii_table.setColumnCount(0) + self.ascii_table.setRowCount(0) + self.ascii_table.horizontalHeader().setMinimumSectionSize(1) + self.verticalLayout_3.addWidget(self.ascii_table) + self.tabWidget.addTab(self.tabWidgetPage1, "") + self.tabWidgetPage2 = QtWidgets.QWidget() + self.tabWidgetPage2.setObjectName("tabWidgetPage2") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.tabWidgetPage2) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.plainTextEdit = QtWidgets.QPlainTextEdit(self.tabWidgetPage2) + self.plainTextEdit.setObjectName("plainTextEdit") + self.horizontalLayout_3.addWidget(self.plainTextEdit) + self.formLayout = QtWidgets.QFormLayout() + self.formLayout.setFieldGrowthPolicy(QtWidgets.QFormLayout.ExpandingFieldsGrow) + self.formLayout.setContentsMargins(0, -1, -1, -1) + self.formLayout.setObjectName("formLayout") + self.label_2 = QtWidgets.QLabel(self.tabWidgetPage2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth()) + self.label_2.setSizePolicy(sizePolicy) + self.label_2.setObjectName("label_2") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_2) + self.delay_lineedit = QtWidgets.QLineEdit(self.tabWidgetPage2) + self.delay_lineedit.setObjectName("delay_lineedit") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.delay_lineedit) + self.label_3 = QtWidgets.QLabel(self.tabWidgetPage2) + self.label_3.setObjectName("label_3") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_3) + self.start_lineedit = QtWidgets.QLineEdit(self.tabWidgetPage2) + self.start_lineedit.setObjectName("start_lineedit") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.start_lineedit) + self.label_4 = QtWidgets.QLabel(self.tabWidgetPage2) + self.label_4.setObjectName("label_4") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_4) + self.end_lineedit = QtWidgets.QLineEdit(self.tabWidgetPage2) + self.end_lineedit.setObjectName("end_lineedit") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.end_lineedit) + self.checkBox = QtWidgets.QCheckBox(self.tabWidgetPage2) + self.checkBox.setLayoutDirection(QtCore.Qt.LeftToRight) + self.checkBox.setObjectName("checkBox") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.SpanningRole, self.checkBox) + self.checkBox_2 = QtWidgets.QCheckBox(self.tabWidgetPage2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.checkBox_2.sizePolicy().hasHeightForWidth()) + self.checkBox_2.setSizePolicy(sizePolicy) + self.checkBox_2.setObjectName("checkBox_2") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.checkBox_2) + self.stag_lineEdit = QtWidgets.QLineEdit(self.tabWidgetPage2) + self.stag_lineEdit.setEnabled(True) + self.stag_lineEdit.setObjectName("stag_lineEdit") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.stag_lineEdit) + self.pushButton = QtWidgets.QPushButton(self.tabWidgetPage2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth()) + self.pushButton.setSizePolicy(sizePolicy) + icon = QtGui.QIcon.fromTheme("accessories-calculator") + self.pushButton.setIcon(icon) + self.pushButton.setObjectName("pushButton") + self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.pushButton) + self.horizontalLayout_3.addLayout(self.formLayout) + self.tabWidget.addTab(self.tabWidgetPage2, "") + self.verticalLayout.addWidget(self.tabWidget) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.x_label = QtWidgets.QLabel(ascii_reader) + self.x_label.setObjectName("x_label") + self.horizontalLayout.addWidget(self.x_label) + self.x_lineedit = QtWidgets.QLineEdit(ascii_reader) + self.x_lineedit.setInputMethodHints(QtCore.Qt.ImhFormattedNumbersOnly|QtCore.Qt.ImhPreferNumbers) + self.x_lineedit.setObjectName("x_lineedit") + self.horizontalLayout.addWidget(self.x_lineedit) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem1) + self.y_label = QtWidgets.QLabel(ascii_reader) + self.y_label.setObjectName("y_label") + self.horizontalLayout.addWidget(self.y_label) + self.y_lineedit = QtWidgets.QLineEdit(ascii_reader) + self.y_lineedit.setInputMethodHints(QtCore.Qt.ImhFormattedNumbersOnly|QtCore.Qt.ImhPreferNumbers) + self.y_lineedit.setObjectName("y_lineedit") + self.horizontalLayout.addWidget(self.y_lineedit) + self.widget = QtWidgets.QWidget(ascii_reader) + self.widget.setObjectName("widget") + self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.widget) + self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_4.setSpacing(0) + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_4.addItem(spacerItem2) + self.label_5 = QtWidgets.QLabel(self.widget) + self.label_5.setObjectName("label_5") + self.horizontalLayout_4.addWidget(self.label_5) + self.lineEdit = QtWidgets.QLineEdit(self.widget) + self.lineEdit.setObjectName("lineEdit") + self.horizontalLayout_4.addWidget(self.lineEdit) + self.horizontalLayout.addWidget(self.widget) + self.verticalLayout.addLayout(self.horizontalLayout) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.skippy_checkbox = QtWidgets.QCheckBox(ascii_reader) + self.skippy_checkbox.setObjectName("skippy_checkbox") + self.horizontalLayout_2.addWidget(self.skippy_checkbox) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem3) + self.radioButton = QtWidgets.QRadioButton(ascii_reader) + self.radioButton.setChecked(True) + self.radioButton.setAutoExclusive(True) + self.radioButton.setObjectName("radioButton") + self.buttonGroup = QtWidgets.QButtonGroup(ascii_reader) + self.buttonGroup.setObjectName("buttonGroup") + self.buttonGroup.addButton(self.radioButton) + self.horizontalLayout_2.addWidget(self.radioButton) + self.radioButton_2 = QtWidgets.QRadioButton(ascii_reader) + self.radioButton_2.setAutoExclusive(True) + self.radioButton_2.setObjectName("radioButton_2") + self.buttonGroup.addButton(self.radioButton_2) + self.horizontalLayout_2.addWidget(self.radioButton_2) + self.radioButton_3 = QtWidgets.QRadioButton(ascii_reader) + self.radioButton_3.setObjectName("radioButton_3") + self.buttonGroup.addButton(self.radioButton_3) + self.horizontalLayout_2.addWidget(self.radioButton_3) + self.verticalLayout.addLayout(self.horizontalLayout_2) + self.buttonbox = QtWidgets.QDialogButtonBox(ascii_reader) + self.buttonbox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonbox.setObjectName("buttonbox") + self.verticalLayout.addWidget(self.buttonbox) + + self.retranslateUi(ascii_reader) + self.tabWidget.setCurrentIndex(0) + self.buttonbox.rejected.connect(ascii_reader.close) + QtCore.QMetaObject.connectSlotsByName(ascii_reader) + + def retranslateUi(self, ascii_reader): + _translate = QtCore.QCoreApplication.translate + ascii_reader.setWindowTitle(_translate("ascii_reader", "Read text file")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabWidgetPage1), _translate("ascii_reader", "Data")) + self.label_2.setText(_translate("ascii_reader", "Number of delays")) + self.label_3.setText(_translate("ascii_reader", "Start value")) + self.label_4.setText(_translate("ascii_reader", "End value")) + self.checkBox.setText(_translate("ascii_reader", "Logarithmic scale")) + self.checkBox_2.setText(_translate("ascii_reader", "Staggered range")) + self.pushButton.setText(_translate("ascii_reader", "Calculate delays")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabWidgetPage2), _translate("ascii_reader", "Delays")) + self.x_label.setText(_translate("ascii_reader", "x")) + self.x_lineedit.setToolTip(_translate("ascii_reader", "

Specify which column is used as x-value.

")) + self.y_label.setText(_translate("ascii_reader", "y")) + self.y_lineedit.setToolTip(_translate("ascii_reader", "

Specify which columns are read for y-values. (\'Points\': Every number creates a new data set;\'FID\'/\'Spectrum\': Numbers at even positions are used for real parts, at odd positions for imaginary parts.)

")) + self.label_5.setText(_translate("ascii_reader", "

Δy

")) + self.skippy_checkbox.setToolTip(_translate("ascii_reader", "Use selection for next files. Deletes possible delay values.")) + self.skippy_checkbox.setText(_translate("ascii_reader", "Skip next dialogues?")) + self.radioButton.setText(_translate("ascii_reader", "Points")) + self.radioButton_2.setText(_translate("ascii_reader", "FID")) + self.radioButton_3.setText(_translate("ascii_reader", "Spectrum")) diff --git a/nmreval/gui_qt/_py/axisConfigTemplate.py b/nmreval/gui_qt/_py/axisConfigTemplate.py new file mode 100644 index 0000000..04e360e --- /dev/null +++ b/nmreval/gui_qt/_py/axisConfigTemplate.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file '_ui/axisConfigTemplate.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(186, 154) + Form.setMaximumSize(QtCore.QSize(200, 16777215)) + self.gridLayout = QtWidgets.QGridLayout(Form) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setSpacing(0) + self.gridLayout.setObjectName("gridLayout") + self.label = QtWidgets.QLabel(Form) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 7, 0, 1, 2) + self.linkCombo = QtWidgets.QComboBox(Form) + self.linkCombo.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) + self.linkCombo.setObjectName("linkCombo") + self.gridLayout.addWidget(self.linkCombo, 7, 2, 1, 2) + self.autoPercentSpin = QtWidgets.QSpinBox(Form) + self.autoPercentSpin.setEnabled(True) + self.autoPercentSpin.setMinimum(1) + self.autoPercentSpin.setMaximum(100) + self.autoPercentSpin.setSingleStep(1) + self.autoPercentSpin.setProperty("value", 100) + self.autoPercentSpin.setObjectName("autoPercentSpin") + self.gridLayout.addWidget(self.autoPercentSpin, 2, 2, 1, 2) + self.autoRadio = QtWidgets.QRadioButton(Form) + self.autoRadio.setChecked(True) + self.autoRadio.setObjectName("autoRadio") + self.gridLayout.addWidget(self.autoRadio, 2, 0, 1, 2) + self.manualRadio = QtWidgets.QRadioButton(Form) + self.manualRadio.setObjectName("manualRadio") + self.gridLayout.addWidget(self.manualRadio, 1, 0, 1, 2) + self.minText = QtWidgets.QLineEdit(Form) + self.minText.setObjectName("minText") + self.gridLayout.addWidget(self.minText, 1, 2, 1, 1) + self.maxText = QtWidgets.QLineEdit(Form) + self.maxText.setObjectName("maxText") + self.gridLayout.addWidget(self.maxText, 1, 3, 1, 1) + self.invertCheck = QtWidgets.QCheckBox(Form) + self.invertCheck.setObjectName("invertCheck") + self.gridLayout.addWidget(self.invertCheck, 5, 0, 1, 4) + self.mouseCheck = QtWidgets.QCheckBox(Form) + self.mouseCheck.setChecked(True) + self.mouseCheck.setObjectName("mouseCheck") + self.gridLayout.addWidget(self.mouseCheck, 6, 0, 1, 4) + self.visibleOnlyCheck = QtWidgets.QCheckBox(Form) + self.visibleOnlyCheck.setObjectName("visibleOnlyCheck") + self.gridLayout.addWidget(self.visibleOnlyCheck, 3, 2, 1, 2) + self.autoPanCheck = QtWidgets.QCheckBox(Form) + self.autoPanCheck.setObjectName("autoPanCheck") + self.gridLayout.addWidget(self.autoPanCheck, 4, 2, 1, 2) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "PyQtGraph")) + self.label.setText(_translate("Form", "Link Axis:")) + self.linkCombo.setToolTip(_translate("Form", "

Links this axis with another view. When linked, both views will display the same data range.

")) + self.autoPercentSpin.setToolTip(_translate("Form", "

Percent of data to be visible when auto-scaling. It may be useful to decrease this value for data with spiky noise.

")) + self.autoPercentSpin.setSuffix(_translate("Form", "%")) + self.autoRadio.setToolTip(_translate("Form", "

Automatically resize this axis whenever the displayed data is changed.

")) + self.autoRadio.setText(_translate("Form", "Auto")) + self.manualRadio.setToolTip(_translate("Form", "

Set the range for this axis manually. This disables automatic scaling.

")) + self.manualRadio.setText(_translate("Form", "Manual")) + self.minText.setToolTip(_translate("Form", "

Minimum value to display for this axis.

")) + self.minText.setText(_translate("Form", "0")) + self.maxText.setToolTip(_translate("Form", "

Maximum value to display for this axis.

")) + self.maxText.setText(_translate("Form", "0")) + self.invertCheck.setToolTip(_translate("Form", "

Inverts the display of this axis. (+y points downward instead of upward)

")) + self.invertCheck.setText(_translate("Form", "Invert Axis")) + self.mouseCheck.setToolTip(_translate("Form", "

Enables mouse interaction (panning, scaling) for this axis.

")) + self.mouseCheck.setText(_translate("Form", "Mouse Enabled")) + self.visibleOnlyCheck.setToolTip(_translate("Form", "

When checked, the axis will only auto-scale to data that is visible along the orthogonal axis.

")) + self.visibleOnlyCheck.setText(_translate("Form", "Visible Data Only")) + self.autoPanCheck.setToolTip(_translate("Form", "

When checked, the axis will automatically pan to center on the current data, but the scale along this axis will not change.

")) + self.autoPanCheck.setText(_translate("Form", "Auto Pan Only")) diff --git a/nmreval/gui_qt/_py/baseline_dialog.py b/nmreval/gui_qt/_py/baseline_dialog.py new file mode 100644 index 0000000..ca67fe7 --- /dev/null +++ b/nmreval/gui_qt/_py/baseline_dialog.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file '_ui/baseline_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_SignalEdit(object): + def setupUi(self, SignalEdit): + SignalEdit.setObjectName("SignalEdit") + SignalEdit.resize(919, 595) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(SignalEdit.sizePolicy().hasHeightForWidth()) + SignalEdit.setSizePolicy(sizePolicy) + self.gridLayout = QtWidgets.QGridLayout(SignalEdit) + self.gridLayout.setObjectName("gridLayout") + self.groupBox = QtWidgets.QWidget(SignalEdit) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth()) + self.groupBox.setSizePolicy(sizePolicy) + self.groupBox.setObjectName("groupBox") + self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox) + self.verticalLayout.setObjectName("verticalLayout") + self.listWidget = QtWidgets.QListWidget(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth()) + self.listWidget.setSizePolicy(sizePolicy) + self.listWidget.setObjectName("listWidget") + self.verticalLayout.addWidget(self.listWidget) + self.gridLayout.addWidget(self.groupBox, 0, 0, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(SignalEdit) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 3) + self.graphicsView = PlotWidget(SignalEdit) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.graphicsView.sizePolicy().hasHeightForWidth()) + self.graphicsView.setSizePolicy(sizePolicy) + self.graphicsView.setObjectName("graphicsView") + self.gridLayout.addWidget(self.graphicsView, 0, 2, 1, 1) + + self.retranslateUi(SignalEdit) + self.buttonBox.accepted.connect(SignalEdit.accept) + self.buttonBox.rejected.connect(SignalEdit.close) + QtCore.QMetaObject.connectSlotsByName(SignalEdit) + + def retranslateUi(self, SignalEdit): + _translate = QtCore.QCoreApplication.translate + SignalEdit.setWindowTitle(_translate("SignalEdit", "Dialog")) +from pyqtgraph import PlotWidget diff --git a/nmreval/gui_qt/_py/basewindow.py b/nmreval/gui_qt/_py/basewindow.py new file mode 100644 index 0000000..4e8a29b --- /dev/null +++ b/nmreval/gui_qt/_py/basewindow.py @@ -0,0 +1,606 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/basewindow.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_BaseWindow(object): + def setupUi(self, BaseWindow): + BaseWindow.setObjectName("BaseWindow") + BaseWindow.resize(1388, 735) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/logo.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + BaseWindow.setWindowIcon(icon) + BaseWindow.setDockOptions(QtWidgets.QMainWindow.AllowTabbedDocks|QtWidgets.QMainWindow.AnimatedDocks|QtWidgets.QMainWindow.ForceTabbedDocks|QtWidgets.QMainWindow.VerticalTabs) + self.centralwidget = QtWidgets.QWidget(BaseWindow) + self.centralwidget.setObjectName("centralwidget") + self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) + self.verticalLayout.setContentsMargins(3, 3, 3, 3) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.splitter = QtWidgets.QSplitter(self.centralwidget) + self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setObjectName("splitter") + self.tabWidget = QtWidgets.QTabWidget(self.splitter) + self.tabWidget.setTabPosition(QtWidgets.QTabWidget.West) + self.tabWidget.setTabShape(QtWidgets.QTabWidget.Rounded) + self.tabWidget.setElideMode(QtCore.Qt.ElideRight) + self.tabWidget.setTabsClosable(True) + self.tabWidget.setMovable(False) + self.tabWidget.setTabBarAutoHide(True) + self.tabWidget.setObjectName("tabWidget") + self.datawidget = DataWidget() + self.datawidget.setObjectName("datawidget") + self.tabWidget.addTab(self.datawidget, "") + self.valuewidget = ValueEditWidget() + self.valuewidget.setObjectName("valuewidget") + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/value_dock"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.valuewidget, icon1, "") + self.fit_dialog = QFitDialog() + self.fit_dialog.setObjectName("fit_dialog") + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap(":/fit_dock"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.fit_dialog, icon2, "") + self.editsignalwidget = EditSignalWidget() + self.editsignalwidget.setObjectName("editsignalwidget") + icon3 = QtGui.QIcon() + icon3.addPixmap(QtGui.QPixmap(":/signal_dock"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.editsignalwidget, icon3, "") + self.ptsselectwidget = PointSelectWidget() + self.ptsselectwidget.setObjectName("ptsselectwidget") + icon4 = QtGui.QIcon() + icon4.addPixmap(QtGui.QPixmap(":/peakpick_dock"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.ptsselectwidget, icon4, "") + self.t1tauwidget = QT1Widget() + self.t1tauwidget.setObjectName("t1tauwidget") + icon5 = QtGui.QIcon() + icon5.addPixmap(QtGui.QPixmap(":/eval_t1_dock"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.t1tauwidget, icon5, "") + self.area = QtWidgets.QMdiArea(self.splitter) + self.area.setObjectName("area") + self.verticalLayout.addWidget(self.splitter) + BaseWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(BaseWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1388, 30)) + self.menubar.setObjectName("menubar") + self.menuFile = QtWidgets.QMenu(self.menubar) + self.menuFile.setObjectName("menuFile") + self.menuSave = QtWidgets.QMenu(self.menuFile) + icon6 = QtGui.QIcon() + icon6.addPixmap(QtGui.QPixmap(":/Daleks.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.menuSave.setIcon(icon6) + self.menuSave.setSeparatorsCollapsible(True) + self.menuSave.setObjectName("menuSave") + self.menuData = QtWidgets.QMenu(self.menubar) + self.menuData.setObjectName("menuData") + self.menuHelp = QtWidgets.QMenu(self.menubar) + self.menuHelp.setObjectName("menuHelp") + self.menuExtra = QtWidgets.QMenu(self.menubar) + self.menuExtra.setObjectName("menuExtra") + self.menuNormalize = QtWidgets.QMenu(self.menuExtra) + icon7 = QtGui.QIcon() + icon7.addPixmap(QtGui.QPixmap(":/normal.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.menuNormalize.setIcon(icon7) + self.menuNormalize.setObjectName("menuNormalize") + self.menuFit = QtWidgets.QMenu(self.menubar) + self.menuFit.setObjectName("menuFit") + self.menuMethod = QtWidgets.QMenu(self.menuFit) + self.menuMethod.setObjectName("menuMethod") + self.menuLimits = QtWidgets.QMenu(self.menuFit) + self.menuLimits.setObjectName("menuLimits") + self.menuOptions = QtWidgets.QMenu(self.menubar) + self.menuOptions.setObjectName("menuOptions") + self.menuWindow = QtWidgets.QMenu(self.menubar) + self.menuWindow.setObjectName("menuWindow") + self.menuView = QtWidgets.QMenu(self.menuWindow) + self.menuView.setObjectName("menuView") + self.menuNMR = QtWidgets.QMenu(self.menubar) + self.menuNMR.setObjectName("menuNMR") + self.menuBDS = QtWidgets.QMenu(self.menubar) + self.menuBDS.setObjectName("menuBDS") + self.menuSpectrum = QtWidgets.QMenu(self.menubar) + self.menuSpectrum.setObjectName("menuSpectrum") + self.menuStuff = QtWidgets.QMenu(self.menubar) + self.menuStuff.setTitle("") + self.menuStuff.setObjectName("menuStuff") + BaseWindow.setMenuBar(self.menubar) + self.toolBar = QtWidgets.QToolBar(BaseWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.toolBar.sizePolicy().hasHeightForWidth()) + self.toolBar.setSizePolicy(sizePolicy) + self.toolBar.setAllowedAreas(QtCore.Qt.AllToolBarAreas) + self.toolBar.setIconSize(QtCore.QSize(24, 24)) + self.toolBar.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly) + self.toolBar.setObjectName("toolBar") + BaseWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) + self.toolbar_edit = QtWidgets.QToolBar(BaseWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.toolbar_edit.sizePolicy().hasHeightForWidth()) + self.toolbar_edit.setSizePolicy(sizePolicy) + self.toolbar_edit.setIconSize(QtCore.QSize(24, 24)) + self.toolbar_edit.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly) + self.toolbar_edit.setObjectName("toolbar_edit") + BaseWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolbar_edit) + self.statusBar = QtWidgets.QStatusBar(BaseWindow) + self.statusBar.setObjectName("statusBar") + BaseWindow.setStatusBar(self.statusBar) + self.toolBar_nmr = QtWidgets.QToolBar(BaseWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.toolBar_nmr.sizePolicy().hasHeightForWidth()) + self.toolBar_nmr.setSizePolicy(sizePolicy) + self.toolBar_nmr.setIconSize(QtCore.QSize(24, 24)) + self.toolBar_nmr.setObjectName("toolBar_nmr") + BaseWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar_nmr) + self.toolBar_fit = QtWidgets.QToolBar(BaseWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.toolBar_fit.sizePolicy().hasHeightForWidth()) + self.toolBar_fit.setSizePolicy(sizePolicy) + self.toolBar_fit.setIconSize(QtCore.QSize(24, 24)) + self.toolBar_fit.setObjectName("toolBar_fit") + BaseWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar_fit) + self.toolBar_spectrum = QtWidgets.QToolBar(BaseWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.toolBar_spectrum.sizePolicy().hasHeightForWidth()) + self.toolBar_spectrum.setSizePolicy(sizePolicy) + self.toolBar_spectrum.setIconSize(QtCore.QSize(24, 24)) + self.toolBar_spectrum.setObjectName("toolBar_spectrum") + BaseWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar_spectrum) + self.toolBar_data = QtWidgets.QToolBar(BaseWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.toolBar_data.sizePolicy().hasHeightForWidth()) + self.toolBar_data.setSizePolicy(sizePolicy) + self.toolBar_data.setIconSize(QtCore.QSize(24, 24)) + self.toolBar_data.setObjectName("toolBar_data") + BaseWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar_data) + self.action_close = QtWidgets.QAction(BaseWindow) + icon = QtGui.QIcon.fromTheme("window-close") + self.action_close.setIcon(icon) + self.action_close.setObjectName("action_close") + self.actionExportGraphic = QtWidgets.QAction(BaseWindow) + self.actionExportGraphic.setObjectName("actionExportGraphic") + self.action_open = QtWidgets.QAction(BaseWindow) + self.action_open.setObjectName("action_open") + self.actionExportData = QtWidgets.QAction(BaseWindow) + self.actionExportData.setObjectName("actionExportData") + self.action_calc = QtWidgets.QAction(BaseWindow) + self.action_calc.setObjectName("action_calc") + self.action_delete_sets = QtWidgets.QAction(BaseWindow) + icon = QtGui.QIcon.fromTheme("edit-delete") + self.action_delete_sets.setIcon(icon) + self.action_delete_sets.setObjectName("action_delete_sets") + self.action_save_fit_parameter = QtWidgets.QAction(BaseWindow) + self.action_save_fit_parameter.setObjectName("action_save_fit_parameter") + self.action_sort_pts = QtWidgets.QAction(BaseWindow) + self.action_sort_pts.setObjectName("action_sort_pts") + self.action_reset = QtWidgets.QAction(BaseWindow) + icon = QtGui.QIcon.fromTheme("edit-clear") + self.action_reset.setIcon(icon) + self.action_reset.setObjectName("action_reset") + self.actionDocumentation = QtWidgets.QAction(BaseWindow) + icon = QtGui.QIcon.fromTheme("help-about") + self.actionDocumentation.setIcon(icon) + self.actionDocumentation.setObjectName("actionDocumentation") + self.action_FitWidget = QtWidgets.QAction(BaseWindow) + self.action_FitWidget.setObjectName("action_FitWidget") + self.action_norm_max = QtWidgets.QAction(BaseWindow) + self.action_norm_max.setObjectName("action_norm_max") + self.action_norm_first = QtWidgets.QAction(BaseWindow) + self.action_norm_first.setObjectName("action_norm_first") + self.action_norm_area = QtWidgets.QAction(BaseWindow) + self.action_norm_area.setObjectName("action_norm_area") + self.action_norm_max_abs = QtWidgets.QAction(BaseWindow) + self.action_norm_max_abs.setObjectName("action_norm_max_abs") + self.action_norm_last = QtWidgets.QAction(BaseWindow) + self.action_norm_last.setObjectName("action_norm_last") + self.actionSave = QtWidgets.QAction(BaseWindow) + self.actionSave.setObjectName("actionSave") + self.actiontoolbar_display = QtWidgets.QAction(BaseWindow) + self.actiontoolbar_display.setCheckable(True) + self.actiontoolbar_display.setObjectName("actiontoolbar_display") + self.actionEdit_toolbars = QtWidgets.QAction(BaseWindow) + self.actionEdit_toolbars.setCheckable(True) + self.actionEdit_toolbars.setObjectName("actionEdit_toolbars") + self.actionAddlines = QtWidgets.QAction(BaseWindow) + self.actionAddlines.setObjectName("actionAddlines") + self.actionColors = QtWidgets.QAction(BaseWindow) + self.actionColors.setObjectName("actionColors") + self.actionConcatenate_sets = QtWidgets.QAction(BaseWindow) + self.actionConcatenate_sets.setObjectName("actionConcatenate_sets") + self.actionShift = QtWidgets.QAction(BaseWindow) + self.actionShift.setObjectName("actionShift") + self.actionShow_log = QtWidgets.QAction(BaseWindow) + icon = QtGui.QIcon.fromTheme("dialog-information") + self.actionShow_log.setIcon(icon) + self.actionShow_log.setObjectName("actionShow_log") + self.action_create_fit_function = QtWidgets.QAction(BaseWindow) + self.action_create_fit_function.setObjectName("action_create_fit_function") + self.actionGrace_preferences = QtWidgets.QAction(BaseWindow) + self.actionGrace_preferences.setObjectName("actionGrace_preferences") + self.actionSave_session = QtWidgets.QAction(BaseWindow) + self.actionSave_session.setObjectName("actionSave_session") + self.actionMouse_behaviour = QtWidgets.QAction(BaseWindow) + self.actionMouse_behaviour.setCheckable(True) + self.actionMouse_behaviour.setObjectName("actionMouse_behaviour") + self.actionConfiguration = QtWidgets.QAction(BaseWindow) + self.actionConfiguration.setObjectName("actionConfiguration") + self.actionRefresh = QtWidgets.QAction(BaseWindow) + icon = QtGui.QIcon.fromTheme("view-refresh") + self.actionRefresh.setIcon(icon) + self.actionRefresh.setObjectName("actionRefresh") + self.actionInterpolation = QtWidgets.QAction(BaseWindow) + self.actionInterpolation.setObjectName("actionInterpolation") + self.actionRunning_values = QtWidgets.QAction(BaseWindow) + self.actionRunning_values.setObjectName("actionRunning_values") + self.actionFit_parameter_saving = QtWidgets.QAction(BaseWindow) + self.actionFit_parameter_saving.setObjectName("actionFit_parameter_saving") + self.actionShow_fit_parameter = QtWidgets.QAction(BaseWindow) + self.actionShow_fit_parameter.setObjectName("actionShow_fit_parameter") + self.actionSkip_points = QtWidgets.QAction(BaseWindow) + self.actionSkip_points.setObjectName("actionSkip_points") + self.actionGuide_lines = QtWidgets.QAction(BaseWindow) + self.actionGuide_lines.setObjectName("actionGuide_lines") + self.actionMaximize = QtWidgets.QAction(BaseWindow) + self.actionMaximize.setCheckable(True) + self.actionMaximize.setVisible(False) + self.actionMaximize.setObjectName("actionMaximize") + self.actionTile = QtWidgets.QAction(BaseWindow) + self.actionTile.setObjectName("actionTile") + self.actionMinimize = QtWidgets.QAction(BaseWindow) + self.actionMinimize.setCheckable(True) + self.actionMinimize.setVisible(False) + self.actionMinimize.setObjectName("actionMinimize") + self.actionNew_window = QtWidgets.QAction(BaseWindow) + self.actionNew_window.setObjectName("actionNew_window") + self.actionDelete_window = QtWidgets.QAction(BaseWindow) + icon = QtGui.QIcon.fromTheme("edit-delete") + self.actionDelete_window.setIcon(icon) + self.actionDelete_window.setObjectName("actionDelete_window") + self.actionCascade_windows = QtWidgets.QAction(BaseWindow) + self.actionCascade_windows.setObjectName("actionCascade_windows") + self.actionNext_window = QtWidgets.QAction(BaseWindow) + self.actionNext_window.setObjectName("actionNext_window") + self.actionPrevious = QtWidgets.QAction(BaseWindow) + self.actionPrevious.setObjectName("actionPrevious") + self.t1action = QtWidgets.QAction(BaseWindow) + self.t1action.setObjectName("t1action") + self.t1tau = QtWidgets.QAction(BaseWindow) + self.t1tau.setObjectName("t1tau") + self.action_coup_calc = QtWidgets.QAction(BaseWindow) + self.action_coup_calc.setObjectName("action_coup_calc") + self.action_calc_eps_derivative = QtWidgets.QAction(BaseWindow) + self.action_calc_eps_derivative.setObjectName("action_calc_eps_derivative") + self.actionOpen_FC = QtWidgets.QAction(BaseWindow) + self.actionOpen_FC.setObjectName("actionOpen_FC") + self.action_mean_t1 = QtWidgets.QAction(BaseWindow) + self.action_mean_t1.setObjectName("action_mean_t1") + self.actionFilon = QtWidgets.QAction(BaseWindow) + self.actionFilon.setObjectName("actionFilon") + self.action_new_set = QtWidgets.QAction(BaseWindow) + self.action_new_set.setObjectName("action_new_set") + self.action_magnitude = QtWidgets.QAction(BaseWindow) + self.action_magnitude.setObjectName("action_magnitude") + self.actionCenterMax = QtWidgets.QAction(BaseWindow) + self.actionCenterMax.setObjectName("actionCenterMax") + self.action_depake = QtWidgets.QAction(BaseWindow) + self.action_depake.setObjectName("action_depake") + self.action_edit = QtWidgets.QAction(BaseWindow) + self.action_edit.setObjectName("action_edit") + self.actionPick_position = QtWidgets.QAction(BaseWindow) + self.actionPick_position.setObjectName("actionPick_position") + self.actionIntegrate = QtWidgets.QAction(BaseWindow) + self.actionIntegrate.setObjectName("actionIntegrate") + self.actionDerivation = QtWidgets.QAction(BaseWindow) + self.actionDerivation.setObjectName("actionDerivation") + self.actionIntegration = QtWidgets.QAction(BaseWindow) + self.actionIntegration.setObjectName("actionIntegration") + self.action_cut = QtWidgets.QAction(BaseWindow) + self.action_cut.setObjectName("action_cut") + self.actionMove_between_plots = QtWidgets.QAction(BaseWindow) + self.actionMove_between_plots.setObjectName("actionMove_between_plots") + self.actionBaseline = QtWidgets.QAction(BaseWindow) + self.actionBaseline.setObjectName("actionBaseline") + self.actionCalculateT1 = QtWidgets.QAction(BaseWindow) + self.actionCalculateT1.setObjectName("actionCalculateT1") + self.actionChange_datatypes = QtWidgets.QAction(BaseWindow) + self.actionChange_datatypes.setObjectName("actionChange_datatypes") + self.actionPrint = QtWidgets.QAction(BaseWindow) + icon = QtGui.QIcon.fromTheme("document-print") + self.actionPrint.setIcon(icon) + self.actionPrint.setObjectName("actionPrint") + self.action_lm_fit = QtWidgets.QAction(BaseWindow) + self.action_lm_fit.setCheckable(True) + self.action_lm_fit.setChecked(True) + self.action_lm_fit.setObjectName("action_lm_fit") + self.action_nm_fit = QtWidgets.QAction(BaseWindow) + self.action_nm_fit.setCheckable(True) + self.action_nm_fit.setObjectName("action_nm_fit") + self.action_odr_fit = QtWidgets.QAction(BaseWindow) + self.action_odr_fit.setCheckable(True) + self.action_odr_fit.setObjectName("action_odr_fit") + self.action_no_range = QtWidgets.QAction(BaseWindow) + self.action_no_range.setCheckable(True) + self.action_no_range.setChecked(False) + self.action_no_range.setObjectName("action_no_range") + self.action_x_range = QtWidgets.QAction(BaseWindow) + self.action_x_range.setCheckable(True) + self.action_x_range.setChecked(True) + self.action_x_range.setObjectName("action_x_range") + self.action_custom_range = QtWidgets.QAction(BaseWindow) + self.action_custom_range.setCheckable(True) + self.action_custom_range.setObjectName("action_custom_range") + self.actionSnake = QtWidgets.QAction(BaseWindow) + self.actionSnake.setObjectName("actionSnake") + self.actionFunction_editor = QtWidgets.QAction(BaseWindow) + self.actionFunction_editor.setObjectName("actionFunction_editor") + self.actionLife = QtWidgets.QAction(BaseWindow) + self.actionLife.setObjectName("actionLife") + self.actionTetris = QtWidgets.QAction(BaseWindow) + self.actionTetris.setObjectName("actionTetris") + self.actionUpdate = QtWidgets.QAction(BaseWindow) + self.actionUpdate.setObjectName("actionUpdate") + self.menuSave.addAction(self.actionSave) + self.menuSave.addAction(self.actionExportGraphic) + self.menuSave.addAction(self.action_save_fit_parameter) + self.menuFile.addAction(self.action_open) + self.menuFile.addAction(self.actionOpen_FC) + self.menuFile.addAction(self.menuSave.menuAction()) + self.menuFile.addSeparator() + self.menuFile.addAction(self.actionPrint) + self.menuFile.addAction(self.action_reset) + self.menuFile.addSeparator() + self.menuFile.addAction(self.action_close) + self.menuFile.addSeparator() + self.menuData.addAction(self.action_new_set) + self.menuData.addAction(self.action_delete_sets) + self.menuData.addAction(self.actionMove_between_plots) + self.menuData.addAction(self.actionConcatenate_sets) + self.menuData.addAction(self.actionAddlines) + self.menuData.addSeparator() + self.menuData.addAction(self.action_sort_pts) + self.menuData.addAction(self.actionSkip_points) + self.menuData.addSeparator() + self.menuData.addAction(self.action_cut) + self.menuData.addSeparator() + self.menuData.addAction(self.actionChange_datatypes) + self.menuHelp.addAction(self.actionDocumentation) + self.menuHelp.addAction(self.actionUpdate) + self.menuNormalize.addAction(self.action_norm_max) + self.menuNormalize.addAction(self.action_norm_max_abs) + self.menuNormalize.addSeparator() + self.menuNormalize.addAction(self.action_norm_first) + self.menuNormalize.addAction(self.action_norm_last) + self.menuNormalize.addSeparator() + self.menuNormalize.addAction(self.action_norm_area) + self.menuExtra.addAction(self.action_mean_t1) + self.menuExtra.addSeparator() + self.menuExtra.addAction(self.actionFilon) + self.menuExtra.addAction(self.actionDerivation) + self.menuExtra.addAction(self.actionIntegration) + self.menuExtra.addSeparator() + self.menuExtra.addAction(self.menuNormalize.menuAction()) + self.menuExtra.addAction(self.actionInterpolation) + self.menuExtra.addAction(self.actionRunning_values) + self.menuExtra.addAction(self.actionShift) + self.menuExtra.addSeparator() + self.menuExtra.addAction(self.action_calc) + self.menuMethod.addAction(self.action_lm_fit) + self.menuMethod.addAction(self.action_nm_fit) + self.menuMethod.addAction(self.action_odr_fit) + self.menuLimits.addAction(self.action_no_range) + self.menuLimits.addAction(self.action_x_range) + self.menuLimits.addAction(self.action_custom_range) + self.menuFit.addAction(self.action_FitWidget) + self.menuFit.addSeparator() + self.menuFit.addAction(self.action_create_fit_function) + self.menuFit.addAction(self.actionFunction_editor) + self.menuFit.addSeparator() + self.menuFit.addAction(self.actionShow_fit_parameter) + self.menuFit.addAction(self.menuMethod.menuAction()) + self.menuFit.addAction(self.menuLimits.menuAction()) + self.menuOptions.addAction(self.actionMouse_behaviour) + self.menuOptions.addSeparator() + self.menuOptions.addAction(self.actionGrace_preferences) + self.menuOptions.addAction(self.actionConfiguration) + self.menuView.addAction(self.actionTile) + self.menuView.addAction(self.actionCascade_windows) + self.menuWindow.addAction(self.actionNew_window) + self.menuWindow.addAction(self.actionDelete_window) + self.menuWindow.addSeparator() + self.menuWindow.addAction(self.actionNext_window) + self.menuWindow.addAction(self.actionPrevious) + self.menuWindow.addAction(self.actionMaximize) + self.menuWindow.addAction(self.actionMinimize) + self.menuWindow.addAction(self.menuView.menuAction()) + self.menuWindow.addSeparator() + self.menuWindow.addAction(self.actionRefresh) + self.menuNMR.addAction(self.t1action) + self.menuNMR.addAction(self.actionCalculateT1) + self.menuNMR.addAction(self.action_coup_calc) + self.menuBDS.addAction(self.action_calc_eps_derivative) + self.menuSpectrum.addAction(self.action_magnitude) + self.menuSpectrum.addAction(self.actionCenterMax) + self.menuSpectrum.addAction(self.action_depake) + self.menuSpectrum.addSeparator() + self.menuSpectrum.addAction(self.action_edit) + self.menuSpectrum.addAction(self.actionBaseline) + self.menuSpectrum.addAction(self.actionPick_position) + self.menuStuff.addAction(self.actionSnake) + self.menuStuff.addAction(self.actionLife) + self.menuStuff.addAction(self.actionTetris) + self.menubar.addAction(self.menuFile.menuAction()) + self.menubar.addAction(self.menuWindow.menuAction()) + self.menubar.addAction(self.menuData.menuAction()) + self.menubar.addAction(self.menuExtra.menuAction()) + self.menubar.addAction(self.menuSpectrum.menuAction()) + self.menubar.addAction(self.menuFit.menuAction()) + self.menubar.addAction(self.menuNMR.menuAction()) + self.menubar.addAction(self.menuBDS.menuAction()) + self.menubar.addAction(self.menuOptions.menuAction()) + self.menubar.addAction(self.menuHelp.menuAction()) + self.menubar.addAction(self.menuStuff.menuAction()) + self.toolBar.addAction(self.action_open) + self.toolBar.addAction(self.actionSave) + self.toolBar.addSeparator() + self.toolBar.addAction(self.actionMouse_behaviour) + self.toolbar_edit.addAction(self.action_calc) + self.toolbar_edit.addAction(self.action_mean_t1) + self.toolbar_edit.addAction(self.actionShift) + self.toolBar_nmr.addAction(self.t1action) + self.toolBar_nmr.addAction(self.actionCalculateT1) + self.toolBar_fit.addAction(self.action_FitWidget) + self.toolBar_spectrum.addAction(self.action_edit) + self.toolBar_spectrum.addAction(self.actionPick_position) + self.toolBar_data.addAction(self.actionConcatenate_sets) + self.toolBar_data.addAction(self.action_sort_pts) + + self.retranslateUi(BaseWindow) + self.tabWidget.setCurrentIndex(0) + self.action_close.triggered.connect(BaseWindow.close) + QtCore.QMetaObject.connectSlotsByName(BaseWindow) + + def retranslateUi(self, BaseWindow): + _translate = QtCore.QCoreApplication.translate + BaseWindow.setWindowTitle(_translate("BaseWindow", "Mr. Godot told me to tell you he won\'t come this evening but surely tomorrow.")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.datawidget), _translate("BaseWindow", "Data")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.valuewidget), _translate("BaseWindow", "Values")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.fit_dialog), _translate("BaseWindow", "Fit")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.editsignalwidget), _translate("BaseWindow", "Signals")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.ptsselectwidget), _translate("BaseWindow", "Pick points")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.t1tauwidget), _translate("BaseWindow", "SLR")) + self.menuFile.setTitle(_translate("BaseWindow", "&File")) + self.menuSave.setTitle(_translate("BaseWindow", "&Save...")) + self.menuData.setTitle(_translate("BaseWindow", "&Data")) + self.menuHelp.setTitle(_translate("BaseWindow", "&Help")) + self.menuExtra.setTitle(_translate("BaseWindow", "Math")) + self.menuNormalize.setTitle(_translate("BaseWindow", "&Normalize")) + self.menuFit.setTitle(_translate("BaseWindow", "F&it")) + self.menuMethod.setTitle(_translate("BaseWindow", "Method")) + self.menuLimits.setTitle(_translate("BaseWindow", "Limits")) + self.menuOptions.setTitle(_translate("BaseWindow", "Options")) + self.menuWindow.setTitle(_translate("BaseWindow", "Plots")) + self.menuView.setTitle(_translate("BaseWindow", "View")) + self.menuNMR.setTitle(_translate("BaseWindow", "NMR")) + self.menuBDS.setTitle(_translate("BaseWindow", "BDS")) + self.menuSpectrum.setTitle(_translate("BaseWindow", "Spectrum")) + self.toolBar.setWindowTitle(_translate("BaseWindow", "Main")) + self.toolbar_edit.setWindowTitle(_translate("BaseWindow", "Edit")) + self.toolBar_nmr.setWindowTitle(_translate("BaseWindow", "NMR")) + self.toolBar_fit.setWindowTitle(_translate("BaseWindow", "Fit")) + self.toolBar_spectrum.setWindowTitle(_translate("BaseWindow", "Spectrum")) + self.toolBar_data.setWindowTitle(_translate("BaseWindow", "toolBar_2")) + self.action_close.setText(_translate("BaseWindow", "&Quit")) + self.action_close.setShortcut(_translate("BaseWindow", "Ctrl+Q")) + self.actionExportGraphic.setText(_translate("BaseWindow", "Export graphic...")) + self.actionExportGraphic.setShortcut(_translate("BaseWindow", "Ctrl+Shift+S")) + self.action_open.setText(_translate("BaseWindow", "&Open...")) + self.action_open.setShortcut(_translate("BaseWindow", "Ctrl+O")) + self.actionExportData.setText(_translate("BaseWindow", "Export data...")) + self.actionExportData.setShortcut(_translate("BaseWindow", "Ctrl+Shift+S")) + self.action_calc.setText(_translate("BaseWindow", "&Evaluate expression...")) + self.action_delete_sets.setText(_translate("BaseWindow", "&Delete Set")) + self.action_delete_sets.setShortcut(_translate("BaseWindow", "Ctrl+Del")) + self.action_save_fit_parameter.setText(_translate("BaseWindow", "Save fit ¶meter...")) + self.action_sort_pts.setText(_translate("BaseWindow", "Sort &points")) + self.action_reset.setText(_translate("BaseWindow", "&Reset")) + self.action_reset.setShortcut(_translate("BaseWindow", "Ctrl+R")) + self.actionDocumentation.setText(_translate("BaseWindow", "&Documentation")) + self.actionDocumentation.setShortcut(_translate("BaseWindow", "F1")) + self.action_FitWidget.setText(_translate("BaseWindow", "Open &Fit")) + self.action_FitWidget.setShortcut(_translate("BaseWindow", "Ctrl+F")) + self.action_norm_max.setText(_translate("BaseWindow", "&Max")) + self.action_norm_first.setText(_translate("BaseWindow", "&First point")) + self.action_norm_area.setText(_translate("BaseWindow", "&Area")) + self.action_norm_max_abs.setText(_translate("BaseWindow", "Ma&x(Abs)")) + self.action_norm_last.setText(_translate("BaseWindow", "&Last point")) + self.actionSave.setText(_translate("BaseWindow", "S&ave...")) + self.actionSave.setShortcut(_translate("BaseWindow", "Ctrl+S")) + self.actiontoolbar_display.setText(_translate("BaseWindow", "&Views")) + self.actionEdit_toolbars.setText(_translate("BaseWindow", "&Edit")) + self.actionAddlines.setText(_translate("BaseWindow", "Set by function...")) + self.actionColors.setText(_translate("BaseWindow", "&Reset color")) + self.actionConcatenate_sets.setText(_translate("BaseWindow", "Join sets")) + self.actionShift.setText(_translate("BaseWindow", "&Shift/scale...")) + self.actionShow_log.setText(_translate("BaseWindow", "&Show log...")) + self.action_create_fit_function.setText(_translate("BaseWindow", "&Create fit function...")) + self.actionGrace_preferences.setText(_translate("BaseWindow", "&Grace preferences...")) + self.actionSave_session.setText(_translate("BaseWindow", "Update session")) + self.actionMouse_behaviour.setText(_translate("BaseWindow", "Mouse behaviour")) + self.actionMouse_behaviour.setToolTip(_translate("BaseWindow", "Switch between zoom and pan in graph.")) + self.actionConfiguration.setText(_translate("BaseWindow", "Configuration...")) + self.actionRefresh.setText(_translate("BaseWindow", "Refresh")) + self.actionRefresh.setShortcut(_translate("BaseWindow", "F5")) + self.actionInterpolation.setText(_translate("BaseWindow", "Interpolation...")) + self.actionRunning_values.setText(_translate("BaseWindow", "Smoothing...")) + self.actionFit_parameter_saving.setText(_translate("BaseWindow", "Fit parameter saving...")) + self.actionShow_fit_parameter.setText(_translate("BaseWindow", "Parameter...")) + self.actionSkip_points.setText(_translate("BaseWindow", "Skip points...")) + self.actionGuide_lines.setText(_translate("BaseWindow", "Draw lines...")) + self.actionMaximize.setText(_translate("BaseWindow", "Maximize")) + self.actionTile.setText(_translate("BaseWindow", "Tile windows")) + self.actionMinimize.setText(_translate("BaseWindow", "Minimize")) + self.actionNew_window.setText(_translate("BaseWindow", "New plot")) + self.actionDelete_window.setText(_translate("BaseWindow", "Delete plot")) + self.actionCascade_windows.setText(_translate("BaseWindow", "Cascade windows")) + self.actionNext_window.setText(_translate("BaseWindow", "Next")) + self.actionNext_window.setShortcut(_translate("BaseWindow", "Alt+Right")) + self.actionPrevious.setText(_translate("BaseWindow", "Previous")) + self.actionPrevious.setShortcut(_translate("BaseWindow", "Alt+Left")) + self.t1action.setText(_translate("BaseWindow", "Evaluate T1 minimum...")) + self.t1tau.setText(_translate("BaseWindow", "Calculate T1...")) + self.action_coup_calc.setText(_translate("BaseWindow", "Coupling values...")) + self.action_calc_eps_derivative.setText(_translate("BaseWindow", "Calculate derivative loss")) + self.actionOpen_FC.setText(_translate("BaseWindow", "Read FC data...")) + self.action_mean_t1.setText(_translate("BaseWindow", "Convert mean values...")) + self.actionFilon.setText(_translate("BaseWindow", "Log FT...")) + self.action_new_set.setText(_translate("BaseWindow", "New set")) + self.action_magnitude.setText(_translate("BaseWindow", "Calculate magnitude")) + self.actionCenterMax.setText(_translate("BaseWindow", "Center on max")) + self.action_depake.setText(_translate("BaseWindow", "De-paked spectrum")) + self.action_edit.setText(_translate("BaseWindow", "Edit signals...")) + self.actionPick_position.setText(_translate("BaseWindow", "Pick points...")) + self.actionIntegrate.setText(_translate("BaseWindow", "Integrate")) + self.actionDerivation.setText(_translate("BaseWindow", "Differentiation...")) + self.actionIntegration.setText(_translate("BaseWindow", "Integration...")) + self.action_cut.setText(_translate("BaseWindow", "Cut to visible range")) + self.actionMove_between_plots.setText(_translate("BaseWindow", "Move sets...")) + self.actionBaseline.setText(_translate("BaseWindow", "Baseline...")) + self.actionCalculateT1.setText(_translate("BaseWindow", "Calculate relaxation...")) + self.actionChange_datatypes.setText(_translate("BaseWindow", "Change datatypes...")) + self.actionPrint.setText(_translate("BaseWindow", "Print...")) + self.actionPrint.setShortcut(_translate("BaseWindow", "Ctrl+P")) + self.action_lm_fit.setText(_translate("BaseWindow", "Default stuff")) + self.action_nm_fit.setText(_translate("BaseWindow", "Nelder-Mead")) + self.action_odr_fit.setText(_translate("BaseWindow", "ODR")) + self.action_no_range.setText(_translate("BaseWindow", "None")) + self.action_x_range.setText(_translate("BaseWindow", "Visible x range")) + self.action_custom_range.setText(_translate("BaseWindow", "Custom")) + self.actionSnake.setText(_translate("BaseWindow", "Worms")) + self.actionFunction_editor.setText(_translate("BaseWindow", "Function editor...")) + self.actionLife.setText(_translate("BaseWindow", "Life...")) + self.actionTetris.setText(_translate("BaseWindow", "Not Tetris")) + self.actionUpdate.setText(_translate("BaseWindow", "Look for updates")) +from ..data.datawidget.datawidget import DataWidget +from ..data.point_select import PointSelectWidget +from ..data.signaledit.editsignalwidget import EditSignalWidget +from ..data.valueeditwidget import ValueEditWidget +from ..fit.fitwindow import QFitDialog +from ..nmr.t1widget import QT1Widget diff --git a/nmreval/gui_qt/_py/bdsdialog.py b/nmreval/gui_qt/_py/bdsdialog.py new file mode 100644 index 0000000..909eb76 --- /dev/null +++ b/nmreval/gui_qt/_py/bdsdialog.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/bdsdialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(400, 319) + self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setObjectName("gridLayout") + self.listWidget = QtWidgets.QListWidget(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth()) + self.listWidget.setSizePolicy(sizePolicy) + self.listWidget.setObjectName("listWidget") + self.gridLayout.addWidget(self.listWidget, 1, 0, 1, 1) + self.label = QtWidgets.QLabel(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + self.label_2 = QtWidgets.QLabel(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth()) + self.label_2.setSizePolicy(sizePolicy) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 0, 1, 1, 1) + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.eps_checkBox = QtWidgets.QCheckBox(Dialog) + self.eps_checkBox.setChecked(True) + self.eps_checkBox.setObjectName("eps_checkBox") + self.verticalLayout.addWidget(self.eps_checkBox) + self.modul_checkBox = QtWidgets.QCheckBox(Dialog) + self.modul_checkBox.setObjectName("modul_checkBox") + self.verticalLayout.addWidget(self.modul_checkBox) + self.cond_checkBox = QtWidgets.QCheckBox(Dialog) + self.cond_checkBox.setObjectName("cond_checkBox") + self.verticalLayout.addWidget(self.cond_checkBox) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem) + self.gridLayout.addLayout(self.verticalLayout, 1, 1, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 2, 0, 1, 2) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Read BDS data")) + self.label.setText(_translate("Dialog", "Found temperatures")) + self.label_2.setText(_translate("Dialog", "Read as:")) + self.eps_checkBox.setText(_translate("Dialog", "Permittivity ε")) + self.modul_checkBox.setText(_translate("Dialog", "Modulus 1/ε")) + self.cond_checkBox.setText(_translate("Dialog", "Conductivity iεω")) diff --git a/nmreval/gui_qt/_py/color_palette.py b/nmreval/gui_qt/_py/color_palette.py new file mode 100644 index 0000000..7d7e186 --- /dev/null +++ b/nmreval/gui_qt/_py/color_palette.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/color_palette.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(390, 409) + self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setObjectName("gridLayout") + self.append_palette_button = QtWidgets.QPushButton(Dialog) + self.append_palette_button.setObjectName("append_palette_button") + self.gridLayout.addWidget(self.append_palette_button, 2, 0, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem, 4, 0, 1, 1) + self.palette_combobox = QtWidgets.QComboBox(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.palette_combobox.sizePolicy().hasHeightForWidth()) + self.palette_combobox.setSizePolicy(sizePolicy) + self.palette_combobox.setObjectName("palette_combobox") + self.gridLayout.addWidget(self.palette_combobox, 0, 0, 1, 1) + self.add_color_button = QtWidgets.QPushButton(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.add_color_button.sizePolicy().hasHeightForWidth()) + self.add_color_button.setSizePolicy(sizePolicy) + self.add_color_button.setObjectName("add_color_button") + self.gridLayout.addWidget(self.add_color_button, 6, 0, 1, 1) + self.color_combobox = ColorListEditor(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.color_combobox.sizePolicy().hasHeightForWidth()) + self.color_combobox.setSizePolicy(sizePolicy) + self.color_combobox.setObjectName("color_combobox") + self.gridLayout.addWidget(self.color_combobox, 5, 0, 1, 1) + self.save_button = QtWidgets.QPushButton(Dialog) + self.save_button.setObjectName("save_button") + self.gridLayout.addWidget(self.save_button, 9, 1, 1, 1) + self.add_palette_button = QtWidgets.QPushButton(Dialog) + self.add_palette_button.setObjectName("add_palette_button") + self.gridLayout.addWidget(self.add_palette_button, 1, 0, 1, 1) + self.new_name_edit = QtWidgets.QLineEdit(Dialog) + self.new_name_edit.setObjectName("new_name_edit") + self.gridLayout.addWidget(self.new_name_edit, 9, 2, 1, 1) + self.colorlist = QtWidgets.QListWidget(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.colorlist.sizePolicy().hasHeightForWidth()) + self.colorlist.setSizePolicy(sizePolicy) + self.colorlist.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) + self.colorlist.setObjectName("colorlist") + self.gridLayout.addWidget(self.colorlist, 0, 1, 9, 2) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 10, 0, 1, 3) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Color Palette")) + self.append_palette_button.setText(_translate("Dialog", "Append")) + self.add_color_button.setText(_translate("Dialog", "Add color")) + self.save_button.setText(_translate("Dialog", "Save as new list")) + self.add_palette_button.setText(_translate("Dialog", "Load")) +from ..lib.delegates import ColorListEditor diff --git a/nmreval/gui_qt/_py/coupling_calculator.py b/nmreval/gui_qt/_py/coupling_calculator.py new file mode 100644 index 0000000..72ac914 --- /dev/null +++ b/nmreval/gui_qt/_py/coupling_calculator.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/coupling_calculator.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_coupling_calc_dialog(object): + def setupUi(self, coupling_calc_dialog): + coupling_calc_dialog.setObjectName("coupling_calc_dialog") + coupling_calc_dialog.resize(400, 280) + self.verticalLayout = QtWidgets.QVBoxLayout(coupling_calc_dialog) + self.verticalLayout.setObjectName("verticalLayout") + self.comboBox = QtWidgets.QComboBox(coupling_calc_dialog) + self.comboBox.setObjectName("comboBox") + self.verticalLayout.addWidget(self.comboBox) + self.label_2 = QtWidgets.QLabel(coupling_calc_dialog) + self.label_2.setObjectName("label_2") + self.verticalLayout.addWidget(self.label_2) + self.verticalFrame = QtWidgets.QFrame(coupling_calc_dialog) + self.verticalFrame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.verticalFrame.setObjectName("verticalFrame") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.verticalFrame) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.verticalLayout.addWidget(self.verticalFrame) + self.label = QtWidgets.QLabel(coupling_calc_dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setStyleSheet("font-weight: bold") + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem) + self.buttonBox = QtWidgets.QDialogButtonBox(coupling_calc_dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + + self.retranslateUi(coupling_calc_dialog) + self.buttonBox.accepted.connect(coupling_calc_dialog.accept) + self.buttonBox.rejected.connect(coupling_calc_dialog.reject) + QtCore.QMetaObject.connectSlotsByName(coupling_calc_dialog) + + def retranslateUi(self, coupling_calc_dialog): + _translate = QtCore.QCoreApplication.translate + coupling_calc_dialog.setWindowTitle(_translate("coupling_calc_dialog", "Calculate BPP coupling constants")) + self.label_2.setText(_translate("coupling_calc_dialog", "TextLabel")) + self.label.setText(_translate("coupling_calc_dialog", "TextLabel")) diff --git a/nmreval/gui_qt/_py/coupling_t1_from_tau.py b/nmreval/gui_qt/_py/coupling_t1_from_tau.py new file mode 100644 index 0000000..4a18eea --- /dev/null +++ b/nmreval/gui_qt/_py/coupling_t1_from_tau.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/coupling_t1_from_tau.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_couplingForm(object): + def setupUi(self, couplingForm): + couplingForm.setObjectName("couplingForm") + couplingForm.resize(400, 300) + self.horizontalLayout = QtWidgets.QHBoxLayout(couplingForm) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(couplingForm) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.lineEdit = LineEdit(couplingForm) + self.lineEdit.setObjectName("lineEdit") + self.horizontalLayout.addWidget(self.lineEdit) + self.radioButton_2 = QtWidgets.QRadioButton(couplingForm) + self.radioButton_2.setChecked(True) + self.radioButton_2.setObjectName("radioButton_2") + self.buttonGroup = QtWidgets.QButtonGroup(couplingForm) + self.buttonGroup.setObjectName("buttonGroup") + self.buttonGroup.addButton(self.radioButton_2) + self.horizontalLayout.addWidget(self.radioButton_2) + self.radioButton = QtWidgets.QRadioButton(couplingForm) + self.radioButton.setObjectName("radioButton") + self.buttonGroup.addButton(self.radioButton) + self.horizontalLayout.addWidget(self.radioButton) + + self.retranslateUi(couplingForm) + QtCore.QMetaObject.connectSlotsByName(couplingForm) + + def retranslateUi(self, couplingForm): + _translate = QtCore.QCoreApplication.translate + couplingForm.setWindowTitle(_translate("couplingForm", "Form")) + self.label.setText(_translate("couplingForm", "parameter_name")) + self.radioButton_2.setText(_translate("couplingForm", "Value")) + self.radioButton.setText(_translate("couplingForm", "Index")) +from nmrevalgui.lib.forms import LineEdit diff --git a/nmreval/gui_qt/_py/datawidget.py b/nmreval/gui_qt/_py/datawidget.py new file mode 100644 index 0000000..498dbfe --- /dev/null +++ b/nmreval/gui_qt/_py/datawidget.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/datawidget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_DataWidget(object): + def setupUi(self, DataWidget): + DataWidget.setObjectName("DataWidget") + DataWidget.resize(307, 847) + self.verticalLayout_2 = QtWidgets.QVBoxLayout(DataWidget) + self.verticalLayout_2.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_2.setSpacing(3) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.verticalLayout_2.addLayout(self.verticalLayout) + self.propwidget = ExpandableWidget(DataWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.propwidget.sizePolicy().hasHeightForWidth()) + self.propwidget.setSizePolicy(sizePolicy) + self.propwidget.setObjectName("propwidget") + self.verticalLayout_2.addWidget(self.propwidget) + self.frame = QtWidgets.QFrame(DataWidget) + self.frame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame.setFrameShadow(QtWidgets.QFrame.Plain) + self.frame.setObjectName("frame") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setSpacing(0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.graph_toolButton = QtWidgets.QToolButton(self.frame) + self.graph_toolButton.setObjectName("graph_toolButton") + self.horizontalLayout.addWidget(self.graph_toolButton) + self.empty_toolButton = QtWidgets.QToolButton(self.frame) + self.empty_toolButton.setObjectName("empty_toolButton") + self.horizontalLayout.addWidget(self.empty_toolButton) + self.func_toolButton = QtWidgets.QToolButton(self.frame) + self.func_toolButton.setText("") + self.func_toolButton.setObjectName("func_toolButton") + self.horizontalLayout.addWidget(self.func_toolButton) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.verticalLayout_2.addWidget(self.frame) + + self.retranslateUi(DataWidget) + QtCore.QMetaObject.connectSlotsByName(DataWidget) + + def retranslateUi(self, DataWidget): + _translate = QtCore.QCoreApplication.translate + DataWidget.setWindowTitle(_translate("DataWidget", "Data")) + self.graph_toolButton.setToolTip(_translate("DataWidget", "New graph")) + self.graph_toolButton.setText(_translate("DataWidget", "New graph")) + self.empty_toolButton.setToolTip(_translate("DataWidget", "New set")) + self.empty_toolButton.setText(_translate("DataWidget", "Empty set")) +from ..lib.expandablewidget import ExpandableWidget diff --git a/nmreval/gui_qt/_py/dscfile_dialog.py b/nmreval/gui_qt/_py/dscfile_dialog.py new file mode 100644 index 0000000..12cb6d5 --- /dev/null +++ b/nmreval/gui_qt/_py/dscfile_dialog.py @@ -0,0 +1,213 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/dscfile_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.9.2 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(962, 662) + self.gridLayout_2 = QtWidgets.QGridLayout(Dialog) + self.gridLayout_2.setObjectName("gridLayout_2") + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok|QtWidgets.QDialogButtonBox.Save) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout_2.addWidget(self.buttonBox, 1, 1, 1, 1) + self.gridLayout_4 = QtWidgets.QGridLayout() + self.gridLayout_4.setContentsMargins(-1, 0, 0, -1) + self.gridLayout_4.setSpacing(3) + self.gridLayout_4.setObjectName("gridLayout_4") + self.cp_checkBox = QtWidgets.QCheckBox(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.cp_checkBox.sizePolicy().hasHeightForWidth()) + self.cp_checkBox.setSizePolicy(sizePolicy) + self.cp_checkBox.setChecked(True) + self.cp_checkBox.setObjectName("cp_checkBox") + self.gridLayout_4.addWidget(self.cp_checkBox, 11, 0, 1, 4) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setSpacing(3) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.loadempty_button = QtWidgets.QPushButton(Dialog) + self.loadempty_button.setObjectName("loadempty_button") + self.horizontalLayout_2.addWidget(self.loadempty_button) + self.delempty_button = QtWidgets.QPushButton(Dialog) + self.delempty_button.setObjectName("delempty_button") + self.horizontalLayout_2.addWidget(self.delempty_button) + self.gridLayout_4.addLayout(self.horizontalLayout_2, 5, 0, 1, 4) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_4.addItem(spacerItem, 12, 0, 1, 1) + self.isotherm_radioButton = QtWidgets.QRadioButton(Dialog) + self.isotherm_radioButton.setChecked(True) + self.isotherm_radioButton.setObjectName("isotherm_radioButton") + self.buttonGroup = QtWidgets.QButtonGroup(Dialog) + self.buttonGroup.setObjectName("buttonGroup") + self.buttonGroup.addButton(self.isotherm_radioButton) + self.gridLayout_4.addWidget(self.isotherm_radioButton, 6, 1, 1, 1) + self.label_4 = QtWidgets.QLabel(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4.setSizePolicy(sizePolicy) + self.label_4.setStyleSheet("font-weight: bold") + self.label_4.setObjectName("label_4") + self.gridLayout_4.addWidget(self.label_4, 0, 0, 1, 4) + self.reference_tableWidget = QtWidgets.QTableWidget(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.reference_tableWidget.sizePolicy().hasHeightForWidth()) + self.reference_tableWidget.setSizePolicy(sizePolicy) + self.reference_tableWidget.setMinimumSize(QtCore.QSize(0, 0)) + self.reference_tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.reference_tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.reference_tableWidget.setColumnCount(2) + self.reference_tableWidget.setObjectName("reference_tableWidget") + self.reference_tableWidget.setRowCount(0) + self.reference_tableWidget.horizontalHeader().setVisible(False) + self.reference_tableWidget.horizontalHeader().setStretchLastSection(True) + self.reference_tableWidget.verticalHeader().setVisible(False) + self.gridLayout_4.addWidget(self.reference_tableWidget, 9, 0, 1, 4) + self.step_listWidget = QtWidgets.QListWidget(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.step_listWidget.sizePolicy().hasHeightForWidth()) + self.step_listWidget.setSizePolicy(sizePolicy) + self.step_listWidget.setMinimumSize(QtCore.QSize(0, 0)) + self.step_listWidget.setObjectName("step_listWidget") + self.gridLayout_4.addWidget(self.step_listWidget, 1, 0, 1, 4) + self.label = QtWidgets.QLabel(Dialog) + self.label.setObjectName("label") + self.gridLayout_4.addWidget(self.label, 6, 0, 1, 1) + self.slope_radioButton = QtWidgets.QRadioButton(Dialog) + self.slope_radioButton.setObjectName("slope_radioButton") + self.buttonGroup.addButton(self.slope_radioButton) + self.gridLayout_4.addWidget(self.slope_radioButton, 6, 2, 1, 1) + self.empty_label = QtWidgets.QLabel(Dialog) + self.empty_label.setObjectName("empty_label") + self.gridLayout_4.addWidget(self.empty_label, 4, 0, 1, 4) + self.label_3 = QtWidgets.QLabel(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth()) + self.label_3.setSizePolicy(sizePolicy) + self.label_3.setStyleSheet("font-weight: bold") + self.label_3.setObjectName("label_3") + self.gridLayout_4.addWidget(self.label_3, 8, 0, 1, 4) + self.label_2 = QtWidgets.QLabel(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth()) + self.label_2.setSizePolicy(sizePolicy) + self.label_2.setStyleSheet("font-weight: bold") + self.label_2.setObjectName("label_2") + self.gridLayout_4.addWidget(self.label_2, 3, 0, 1, 4) + self.line = QtWidgets.QFrame(Dialog) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.gridLayout_4.addWidget(self.line, 7, 0, 1, 4) + self.none_radioButton = QtWidgets.QRadioButton(Dialog) + self.none_radioButton.setObjectName("none_radioButton") + self.buttonGroup.addButton(self.none_radioButton) + self.gridLayout_4.addWidget(self.none_radioButton, 6, 3, 1, 1) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setSpacing(3) + self.horizontalLayout.setObjectName("horizontalLayout") + self.ref_add_pushButton = QtWidgets.QPushButton(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.ref_add_pushButton.sizePolicy().hasHeightForWidth()) + self.ref_add_pushButton.setSizePolicy(sizePolicy) + self.ref_add_pushButton.setObjectName("ref_add_pushButton") + self.horizontalLayout.addWidget(self.ref_add_pushButton) + self.ref_remove_pushButton = QtWidgets.QPushButton(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.ref_remove_pushButton.sizePolicy().hasHeightForWidth()) + self.ref_remove_pushButton.setSizePolicy(sizePolicy) + self.ref_remove_pushButton.setObjectName("ref_remove_pushButton") + self.horizontalLayout.addWidget(self.ref_remove_pushButton) + self.gridLayout_4.addLayout(self.horizontalLayout, 10, 0, 1, 4) + self.line_2 = QtWidgets.QFrame(Dialog) + self.line_2.setFrameShape(QtWidgets.QFrame.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.gridLayout_4.addWidget(self.line_2, 2, 0, 1, 4) + self.gridLayout_2.addLayout(self.gridLayout_4, 0, 0, 1, 1) + self.gridLayout = QtWidgets.QGridLayout() + self.gridLayout.setObjectName("gridLayout") + self.raw_graph = PlotWidget(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.raw_graph.sizePolicy().hasHeightForWidth()) + self.raw_graph.setSizePolicy(sizePolicy) + self.raw_graph.setMinimumSize(QtCore.QSize(300, 200)) + self.raw_graph.setObjectName("raw_graph") + self.gridLayout.addWidget(self.raw_graph, 0, 0, 1, 1) + self.calib_graph = PlotWidget(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.calib_graph.sizePolicy().hasHeightForWidth()) + self.calib_graph.setSizePolicy(sizePolicy) + self.calib_graph.setMinimumSize(QtCore.QSize(300, 200)) + self.calib_graph.setObjectName("calib_graph") + self.gridLayout.addWidget(self.calib_graph, 1, 0, 1, 1) + self.baseline_graph = PlotWidget(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.baseline_graph.sizePolicy().hasHeightForWidth()) + self.baseline_graph.setSizePolicy(sizePolicy) + self.baseline_graph.setMinimumSize(QtCore.QSize(300, 200)) + self.baseline_graph.setObjectName("baseline_graph") + self.gridLayout.addWidget(self.baseline_graph, 0, 1, 1, 1) + self.end_graph = PlotWidget(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.end_graph.sizePolicy().hasHeightForWidth()) + self.end_graph.setSizePolicy(sizePolicy) + self.end_graph.setMinimumSize(QtCore.QSize(0, 0)) + self.end_graph.setObjectName("end_graph") + self.gridLayout.addWidget(self.end_graph, 1, 1, 1, 1) + self.gridLayout_2.addLayout(self.gridLayout, 0, 1, 1, 1) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Read DSC file")) + self.cp_checkBox.setText(_translate("Dialog", "Convert to heat capacity")) + self.loadempty_button.setText(_translate("Dialog", "Load empty")) + self.delempty_button.setText(_translate("Dialog", "Remove empty")) + self.isotherm_radioButton.setText(_translate("Dialog", "Isotherms")) + self.label_4.setText(_translate("Dialog", "Detected steps")) + self.label.setText(_translate("Dialog", "Slope")) + self.slope_radioButton.setText(_translate("Dialog", "Initial slope")) + self.empty_label.setText(_translate("Dialog", "Empty measurement")) + self.label_3.setText(_translate("Dialog", "Calibration")) + self.label_2.setText(_translate("Dialog", "Baseline")) + self.none_radioButton.setText(_translate("Dialog", "None")) + self.ref_add_pushButton.setText(_translate("Dialog", "Add reference")) + self.ref_remove_pushButton.setText(_translate("Dialog", "Remove reference")) + +from pyqtgraph import PlotWidget diff --git a/nmreval/gui_qt/_py/editsignalwidget.py b/nmreval/gui_qt/_py/editsignalwidget.py new file mode 100644 index 0000000..1372ab5 --- /dev/null +++ b/nmreval/gui_qt/_py/editsignalwidget.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/editsignalwidget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(328, 732) + self.verticalLayout = QtWidgets.QVBoxLayout(Form) + self.verticalLayout.setContentsMargins(3, 3, 3, 3) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.groupBox_4 = QtWidgets.QGroupBox(Form) + self.groupBox_4.setObjectName("groupBox_4") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.groupBox_4) + self.horizontalLayout_3.setContentsMargins(3, 3, 3, 3) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.baselinebutton = QtWidgets.QPushButton(self.groupBox_4) + self.baselinebutton.setObjectName("baselinebutton") + self.horizontalLayout_3.addWidget(self.baselinebutton) + self.verticalLayout.addWidget(self.groupBox_4) + self.groupBox = QtWidgets.QGroupBox(Form) + self.groupBox.setObjectName("groupBox") + self.gridLayout_3 = QtWidgets.QGridLayout(self.groupBox) + self.gridLayout_3.setContentsMargins(3, 3, 3, 3) + self.gridLayout_3.setObjectName("gridLayout_3") + self.leftshiftbutton = QtWidgets.QPushButton(self.groupBox) + self.leftshiftbutton.setObjectName("leftshiftbutton") + self.gridLayout_3.addWidget(self.leftshiftbutton, 1, 0, 1, 2) + self.comboBox = QtWidgets.QComboBox(self.groupBox) + self.comboBox.setObjectName("comboBox") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.gridLayout_3.addWidget(self.comboBox, 0, 0, 1, 1) + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setContentsMargins(-1, 0, -1, -1) + self.verticalLayout_2.setSpacing(0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.lsspinBox = QtWidgets.QSpinBox(self.groupBox) + self.lsspinBox.setMaximum(9999) + self.lsspinBox.setObjectName("lsspinBox") + self.verticalLayout_2.addWidget(self.lsspinBox) + self.lineEdit = QtWidgets.QLineEdit(self.groupBox) + self.lineEdit.setObjectName("lineEdit") + self.verticalLayout_2.addWidget(self.lineEdit) + self.gridLayout_3.addLayout(self.verticalLayout_2, 0, 1, 1, 1) + self.verticalLayout.addWidget(self.groupBox) + self.groupBox_6 = QtWidgets.QGroupBox(Form) + self.groupBox_6.setFlat(False) + self.groupBox_6.setObjectName("groupBox_6") + self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.groupBox_6) + self.horizontalLayout_4.setContentsMargins(3, 3, 3, 3) + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.zfbutton = QtWidgets.QPushButton(self.groupBox_6) + self.zfbutton.setObjectName("zfbutton") + self.horizontalLayout_4.addWidget(self.zfbutton) + self.verticalLayout.addWidget(self.groupBox_6) + self.groupBox_2 = QtWidgets.QGroupBox(Form) + self.groupBox_2.setFlat(False) + self.groupBox_2.setObjectName("groupBox_2") + self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBox_2) + self.gridLayout_4.setContentsMargins(3, 3, 3, 3) + self.gridLayout_4.setVerticalSpacing(0) + self.gridLayout_4.setObjectName("gridLayout_4") + self.ph1slider = QtWidgets.QDoubleSpinBox(self.groupBox_2) + self.ph1slider.setMinimum(-360.0) + self.ph1slider.setMaximum(360.0) + self.ph1slider.setObjectName("ph1slider") + self.gridLayout_4.addWidget(self.ph1slider, 5, 1, 1, 1) + self.label_6 = QtWidgets.QLabel(self.groupBox_2) + self.label_6.setObjectName("label_6") + self.gridLayout_4.addWidget(self.label_6, 4, 0, 3, 1) + self.pushButton_2 = QtWidgets.QPushButton(self.groupBox_2) + self.pushButton_2.setObjectName("pushButton_2") + self.gridLayout_4.addWidget(self.pushButton_2, 8, 0, 1, 1) + self.label = QtWidgets.QLabel(self.groupBox_2) + self.label.setObjectName("label") + self.gridLayout_4.addWidget(self.label, 1, 0, 3, 1) + self.pivot_lineedit = QtWidgets.QLineEdit(self.groupBox_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pivot_lineedit.sizePolicy().hasHeightForWidth()) + self.pivot_lineedit.setSizePolicy(sizePolicy) + self.pivot_lineedit.setInputMethodHints(QtCore.Qt.ImhDigitsOnly) + self.pivot_lineedit.setObjectName("pivot_lineedit") + self.gridLayout_4.addWidget(self.pivot_lineedit, 7, 1, 1, 1) + self.ph0slider = QtWidgets.QDoubleSpinBox(self.groupBox_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.ph0slider.sizePolicy().hasHeightForWidth()) + self.ph0slider.setSizePolicy(sizePolicy) + self.ph0slider.setMinimum(-180.0) + self.ph0slider.setMaximum(180.0) + self.ph0slider.setObjectName("ph0slider") + self.gridLayout_4.addWidget(self.ph0slider, 2, 1, 1, 1) + self.label_8 = QtWidgets.QLabel(self.groupBox_2) + self.label_8.setObjectName("label_8") + self.gridLayout_4.addWidget(self.label_8, 7, 0, 1, 1) + self.phasebutton = QtWidgets.QPushButton(self.groupBox_2) + self.phasebutton.setObjectName("phasebutton") + self.gridLayout_4.addWidget(self.phasebutton, 8, 1, 1, 1) + self.verticalLayout.addWidget(self.groupBox_2) + self.groupBox_3 = QtWidgets.QGroupBox(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox_3.sizePolicy().hasHeightForWidth()) + self.groupBox_3.setSizePolicy(sizePolicy) + self.groupBox_3.setObjectName("groupBox_3") + self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.groupBox_3) + self.verticalLayout_7.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_7.setObjectName("verticalLayout_7") + self.apodcombobox = QtWidgets.QComboBox(self.groupBox_3) + self.apodcombobox.setObjectName("apodcombobox") + self.verticalLayout_7.addWidget(self.apodcombobox) + self.label_2 = QtWidgets.QLabel(self.groupBox_3) + self.label_2.setIndent(3) + self.label_2.setObjectName("label_2") + self.verticalLayout_7.addWidget(self.label_2) + self.verticalLayout_8 = QtWidgets.QVBoxLayout() + self.verticalLayout_8.setSpacing(0) + self.verticalLayout_8.setObjectName("verticalLayout_8") + self.verticalLayout_7.addLayout(self.verticalLayout_8) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.pushButton = QtWidgets.QPushButton(self.groupBox_3) + self.pushButton.setObjectName("pushButton") + self.horizontalLayout.addWidget(self.pushButton) + self.apodbutton = QtWidgets.QPushButton(self.groupBox_3) + self.apodbutton.setObjectName("apodbutton") + self.horizontalLayout.addWidget(self.apodbutton) + self.verticalLayout_7.addLayout(self.horizontalLayout) + self.verticalLayout.addWidget(self.groupBox_3) + self.groupBox_5 = QtWidgets.QGroupBox(Form) + self.groupBox_5.setObjectName("groupBox_5") + self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.groupBox_5) + self.horizontalLayout_5.setContentsMargins(3, 3, 3, 3) + self.horizontalLayout_5.setObjectName("horizontalLayout_5") + self.fourierutton = QtWidgets.QPushButton(self.groupBox_5) + self.fourierutton.setObjectName("fourierutton") + self.horizontalLayout_5.addWidget(self.fourierutton) + self.verticalLayout.addWidget(self.groupBox_5) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.groupBox_4.setTitle(_translate("Form", "Baseline correction")) + self.baselinebutton.setText(_translate("Form", "Apply")) + self.groupBox.setTitle(_translate("Form", "Left shift")) + self.leftshiftbutton.setText(_translate("Form", "Apply")) + self.comboBox.setItemText(0, _translate("Form", "Points")) + self.comboBox.setItemText(1, _translate("Form", "Seconds")) + self.groupBox_6.setTitle(_translate("Form", "Zerofilling")) + self.zfbutton.setText(_translate("Form", "Apply")) + self.groupBox_2.setTitle(_translate("Form", "Phase correction")) + self.label_6.setText(_translate("Form", "Phase 1")) + self.pushButton_2.setText(_translate("Form", "Preview")) + self.label.setText(_translate("Form", "Phase 0")) + self.pivot_lineedit.setText(_translate("Form", "0")) + self.label_8.setText(_translate("Form", "Pivot")) + self.phasebutton.setText(_translate("Form", "Apply")) + self.groupBox_3.setTitle(_translate("Form", "Apodization")) + self.label_2.setText(_translate("Form", "TextLabel")) + self.pushButton.setText(_translate("Form", "Preview")) + self.apodbutton.setText(_translate("Form", "Apply")) + self.groupBox_5.setTitle(_translate("Form", "FFT")) + self.fourierutton.setText(_translate("Form", "Apply")) diff --git a/nmreval/gui_qt/_py/eval_expr_dialog.py b/nmreval/gui_qt/_py/eval_expr_dialog.py new file mode 100644 index 0000000..d70a5ed --- /dev/null +++ b/nmreval/gui_qt/_py/eval_expr_dialog.py @@ -0,0 +1,240 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/eval_expr_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_CalcDialog(object): + def setupUi(self, CalcDialog): + CalcDialog.setObjectName("CalcDialog") + CalcDialog.setWindowModality(QtCore.Qt.WindowModal) + CalcDialog.resize(804, 627) + self.verticalLayout_5 = QtWidgets.QVBoxLayout(CalcDialog) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.splitter_2 = QtWidgets.QSplitter(CalcDialog) + self.splitter_2.setOrientation(QtCore.Qt.Horizontal) + self.splitter_2.setObjectName("splitter_2") + self.verticalLayoutWidget = QtWidgets.QWidget(self.splitter_2) + self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") + self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.verticalLayout.setObjectName("verticalLayout") + self.stackedWidget = QtWidgets.QStackedWidget(self.verticalLayoutWidget) + self.stackedWidget.setObjectName("stackedWidget") + self.page = QtWidgets.QWidget() + self.page.setObjectName("page") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.page) + self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_2.setSpacing(0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.label_2 = QtWidgets.QLabel(self.page) + self.label_2.setObjectName("label_2") + self.verticalLayout_2.addWidget(self.label_2) + self.listWidget = QtWidgets.QListWidget(self.page) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth()) + self.listWidget.setSizePolicy(sizePolicy) + self.listWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.listWidget.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.listWidget.setObjectName("listWidget") + self.verticalLayout_2.addWidget(self.listWidget) + self.overwrite_checkbox = QtWidgets.QCheckBox(self.page) + self.overwrite_checkbox.setLayoutDirection(QtCore.Qt.LeftToRight) + self.overwrite_checkbox.setObjectName("overwrite_checkbox") + self.verticalLayout_2.addWidget(self.overwrite_checkbox) + self.stackedWidget.addWidget(self.page) + self.page_2 = QtWidgets.QWidget() + self.page_2.setObjectName("page_2") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.page_2) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.groupBox_2 = QtWidgets.QGroupBox(self.page_2) + self.groupBox_2.setObjectName("groupBox_2") + self.formLayout_3 = QtWidgets.QFormLayout(self.groupBox_2) + self.formLayout_3.setContentsMargins(3, 3, 3, 3) + self.formLayout_3.setHorizontalSpacing(3) + self.formLayout_3.setObjectName("formLayout_3") + self.label_3 = QtWidgets.QLabel(self.groupBox_2) + self.label_3.setObjectName("label_3") + self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_3) + self.label_lineEdit = QtWidgets.QLineEdit(self.groupBox_2) + self.label_lineEdit.setObjectName("label_lineEdit") + self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.label_lineEdit) + self.label_9 = QtWidgets.QLabel(self.groupBox_2) + self.label_9.setObjectName("label_9") + self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_9) + self.value_lineEdit = QtWidgets.QLineEdit(self.groupBox_2) + self.value_lineEdit.setObjectName("value_lineEdit") + self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.value_lineEdit) + self.label_6 = QtWidgets.QLabel(self.groupBox_2) + self.label_6.setObjectName("label_6") + self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_6) + self.dtype_comboBox = QtWidgets.QComboBox(self.groupBox_2) + self.dtype_comboBox.setObjectName("dtype_comboBox") + self.dtype_comboBox.addItem("") + self.dtype_comboBox.addItem("") + self.dtype_comboBox.addItem("") + self.dtype_comboBox.addItem("") + self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.dtype_comboBox) + self.verticalLayout_4.addWidget(self.groupBox_2) + self.groupBox = QtWidgets.QGroupBox(self.page_2) + self.groupBox.setObjectName("groupBox") + self.formLayout_2 = QtWidgets.QFormLayout(self.groupBox) + self.formLayout_2.setContentsMargins(3, 3, 3, 3) + self.formLayout_2.setSpacing(3) + self.formLayout_2.setObjectName("formLayout_2") + self.label_4 = QtWidgets.QLabel(self.groupBox) + self.label_4.setObjectName("label_4") + self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_4) + self.symcolor_comboBox = ColorListEditor(self.groupBox) + self.symcolor_comboBox.setObjectName("symcolor_comboBox") + self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.symcolor_comboBox) + self.label_5 = QtWidgets.QLabel(self.groupBox) + self.label_5.setObjectName("label_5") + self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_5) + self.symbol_spinBox = QtWidgets.QSpinBox(self.groupBox) + self.symbol_spinBox.setProperty("value", 10) + self.symbol_spinBox.setObjectName("symbol_spinBox") + self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.symbol_spinBox) + self.symbol_comboBox = SymbolStyleEditor(self.groupBox) + self.symbol_comboBox.setObjectName("symbol_comboBox") + self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.symbol_comboBox) + self.label_10 = QtWidgets.QLabel(self.groupBox) + self.label_10.setObjectName("label_10") + self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_10) + self.verticalLayout_4.addWidget(self.groupBox) + self.groupBox_3 = QtWidgets.QGroupBox(self.page_2) + self.groupBox_3.setObjectName("groupBox_3") + self.formLayout = QtWidgets.QFormLayout(self.groupBox_3) + self.formLayout.setContentsMargins(3, 3, 3, 3) + self.formLayout.setSpacing(3) + self.formLayout.setObjectName("formLayout") + self.label_7 = QtWidgets.QLabel(self.groupBox_3) + self.label_7.setObjectName("label_7") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_7) + self.linecolor_comboBox = ColorListEditor(self.groupBox_3) + self.linecolor_comboBox.setObjectName("linecolor_comboBox") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.linecolor_comboBox) + self.label_8 = QtWidgets.QLabel(self.groupBox_3) + self.label_8.setObjectName("label_8") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_8) + self.line_doubleSpinBox = QtWidgets.QDoubleSpinBox(self.groupBox_3) + self.line_doubleSpinBox.setProperty("value", 1.0) + self.line_doubleSpinBox.setObjectName("line_doubleSpinBox") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.line_doubleSpinBox) + self.linestyle_comboBox = LineStyleEditor(self.groupBox_3) + self.linestyle_comboBox.setObjectName("linestyle_comboBox") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.linestyle_comboBox) + self.label_11 = QtWidgets.QLabel(self.groupBox_3) + self.label_11.setObjectName("label_11") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_11) + self.verticalLayout_4.addWidget(self.groupBox_3) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_4.addItem(spacerItem) + self.graph_comboBox = QtWidgets.QComboBox(self.page_2) + self.graph_comboBox.setObjectName("graph_comboBox") + self.verticalLayout_4.addWidget(self.graph_comboBox) + self.groupBox.raise_() + self.groupBox_2.raise_() + self.groupBox_3.raise_() + self.graph_comboBox.raise_() + self.stackedWidget.addWidget(self.page_2) + self.page_3 = QtWidgets.QWidget() + self.page_3.setObjectName("page_3") + self.stackedWidget.addWidget(self.page_3) + self.verticalLayout.addWidget(self.stackedWidget) + self.splitter = QtWidgets.QSplitter(self.splitter_2) + self.splitter.setOrientation(QtCore.Qt.Vertical) + self.splitter.setChildrenCollapsible(False) + self.splitter.setObjectName("splitter") + self.verticalLayoutWidget_2 = QtWidgets.QWidget(self.splitter) + self.verticalLayoutWidget_2.setObjectName("verticalLayoutWidget_2") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_2) + self.verticalLayout_6.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.namespace_widget = QNamespaceWidget(self.verticalLayoutWidget_2) + self.namespace_widget.setObjectName("namespace_widget") + self.verticalLayout_6.addWidget(self.namespace_widget) + self.verticalLayoutWidget_3 = QtWidgets.QWidget(self.splitter) + self.verticalLayoutWidget_3.setObjectName("verticalLayoutWidget_3") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_3) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.line_2 = QtWidgets.QFrame(self.verticalLayoutWidget_3) + self.line_2.setFrameShape(QtWidgets.QFrame.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.verticalLayout_3.addWidget(self.line_2) + self.label = QtWidgets.QLabel(self.verticalLayoutWidget_3) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label.setFont(font) + self.label.setObjectName("label") + self.verticalLayout_3.addWidget(self.label) + self.calc_edit = QtWidgets.QPlainTextEdit(self.verticalLayoutWidget_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.calc_edit.sizePolicy().hasHeightForWidth()) + self.calc_edit.setSizePolicy(sizePolicy) + self.calc_edit.setObjectName("calc_edit") + self.verticalLayout_3.addWidget(self.calc_edit) + self.verticalLayout_5.addWidget(self.splitter_2) + self.buttonBox = QtWidgets.QDialogButtonBox(CalcDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout_5.addWidget(self.buttonBox) + self.label_3.setBuddy(self.label_lineEdit) + self.label_9.setBuddy(self.value_lineEdit) + self.label_6.setBuddy(self.dtype_comboBox) + self.label_4.setBuddy(self.symcolor_comboBox) + self.label_5.setBuddy(self.symbol_spinBox) + self.label_7.setBuddy(self.linecolor_comboBox) + self.label_8.setBuddy(self.line_doubleSpinBox) + + self.retranslateUi(CalcDialog) + self.stackedWidget.setCurrentIndex(2) + QtCore.QMetaObject.connectSlotsByName(CalcDialog) + CalcDialog.setTabOrder(self.calc_edit, self.listWidget) + CalcDialog.setTabOrder(self.listWidget, self.overwrite_checkbox) + CalcDialog.setTabOrder(self.overwrite_checkbox, self.label_lineEdit) + CalcDialog.setTabOrder(self.label_lineEdit, self.value_lineEdit) + CalcDialog.setTabOrder(self.value_lineEdit, self.dtype_comboBox) + CalcDialog.setTabOrder(self.dtype_comboBox, self.symcolor_comboBox) + CalcDialog.setTabOrder(self.symcolor_comboBox, self.symbol_spinBox) + CalcDialog.setTabOrder(self.symbol_spinBox, self.linecolor_comboBox) + CalcDialog.setTabOrder(self.linecolor_comboBox, self.line_doubleSpinBox) + + def retranslateUi(self, CalcDialog): + _translate = QtCore.QCoreApplication.translate + CalcDialog.setWindowTitle(_translate("CalcDialog", "Evaluate stuff")) + self.label_2.setText(_translate("CalcDialog", "Select sets for evaluation")) + self.overwrite_checkbox.setText(_translate("CalcDialog", "Overwrite values")) + self.groupBox_2.setTitle(_translate("CalcDialog", "GroupBox")) + self.label_3.setText(_translate("CalcDialog", "Label")) + self.label_9.setText(_translate("CalcDialog", "Value")) + self.label_6.setText(_translate("CalcDialog", "Datatype")) + self.dtype_comboBox.setItemText(0, _translate("CalcDialog", "Points")) + self.dtype_comboBox.setItemText(1, _translate("CalcDialog", "Timesignal")) + self.dtype_comboBox.setItemText(2, _translate("CalcDialog", "Spectrum")) + self.dtype_comboBox.setItemText(3, _translate("CalcDialog", "BDS")) + self.groupBox.setTitle(_translate("CalcDialog", "Symbol")) + self.label_4.setText(_translate("CalcDialog", "Color")) + self.label_5.setText(_translate("CalcDialog", "Size")) + self.label_10.setText(_translate("CalcDialog", "Style")) + self.groupBox_3.setTitle(_translate("CalcDialog", "Line")) + self.label_7.setText(_translate("CalcDialog", "Color")) + self.label_8.setText(_translate("CalcDialog", "Width")) + self.label_11.setText(_translate("CalcDialog", "Style")) + self.label.setText(_translate("CalcDialog", "Expressions are evaluated line by line and change previous values")) +from ..lib.delegates import ColorListEditor, LineStyleEditor, SymbolStyleEditor +from ..lib.namespace import QNamespaceWidget diff --git a/nmreval/gui_qt/_py/evalexpression.py b/nmreval/gui_qt/_py/evalexpression.py new file mode 100644 index 0000000..43e0f9c --- /dev/null +++ b/nmreval/gui_qt/_py/evalexpression.py @@ -0,0 +1,217 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/evalexpression.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_CalcDialog(object): + def setupUi(self, CalcDialog): + CalcDialog.setObjectName("CalcDialog") + CalcDialog.resize(895, 547) + self.gridLayout = QtWidgets.QGridLayout(CalcDialog) + self.gridLayout.setObjectName("gridLayout") + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setContentsMargins(-1, 0, -1, -1) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.tabWidget = QtWidgets.QTabWidget(CalcDialog) + self.tabWidget.setObjectName("tabWidget") + self.tab = QtWidgets.QWidget() + self.tab.setObjectName("tab") + self.verticalLayout = QtWidgets.QVBoxLayout(self.tab) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.verticalLayout.setSpacing(0) + self.verticalLayout.setObjectName("verticalLayout") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout_2.setSpacing(0) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.textEdit = QtWidgets.QTextEdit(self.tab) + self.textEdit.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.textEdit.sizePolicy().hasHeightForWidth()) + self.textEdit.setSizePolicy(sizePolicy) + self.textEdit.setFrameShape(QtWidgets.QFrame.NoFrame) + self.textEdit.setFrameShadow(QtWidgets.QFrame.Plain) + self.textEdit.setAutoFormatting(QtWidgets.QTextEdit.AutoNone) + self.textEdit.setTextInteractionFlags(QtCore.Qt.NoTextInteraction) + self.textEdit.setObjectName("textEdit") + self.horizontalLayout_2.addWidget(self.textEdit) + self.textEdit_3 = QtWidgets.QTextEdit(self.tab) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.textEdit_3.sizePolicy().hasHeightForWidth()) + self.textEdit_3.setSizePolicy(sizePolicy) + self.textEdit_3.setFrameShape(QtWidgets.QFrame.NoFrame) + self.textEdit_3.setFrameShadow(QtWidgets.QFrame.Plain) + self.textEdit_3.setTextInteractionFlags(QtCore.Qt.NoTextInteraction) + self.textEdit_3.setObjectName("textEdit_3") + self.horizontalLayout_2.addWidget(self.textEdit_3) + self.verticalLayout.addLayout(self.horizontalLayout_2) + self.tabWidget.addTab(self.tab, "") + self.tab_2 = QtWidgets.QWidget() + self.tab_2.setObjectName("tab_2") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.tab_2) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_3.setSpacing(0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout_3.setSpacing(0) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.textEdit_2 = QtWidgets.QTextEdit(self.tab_2) + self.textEdit_2.setEnabled(True) + self.textEdit_2.setFrameShape(QtWidgets.QFrame.NoFrame) + self.textEdit_2.setFrameShadow(QtWidgets.QFrame.Plain) + self.textEdit_2.setTextInteractionFlags(QtCore.Qt.NoTextInteraction) + self.textEdit_2.setObjectName("textEdit_2") + self.horizontalLayout_3.addWidget(self.textEdit_2) + self.textEdit_4 = QtWidgets.QTextEdit(self.tab_2) + self.textEdit_4.setFrameShape(QtWidgets.QFrame.NoFrame) + self.textEdit_4.setFrameShadow(QtWidgets.QFrame.Plain) + self.textEdit_4.setReadOnly(True) + self.textEdit_4.setObjectName("textEdit_4") + self.horizontalLayout_3.addWidget(self.textEdit_4) + self.verticalLayout_3.addLayout(self.horizontalLayout_3) + self.tabWidget.addTab(self.tab_2, "") + self.tab_3 = QtWidgets.QWidget() + self.tab_3.setObjectName("tab_3") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.tab_3) + self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_4.setSpacing(0) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.treeWidget = QtWidgets.QTreeWidget(self.tab_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.treeWidget.sizePolicy().hasHeightForWidth()) + self.treeWidget.setSizePolicy(sizePolicy) + self.treeWidget.setFrameShape(QtWidgets.QFrame.NoFrame) + self.treeWidget.setFrameShadow(QtWidgets.QFrame.Plain) + self.treeWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.treeWidget.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection) + self.treeWidget.setObjectName("treeWidget") + self.treeWidget.header().setVisible(False) + self.verticalLayout_4.addWidget(self.treeWidget) + self.tabWidget.addTab(self.tab_3, "") + self.verticalLayout_2.addWidget(self.tabWidget) + self.label = QtWidgets.QLabel(CalcDialog) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label.setFont(font) + self.label.setObjectName("label") + self.verticalLayout_2.addWidget(self.label) + self.calc_edit = QtWidgets.QPlainTextEdit(CalcDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.calc_edit.sizePolicy().hasHeightForWidth()) + self.calc_edit.setSizePolicy(sizePolicy) + self.calc_edit.setObjectName("calc_edit") + self.verticalLayout_2.addWidget(self.calc_edit) + self.gridLayout.addLayout(self.verticalLayout_2, 0, 3, 1, 1) + self.verticalLayout_5 = QtWidgets.QVBoxLayout() + self.verticalLayout_5.setSpacing(0) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.label_2 = QtWidgets.QLabel(CalcDialog) + self.label_2.setObjectName("label_2") + self.verticalLayout_5.addWidget(self.label_2) + self.listWidget = QtWidgets.QListWidget(CalcDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth()) + self.listWidget.setSizePolicy(sizePolicy) + self.listWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.listWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) + self.listWidget.setObjectName("listWidget") + self.verticalLayout_5.addWidget(self.listWidget) + self.overwrite_checkbox = QtWidgets.QCheckBox(CalcDialog) + self.overwrite_checkbox.setLayoutDirection(QtCore.Qt.LeftToRight) + self.overwrite_checkbox.setObjectName("overwrite_checkbox") + self.verticalLayout_5.addWidget(self.overwrite_checkbox) + self.gridLayout.addLayout(self.verticalLayout_5, 0, 1, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(CalcDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 1, 3, 1, 1) + self.line = QtWidgets.QFrame(CalcDialog) + self.line.setFrameShape(QtWidgets.QFrame.VLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.gridLayout.addWidget(self.line, 0, 2, 1, 1) + + self.retranslateUi(CalcDialog) + self.tabWidget.setCurrentIndex(0) + self.buttonBox.accepted.connect(CalcDialog.accept) + self.buttonBox.rejected.connect(CalcDialog.reject) + QtCore.QMetaObject.connectSlotsByName(CalcDialog) + + def retranslateUi(self, CalcDialog): + _translate = QtCore.QCoreApplication.translate + CalcDialog.setWindowTitle(_translate("CalcDialog", "Evaluate stuff")) + self.textEdit.setHtml(_translate("CalcDialog", "\n" +"\n" +"

- X, y, and Δy values

\n" +"

- Values of dataset on position i in list

\n" +"

(s[i].x and x return the same values)

\n" +"

- Numpy functions

\n" +"

- If available, fit parameters

\n" +"

(see namespace for available parameters)

\n" +"

- Fit functions:

\n" +"

(meaning of p and extra arguments

\n" +"

depend on function)

\n" +"

- Constants:

\n" +"

(nuclei are accessed by const[\'gamma\'][\'1H\'])

")) + self.textEdit_3.setHtml(_translate("CalcDialog", "\n" +"\n" +"

x y y_err

\n" +"

s[i].x s[i+2].y s[i-1].y_err

\n" +"


\n" +"

np.function

\n" +"

fit[\'NAME\']

\n" +"


\n" +"


\n" +"

Name.func(p, x, *args)

\n" +"


\n" +"


\n" +"

const[\'NAME\']

")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("CalcDialog", "Parameter")) + self.textEdit_2.setHtml(_translate("CalcDialog", "\n" +"\n" +"

Substract neighbouring datasets:

\n" +"

Normalize on fit value M:

\n" +"

Logscale x:

\n" +"

Division by exponential decay:

\n" +"


")) + self.textEdit_4.setHtml(_translate("CalcDialog", "\n" +"\n" +"

y = y-s[i+1].y

\n" +"

y = y/fit[\'M_infty\']

\n" +"

x = np.log10(x)

\n" +"

y = y/np.exp(-x/10)

\n" +"

y = y/Exponential_Decay.func([0, 1, 10, 1], x)

")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("CalcDialog", "Example")) + self.treeWidget.headerItem().setText(0, _translate("CalcDialog", "Namespace")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("CalcDialog", "Namespace")) + self.label.setText(_translate("CalcDialog", "Expressions are evaluated line by line and change previous values")) + self.label_2.setText(_translate("CalcDialog", "

Select sets for evaluation
(no selection = all visible):

")) + self.overwrite_checkbox.setText(_translate("CalcDialog", "Overwrite values?")) diff --git a/nmreval/gui_qt/_py/expandablewidget.py b/nmreval/gui_qt/_py/expandablewidget.py new file mode 100644 index 0000000..3fc84db --- /dev/null +++ b/nmreval/gui_qt/_py/expandablewidget.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/expandablewidget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_ExpandableForm(object): + def setupUi(self, ExpandableForm): + ExpandableForm.setObjectName("ExpandableForm") + ExpandableForm.resize(400, 300) + self.verticalLayout = QtWidgets.QVBoxLayout(ExpandableForm) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.verticalLayout.setSpacing(0) + self.verticalLayout.setObjectName("verticalLayout") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setSpacing(0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.toolButton = QtWidgets.QToolButton(ExpandableForm) + self.toolButton.setStyleSheet("border: 0") + self.toolButton.setText("") + self.toolButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + self.toolButton.setArrowType(QtCore.Qt.RightArrow) + self.toolButton.setObjectName("toolButton") + self.horizontalLayout.addWidget(self.toolButton) + self.label = QtWidgets.QLabel(ExpandableForm) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setText("") + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.line = QtWidgets.QFrame(ExpandableForm) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.horizontalLayout.addWidget(self.line) + self.verticalLayout.addLayout(self.horizontalLayout) + + self.retranslateUi(ExpandableForm) + QtCore.QMetaObject.connectSlotsByName(ExpandableForm) + + def retranslateUi(self, ExpandableForm): + _translate = QtCore.QCoreApplication.translate + ExpandableForm.setWindowTitle(_translate("ExpandableForm", "Form")) diff --git a/nmreval/gui_qt/_py/exportConfigTemplate.py b/nmreval/gui_qt/_py/exportConfigTemplate.py new file mode 100644 index 0000000..9f64f56 --- /dev/null +++ b/nmreval/gui_qt/_py/exportConfigTemplate.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/exportConfigTemplate.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(241, 367) + self.gridLayout = QtWidgets.QGridLayout(Form) + self.gridLayout.setSpacing(0) + self.gridLayout.setObjectName("gridLayout") + self.label = QtWidgets.QLabel(Form) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 0, 1, 3) + self.itemTree = QtWidgets.QTreeWidget(Form) + self.itemTree.setObjectName("itemTree") + self.itemTree.headerItem().setText(0, "1") + self.itemTree.header().setVisible(False) + self.gridLayout.addWidget(self.itemTree, 1, 0, 1, 3) + self.label_2 = QtWidgets.QLabel(Form) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 2, 0, 1, 3) + self.formatList = QtWidgets.QListWidget(Form) + self.formatList.setObjectName("formatList") + self.gridLayout.addWidget(self.formatList, 3, 0, 1, 3) + self.exportBtn = QtWidgets.QPushButton(Form) + self.exportBtn.setObjectName("exportBtn") + self.gridLayout.addWidget(self.exportBtn, 6, 1, 1, 1) + self.closeBtn = QtWidgets.QPushButton(Form) + self.closeBtn.setObjectName("closeBtn") + self.gridLayout.addWidget(self.closeBtn, 6, 2, 1, 1) + self.paramTree = ParameterTree(Form) + self.paramTree.setColumnCount(2) + self.paramTree.setObjectName("paramTree") + self.paramTree.headerItem().setText(0, "1") + self.paramTree.header().setVisible(False) + self.gridLayout.addWidget(self.paramTree, 5, 0, 1, 3) + self.label_3 = QtWidgets.QLabel(Form) + self.label_3.setObjectName("label_3") + self.gridLayout.addWidget(self.label_3, 4, 0, 1, 3) + self.copyBtn = QtWidgets.QPushButton(Form) + self.copyBtn.setObjectName("copyBtn") + self.gridLayout.addWidget(self.copyBtn, 6, 0, 1, 1) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Export")) + self.label.setText(_translate("Form", "Item to export:")) + self.label_2.setText(_translate("Form", "Export format")) + self.exportBtn.setText(_translate("Form", "Export")) + self.closeBtn.setText(_translate("Form", "Close")) + self.label_3.setText(_translate("Form", "Export options")) + self.copyBtn.setText(_translate("Form", "Copy")) +from ..parametertree import ParameterTree diff --git a/nmreval/gui_qt/_py/fcreader.py b/nmreval/gui_qt/_py/fcreader.py new file mode 100644 index 0000000..766c641 --- /dev/null +++ b/nmreval/gui_qt/_py/fcreader.py @@ -0,0 +1,196 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/fcreader.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_FCEval_dialog(object): + def setupUi(self, FCEval_dialog): + FCEval_dialog.setObjectName("FCEval_dialog") + FCEval_dialog.resize(457, 697) + self.verticalLayout = QtWidgets.QVBoxLayout(FCEval_dialog) + self.verticalLayout.setContentsMargins(3, 3, 3, 3) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.input_box = QtWidgets.QGroupBox(FCEval_dialog) + self.input_box.setObjectName("input_box") + self.gridLayout_2 = QtWidgets.QGridLayout(self.input_box) + self.gridLayout_2.setContentsMargins(3, 3, 3, 3) + self.gridLayout_2.setSpacing(3) + self.gridLayout_2.setObjectName("gridLayout_2") + self.file_pushbutton = QtWidgets.QPushButton(self.input_box) + self.file_pushbutton.setChecked(False) + self.file_pushbutton.setObjectName("file_pushbutton") + self.gridLayout_2.addWidget(self.file_pushbutton, 0, 0, 1, 1) + self.dir_pushbutton = QtWidgets.QPushButton(self.input_box) + self.dir_pushbutton.setObjectName("dir_pushbutton") + self.gridLayout_2.addWidget(self.dir_pushbutton, 0, 1, 1, 1) + self.listWidget = QtWidgets.QListWidget(self.input_box) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth()) + self.listWidget.setSizePolicy(sizePolicy) + self.listWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.listWidget.setTextElideMode(QtCore.Qt.ElideLeft) + self.listWidget.setObjectName("listWidget") + self.gridLayout_2.addWidget(self.listWidget, 1, 0, 1, 3) + self.overwrite_cb = QtWidgets.QCheckBox(self.input_box) + self.overwrite_cb.setObjectName("overwrite_cb") + self.gridLayout_2.addWidget(self.overwrite_cb, 0, 2, 1, 1) + self.verticalLayout.addWidget(self.input_box) + self.region_box = QtWidgets.QGroupBox(FCEval_dialog) + self.region_box.setCheckable(True) + self.region_box.setObjectName("region_box") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.region_box) + self.horizontalLayout.setContentsMargins(3, 3, 3, 3) + self.horizontalLayout.setSpacing(3) + self.horizontalLayout.setObjectName("horizontalLayout") + self.start_lineedit = QtWidgets.QLineEdit(self.region_box) + self.start_lineedit.setObjectName("start_lineedit") + self.horizontalLayout.addWidget(self.start_lineedit) + self.stop_lineedit = QtWidgets.QLineEdit(self.region_box) + self.stop_lineedit.setObjectName("stop_lineedit") + self.horizontalLayout.addWidget(self.stop_lineedit) + self.verticalLayout.addWidget(self.region_box) + self.fit_box = QtWidgets.QGroupBox(FCEval_dialog) + self.fit_box.setObjectName("fit_box") + self.gridLayout_3 = QtWidgets.QGridLayout(self.fit_box) + self.gridLayout_3.setObjectName("gridLayout_3") + self.label_12 = QtWidgets.QLabel(self.fit_box) + self.label_12.setObjectName("label_12") + self.gridLayout_3.addWidget(self.label_12, 0, 0, 1, 1) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout_3.addItem(spacerItem, 0, 1, 1, 1) + self.kww_checkbox = QtWidgets.QCheckBox(self.fit_box) + self.kww_checkbox.setChecked(True) + self.kww_checkbox.setObjectName("kww_checkbox") + self.gridLayout_3.addWidget(self.kww_checkbox, 0, 2, 1, 1) + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setSpacing(2) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.label_3 = QtWidgets.QLabel(self.fit_box) + self.label_3.setObjectName("label_3") + self.horizontalLayout_3.addWidget(self.label_3) + self.t1_cb = QtWidgets.QCheckBox(self.fit_box) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.t1_cb.sizePolicy().hasHeightForWidth()) + self.t1_cb.setSizePolicy(sizePolicy) + self.t1_cb.setText("") + self.t1_cb.setChecked(True) + self.t1_cb.setObjectName("t1_cb") + self.horizontalLayout_3.addWidget(self.t1_cb) + self.label_4 = QtWidgets.QLabel(self.fit_box) + self.label_4.setObjectName("label_4") + self.horizontalLayout_3.addWidget(self.label_4) + self.beta_cb = QtWidgets.QCheckBox(self.fit_box) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.beta_cb.sizePolicy().hasHeightForWidth()) + self.beta_cb.setSizePolicy(sizePolicy) + self.beta_cb.setChecked(True) + self.beta_cb.setObjectName("beta_cb") + self.horizontalLayout_3.addWidget(self.beta_cb) + self.label_5 = QtWidgets.QLabel(self.fit_box) + self.label_5.setObjectName("label_5") + self.horizontalLayout_3.addWidget(self.label_5) + self.m0_cb = QtWidgets.QCheckBox(self.fit_box) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.m0_cb.sizePolicy().hasHeightForWidth()) + self.m0_cb.setSizePolicy(sizePolicy) + self.m0_cb.setText("") + self.m0_cb.setObjectName("m0_cb") + self.horizontalLayout_3.addWidget(self.m0_cb) + self.label_6 = QtWidgets.QLabel(self.fit_box) + self.label_6.setObjectName("label_6") + self.horizontalLayout_3.addWidget(self.label_6) + self.off_cb = QtWidgets.QCheckBox(self.fit_box) + self.off_cb.setObjectName("off_cb") + self.horizontalLayout_3.addWidget(self.off_cb) + self.gridLayout_3.addLayout(self.horizontalLayout_3, 1, 0, 1, 3) + self.verticalLayout.addWidget(self.fit_box) + self.out_box = QtWidgets.QGroupBox(FCEval_dialog) + self.out_box.setObjectName("out_box") + self.gridLayout = QtWidgets.QGridLayout(self.out_box) + self.gridLayout.setContentsMargins(3, 3, 3, 3) + self.gridLayout.setObjectName("gridLayout") + self.savebutton = QtWidgets.QPushButton(self.out_box) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.savebutton.sizePolicy().hasHeightForWidth()) + self.savebutton.setSizePolicy(sizePolicy) + self.savebutton.setObjectName("savebutton") + self.gridLayout.addWidget(self.savebutton, 0, 1, 1, 1) + self.line = QtWidgets.QFrame(self.out_box) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.gridLayout.addWidget(self.line, 2, 0, 1, 2) + self.graph_comboBox = QtWidgets.QComboBox(self.out_box) + self.graph_comboBox.setObjectName("graph_comboBox") + self.gridLayout.addWidget(self.graph_comboBox, 3, 1, 1, 1) + self.graph_checkbox = QtWidgets.QCheckBox(self.out_box) + self.graph_checkbox.setChecked(True) + self.graph_checkbox.setObjectName("graph_checkbox") + self.gridLayout.addWidget(self.graph_checkbox, 3, 0, 1, 1) + self.label = QtWidgets.QLabel(self.out_box) + self.label.setMaximumSize(QtCore.QSize(16777215, 16777215)) + self.label.setText("") + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 1, 0, 1, 2) + self.label_2 = QtWidgets.QLabel(self.out_box) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1) + self.verticalLayout.addWidget(self.out_box) + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem1) + self.buttonBox = QtWidgets.QDialogButtonBox(FCEval_dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + self.label_12.setBuddy(self.kww_checkbox) + self.label_4.setBuddy(self.t1_cb) + self.label_5.setBuddy(self.beta_cb) + self.label_6.setBuddy(self.m0_cb) + + self.retranslateUi(FCEval_dialog) + self.buttonBox.accepted.connect(FCEval_dialog.accept) + self.buttonBox.rejected.connect(FCEval_dialog.reject) + QtCore.QMetaObject.connectSlotsByName(FCEval_dialog) + + def retranslateUi(self, FCEval_dialog): + _translate = QtCore.QCoreApplication.translate + FCEval_dialog.setWindowTitle(_translate("FCEval_dialog", "FC evaluation")) + self.input_box.setTitle(_translate("FCEval_dialog", "Input")) + self.file_pushbutton.setText(_translate("FCEval_dialog", "Add HDF files...")) + self.dir_pushbutton.setText(_translate("FCEval_dialog", "Add directory...")) + self.overwrite_cb.setText(_translate("FCEval_dialog", "Overwrite prev. data")) + self.region_box.setTitle(_translate("FCEval_dialog", "Evaluate region (empty values default to start/end)")) + self.start_lineedit.setPlaceholderText(_translate("FCEval_dialog", "start pos in µs")) + self.stop_lineedit.setPlaceholderText(_translate("FCEval_dialog", "end pos in µs")) + self.fit_box.setTitle(_translate("FCEval_dialog", "Fit equation")) + self.label_12.setText(_translate("FCEval_dialog", "y = M0 exp[-(x/T1)β] + Off")) + self.kww_checkbox.setToolTip(_translate("FCEval_dialog", "Check to fit a stretched exponential instead of exponential function.")) + self.kww_checkbox.setText(_translate("FCEval_dialog", "Stretched exponential")) + self.label_3.setText(_translate("FCEval_dialog", "Plot:")) + self.label_4.setText(_translate("FCEval_dialog", "T1")) + self.label_5.setText(_translate("FCEval_dialog", "β")) + self.label_6.setText(_translate("FCEval_dialog", "M0")) + self.off_cb.setText(_translate("FCEval_dialog", "Offset")) + self.out_box.setTitle(_translate("FCEval_dialog", "Output")) + self.savebutton.setText(_translate("FCEval_dialog", "Change directory...")) + self.graph_checkbox.setText(_translate("FCEval_dialog", "New graph")) + self.label_2.setText(_translate("FCEval_dialog", "Save location")) diff --git a/nmreval/gui_qt/_py/filedialog.py b/nmreval/gui_qt/_py/filedialog.py new file mode 100644 index 0000000..ade0cd7 --- /dev/null +++ b/nmreval/gui_qt/_py/filedialog.py @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/filedialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_QFileDialog(object): + def setupUi(self, QFileDialog): + QFileDialog.setObjectName("QFileDialog") + QFileDialog.resize(521, 316) + QFileDialog.setSizeGripEnabled(True) + self.gridlayout = QtWidgets.QGridLayout(QFileDialog) + self.gridlayout.setObjectName("gridlayout") + self.lookInLabel = QtWidgets.QLabel(QFileDialog) + self.lookInLabel.setObjectName("lookInLabel") + self.gridlayout.addWidget(self.lookInLabel, 0, 0, 1, 1) + self.hboxlayout = QtWidgets.QHBoxLayout() + self.hboxlayout.setObjectName("hboxlayout") + self.lookInCombo = QFileDialogComboBox(QFileDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lookInCombo.sizePolicy().hasHeightForWidth()) + self.lookInCombo.setSizePolicy(sizePolicy) + self.lookInCombo.setMinimumSize(QtCore.QSize(50, 0)) + self.lookInCombo.setObjectName("lookInCombo") + self.hboxlayout.addWidget(self.lookInCombo) + self.backButton = QtWidgets.QToolButton(QFileDialog) + self.backButton.setObjectName("backButton") + self.hboxlayout.addWidget(self.backButton) + self.forwardButton = QtWidgets.QToolButton(QFileDialog) + self.forwardButton.setObjectName("forwardButton") + self.hboxlayout.addWidget(self.forwardButton) + self.toParentButton = QtWidgets.QToolButton(QFileDialog) + self.toParentButton.setObjectName("toParentButton") + self.hboxlayout.addWidget(self.toParentButton) + self.newFolderButton = QtWidgets.QToolButton(QFileDialog) + self.newFolderButton.setObjectName("newFolderButton") + self.hboxlayout.addWidget(self.newFolderButton) + self.listModeButton = QtWidgets.QToolButton(QFileDialog) + self.listModeButton.setObjectName("listModeButton") + self.hboxlayout.addWidget(self.listModeButton) + self.detailModeButton = QtWidgets.QToolButton(QFileDialog) + self.detailModeButton.setObjectName("detailModeButton") + self.hboxlayout.addWidget(self.detailModeButton) + self.gridlayout.addLayout(self.hboxlayout, 0, 1, 1, 2) + self.splitter = QtWidgets.QSplitter(QFileDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.splitter.sizePolicy().hasHeightForWidth()) + self.splitter.setSizePolicy(sizePolicy) + self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setChildrenCollapsible(False) + self.splitter.setObjectName("splitter") + self.sidebar = QSidebar(self.splitter) + self.sidebar.setObjectName("sidebar") + self.frame = QtWidgets.QFrame(self.splitter) + self.frame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.frame.setObjectName("frame") + self.vboxlayout = QtWidgets.QVBoxLayout(self.frame) + self.vboxlayout.setContentsMargins(0, 0, 0, 0) + self.vboxlayout.setSpacing(0) + self.vboxlayout.setObjectName("vboxlayout") + self.stackedWidget = QtWidgets.QStackedWidget(self.frame) + self.stackedWidget.setObjectName("stackedWidget") + self.page = QtWidgets.QWidget() + self.page.setObjectName("page") + self.vboxlayout1 = QtWidgets.QVBoxLayout(self.page) + self.vboxlayout1.setContentsMargins(0, 0, 0, 0) + self.vboxlayout1.setSpacing(0) + self.vboxlayout1.setObjectName("vboxlayout1") + self.listView = QFileDialogListView(self.page) + self.listView.setObjectName("listView") + self.vboxlayout1.addWidget(self.listView) + self.stackedWidget.addWidget(self.page) + self.page_2 = QtWidgets.QWidget() + self.page_2.setObjectName("page_2") + self.vboxlayout2 = QtWidgets.QVBoxLayout(self.page_2) + self.vboxlayout2.setContentsMargins(0, 0, 0, 0) + self.vboxlayout2.setSpacing(0) + self.vboxlayout2.setObjectName("vboxlayout2") + self.treeView = QFileDialogTreeView(self.page_2) + self.treeView.setObjectName("treeView") + self.vboxlayout2.addWidget(self.treeView) + self.stackedWidget.addWidget(self.page_2) + self.vboxlayout.addWidget(self.stackedWidget) + self.gridlayout.addWidget(self.splitter, 1, 0, 1, 3) + self.fileNameLabel = QtWidgets.QLabel(QFileDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.fileNameLabel.sizePolicy().hasHeightForWidth()) + self.fileNameLabel.setSizePolicy(sizePolicy) + self.fileNameLabel.setMinimumSize(QtCore.QSize(0, 0)) + self.fileNameLabel.setObjectName("fileNameLabel") + self.gridlayout.addWidget(self.fileNameLabel, 2, 0, 1, 1) + self.fileNameEdit = QFileDialogLineEdit(QFileDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.fileNameEdit.sizePolicy().hasHeightForWidth()) + self.fileNameEdit.setSizePolicy(sizePolicy) + self.fileNameEdit.setObjectName("fileNameEdit") + self.gridlayout.addWidget(self.fileNameEdit, 2, 1, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(QFileDialog) + self.buttonBox.setOrientation(QtCore.Qt.Vertical) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridlayout.addWidget(self.buttonBox, 2, 2, 2, 1) + self.fileTypeLabel = QtWidgets.QLabel(QFileDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.fileTypeLabel.sizePolicy().hasHeightForWidth()) + self.fileTypeLabel.setSizePolicy(sizePolicy) + self.fileTypeLabel.setObjectName("fileTypeLabel") + self.gridlayout.addWidget(self.fileTypeLabel, 3, 0, 1, 1) + self.fileTypeCombo = QtWidgets.QComboBox(QFileDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.fileTypeCombo.sizePolicy().hasHeightForWidth()) + self.fileTypeCombo.setSizePolicy(sizePolicy) + self.fileTypeCombo.setObjectName("fileTypeCombo") + self.gridlayout.addWidget(self.fileTypeCombo, 3, 1, 1, 1) + + self.retranslateUi(QFileDialog) + self.stackedWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(QFileDialog) + QFileDialog.setTabOrder(self.lookInCombo, self.backButton) + QFileDialog.setTabOrder(self.backButton, self.forwardButton) + QFileDialog.setTabOrder(self.forwardButton, self.toParentButton) + QFileDialog.setTabOrder(self.toParentButton, self.newFolderButton) + QFileDialog.setTabOrder(self.newFolderButton, self.listModeButton) + QFileDialog.setTabOrder(self.listModeButton, self.detailModeButton) + QFileDialog.setTabOrder(self.detailModeButton, self.sidebar) + QFileDialog.setTabOrder(self.sidebar, self.treeView) + QFileDialog.setTabOrder(self.treeView, self.listView) + QFileDialog.setTabOrder(self.listView, self.fileNameEdit) + QFileDialog.setTabOrder(self.fileNameEdit, self.buttonBox) + QFileDialog.setTabOrder(self.buttonBox, self.fileTypeCombo) + + def retranslateUi(self, QFileDialog): + _translate = QtCore.QCoreApplication.translate + self.lookInLabel.setText(_translate("QFileDialog", "Look in:")) + self.backButton.setToolTip(_translate("QFileDialog", "Back")) + self.backButton.setAccessibleName(_translate("QFileDialog", "Back")) + self.backButton.setAccessibleDescription(_translate("QFileDialog", "Go back")) + self.backButton.setShortcut(_translate("QFileDialog", "Alt+Left")) + self.forwardButton.setToolTip(_translate("QFileDialog", "Forward")) + self.forwardButton.setAccessibleName(_translate("QFileDialog", "Forward")) + self.forwardButton.setAccessibleDescription(_translate("QFileDialog", "Go forward")) + self.forwardButton.setShortcut(_translate("QFileDialog", "Alt+Right")) + self.toParentButton.setToolTip(_translate("QFileDialog", "Parent Directory")) + self.toParentButton.setAccessibleName(_translate("QFileDialog", "Parent Directory")) + self.toParentButton.setAccessibleDescription(_translate("QFileDialog", "Go to the parent directory")) + self.toParentButton.setShortcut(_translate("QFileDialog", "Alt+Up")) + self.newFolderButton.setToolTip(_translate("QFileDialog", "Create New Folder")) + self.newFolderButton.setAccessibleName(_translate("QFileDialog", "Create New Folder")) + self.newFolderButton.setAccessibleDescription(_translate("QFileDialog", "Create a New Folder")) + self.listModeButton.setToolTip(_translate("QFileDialog", "List View")) + self.listModeButton.setAccessibleName(_translate("QFileDialog", "List View")) + self.listModeButton.setAccessibleDescription(_translate("QFileDialog", "Change to list view mode")) + self.detailModeButton.setToolTip(_translate("QFileDialog", "Detail View")) + self.detailModeButton.setAccessibleName(_translate("QFileDialog", "Detail View")) + self.detailModeButton.setAccessibleDescription(_translate("QFileDialog", "Change to detail view mode")) + self.sidebar.setAccessibleName(_translate("QFileDialog", "Sidebar")) + self.sidebar.setAccessibleDescription(_translate("QFileDialog", "List of places and bookmarks")) + self.listView.setAccessibleName(_translate("QFileDialog", "Files")) + self.treeView.setAccessibleName(_translate("QFileDialog", "Files")) + self.fileTypeLabel.setText(_translate("QFileDialog", "Files of type:")) +from private.qfiledialog_p import QFileDialogComboBox, QFileDialogLineEdit, QFileDialogListView, QFileDialogTreeView +from private.qsidebar_p import QSidebar diff --git a/nmreval/gui_qt/_py/fitcreationdialog.py b/nmreval/gui_qt/_py/fitcreationdialog.py new file mode 100644 index 0000000..f2abd98 --- /dev/null +++ b/nmreval/gui_qt/_py/fitcreationdialog.py @@ -0,0 +1,189 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/fitcreationdialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(614, 776) + self.verticalLayout_5 = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout_5.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_5.setSpacing(3) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.groupBox = QtWidgets.QGroupBox(Dialog) + self.groupBox.setCheckable(True) + self.groupBox.setChecked(False) + self.groupBox.setObjectName("groupBox") + self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.groupBox) + self.verticalLayout_7.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_7.setSpacing(3) + self.verticalLayout_7.setObjectName("verticalLayout_7") + self.widget_2 = QtWidgets.QWidget(self.groupBox) + self.widget_2.setObjectName("widget_2") + self.gridLayout_2 = QtWidgets.QGridLayout(self.widget_2) + self.gridLayout_2.setContentsMargins(0, 0, 0, 0) + self.gridLayout_2.setSpacing(3) + self.gridLayout_2.setObjectName("gridLayout_2") + self.name_lineedit = QtWidgets.QLineEdit(self.widget_2) + self.name_lineedit.setObjectName("name_lineedit") + self.gridLayout_2.addWidget(self.name_lineedit, 0, 1, 1, 1) + self.group_lineedit = QtWidgets.QLineEdit(self.widget_2) + self.group_lineedit.setObjectName("group_lineedit") + self.gridLayout_2.addWidget(self.group_lineedit, 1, 1, 1, 1) + self.group_label = QtWidgets.QLabel(self.widget_2) + self.group_label.setObjectName("group_label") + self.gridLayout_2.addWidget(self.group_label, 1, 0, 1, 1) + self.name_label = QtWidgets.QLabel(self.widget_2) + self.name_label.setObjectName("name_label") + self.gridLayout_2.addWidget(self.name_label, 0, 0, 1, 1) + self.lineEdit = QtWidgets.QLineEdit(self.widget_2) + self.lineEdit.setObjectName("lineEdit") + self.gridLayout_2.addWidget(self.lineEdit, 2, 1, 1, 1) + self.label_2 = QtWidgets.QLabel(self.widget_2) + self.label_2.setObjectName("label_2") + self.gridLayout_2.addWidget(self.label_2, 2, 0, 1, 1) + self.verticalLayout_7.addWidget(self.widget_2) + self.verticalLayout_5.addWidget(self.groupBox) + self.groupBox_2 = QtWidgets.QGroupBox(Dialog) + self.groupBox_2.setCheckable(True) + self.groupBox_2.setChecked(False) + self.groupBox_2.setObjectName("groupBox_2") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox_2) + self.verticalLayout_2.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_2.setSpacing(3) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.widget_3 = QtWidgets.QWidget(self.groupBox_2) + self.widget_3.setObjectName("widget_3") + self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.widget_3) + self.verticalLayout_8.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_8.setSpacing(3) + self.verticalLayout_8.setObjectName("verticalLayout_8") + self.tableWidget = QtWidgets.QTableWidget(self.widget_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.tableWidget.sizePolicy().hasHeightForWidth()) + self.tableWidget.setSizePolicy(sizePolicy) + self.tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget.setColumnCount(4) + self.tableWidget.setObjectName("tableWidget") + self.tableWidget.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(2, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(3, item) + self.verticalLayout_8.addWidget(self.tableWidget) + self.parameter_button = QtWidgets.QToolButton(self.widget_3) + self.parameter_button.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + self.parameter_button.setAutoRaise(False) + self.parameter_button.setArrowType(QtCore.Qt.RightArrow) + self.parameter_button.setObjectName("parameter_button") + self.verticalLayout_8.addWidget(self.parameter_button) + self.verticalLayout_2.addWidget(self.widget_3) + self.verticalLayout_5.addWidget(self.groupBox_2) + self.groupBox_3 = QtWidgets.QGroupBox(Dialog) + self.groupBox_3.setCheckable(True) + self.groupBox_3.setChecked(False) + self.groupBox_3.setObjectName("groupBox_3") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox_3) + self.verticalLayout_3.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_3.setSpacing(3) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.widget = QtWidgets.QWidget(self.groupBox_3) + self.widget.setObjectName("widget") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.widget) + self.verticalLayout_6.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_6.setSpacing(3) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.use_nuclei = QtWidgets.QCheckBox(self.widget) + self.use_nuclei.setObjectName("use_nuclei") + self.verticalLayout_6.addWidget(self.use_nuclei) + self.tabWidget = QtWidgets.QTabWidget(self.widget) + self.tabWidget.setTabPosition(QtWidgets.QTabWidget.West) + self.tabWidget.setTabsClosable(True) + self.tabWidget.setObjectName("tabWidget") + self.verticalLayout_6.addWidget(self.tabWidget) + self.selection_button = QtWidgets.QToolButton(self.widget) + self.selection_button.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + self.selection_button.setArrowType(QtCore.Qt.RightArrow) + self.selection_button.setObjectName("selection_button") + self.verticalLayout_6.addWidget(self.selection_button) + self.verticalLayout_3.addWidget(self.widget) + self.verticalLayout_5.addWidget(self.groupBox_3) + self.groupBox_4 = QtWidgets.QGroupBox(Dialog) + self.groupBox_4.setCheckable(True) + self.groupBox_4.setChecked(False) + self.groupBox_4.setObjectName("groupBox_4") + self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox_4) + self.verticalLayout.setObjectName("verticalLayout") + self.namespace_widget = QNamespaceWidget(self.groupBox_4) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.namespace_widget.sizePolicy().hasHeightForWidth()) + self.namespace_widget.setSizePolicy(sizePolicy) + self.namespace_widget.setObjectName("namespace_widget") + self.verticalLayout.addWidget(self.namespace_widget) + self.verticalLayout_5.addWidget(self.groupBox_4) + self.frame_4 = QtWidgets.QFrame(Dialog) + self.frame_4.setObjectName("frame_4") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.frame_4) + self.verticalLayout_4.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_4.setSpacing(3) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.label = QtWidgets.QLabel(self.frame_4) + self.label.setObjectName("label") + self.verticalLayout_4.addWidget(self.label) + self.plainTextEdit = CodeEditor(self.frame_4) + self.plainTextEdit.setObjectName("plainTextEdit") + self.verticalLayout_4.addWidget(self.plainTextEdit) + self.verticalLayout_5.addWidget(self.frame_4) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout_5.addWidget(self.buttonBox) + self.name_label.setBuddy(self.name_lineedit) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Dialog")) + self.groupBox.setTitle(_translate("Dialog", "Description")) + self.group_label.setText(_translate("Dialog", "Group")) + self.name_label.setText(_translate("Dialog", "Name")) + self.label_2.setText(_translate("Dialog", "Equation")) + self.groupBox_2.setTitle(_translate("Dialog", "Variables")) + item = self.tableWidget.horizontalHeaderItem(0) + item.setText(_translate("Dialog", "Variable")) + item = self.tableWidget.horizontalHeaderItem(1) + item.setText(_translate("Dialog", "Name")) + item = self.tableWidget.horizontalHeaderItem(2) + item.setText(_translate("Dialog", "Lower bound")) + item = self.tableWidget.horizontalHeaderItem(3) + item.setText(_translate("Dialog", "Upper bound")) + self.parameter_button.setText(_translate("Dialog", "Add parameter")) + self.groupBox_3.setTitle(_translate("Dialog", "Multiple choice part")) + self.use_nuclei.setText(_translate("Dialog", "Add gyromagnetic ratios")) + self.selection_button.setText(_translate("Dialog", "Add selection")) + self.groupBox_4.setTitle(_translate("Dialog", "Available namespace")) + self.label.setText(_translate("Dialog", "Function y = func(x)")) +from ..lib.codeeditor import CodeEditor +from ..lib.namespace import QNamespaceWidget diff --git a/nmreval/gui_qt/_py/fitdialog.py b/nmreval/gui_qt/_py/fitdialog.py new file mode 100644 index 0000000..8ed9207 --- /dev/null +++ b/nmreval/gui_qt/_py/fitdialog.py @@ -0,0 +1,159 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/fitdialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_FitDialog(object): + def setupUi(self, FitDialog): + FitDialog.setObjectName("FitDialog") + FitDialog.resize(347, 710) + self.verticalLayout = QtWidgets.QVBoxLayout(FitDialog) + self.verticalLayout.setContentsMargins(3, 3, 3, 3) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.scrollArea = QtWidgets.QScrollArea(FitDialog) + self.scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame) + self.scrollArea.setFrameShadow(QtWidgets.QFrame.Plain) + self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.scrollArea.setWidgetResizable(True) + self.scrollArea.setObjectName("scrollArea") + self.scrollAreaWidgetContents_2 = QtWidgets.QWidget() + self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 341, 665)) + self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2") + self.gridLayout_2 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_2) + self.gridLayout_2.setContentsMargins(0, 0, 0, -1) + self.gridLayout_2.setSpacing(3) + self.gridLayout_2.setObjectName("gridLayout_2") + self.weight_combobox = QtWidgets.QComboBox(self.scrollAreaWidgetContents_2) + self.weight_combobox.setObjectName("weight_combobox") + self.weight_combobox.addItem("") + self.weight_combobox.addItem("") + self.weight_combobox.addItem("") + self.weight_combobox.addItem("") + self.weight_combobox.addItem("") + self.gridLayout_2.addWidget(self.weight_combobox, 6, 1, 1, 1) + self.newmodel_button = QtWidgets.QPushButton(self.scrollAreaWidgetContents_2) + self.newmodel_button.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.newmodel_button.sizePolicy().hasHeightForWidth()) + self.newmodel_button.setSizePolicy(sizePolicy) + self.newmodel_button.setObjectName("newmodel_button") + self.gridLayout_2.addWidget(self.newmodel_button, 2, 0, 1, 1) + self.deletemodel_button = QtWidgets.QPushButton(self.scrollAreaWidgetContents_2) + self.deletemodel_button.setEnabled(False) + self.deletemodel_button.setObjectName("deletemodel_button") + self.gridLayout_2.addWidget(self.deletemodel_button, 2, 1, 1, 1) + self.label_3 = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) + self.label_3.setObjectName("label_3") + self.gridLayout_2.addWidget(self.label_3, 6, 0, 1, 1) + self.stackedWidget = QtWidgets.QStackedWidget(self.scrollAreaWidgetContents_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.stackedWidget.sizePolicy().hasHeightForWidth()) + self.stackedWidget.setSizePolicy(sizePolicy) + self.stackedWidget.setObjectName("stackedWidget") + self.page = QtWidgets.QWidget() + self.page.setObjectName("page") + self.stackedWidget.addWidget(self.page) + self.gridLayout_2.addWidget(self.stackedWidget, 1, 0, 1, 2) + self.functionwidget = QFunctionWidget(self.scrollAreaWidgetContents_2) + self.functionwidget.setObjectName("functionwidget") + self.gridLayout_2.addWidget(self.functionwidget, 0, 0, 1, 2) + self.model_frame = QtWidgets.QFrame(self.scrollAreaWidgetContents_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.model_frame.sizePolicy().hasHeightForWidth()) + self.model_frame.setSizePolicy(sizePolicy) + self.model_frame.setObjectName("model_frame") + self.gridLayout = QtWidgets.QGridLayout(self.model_frame) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setHorizontalSpacing(0) + self.gridLayout.setVerticalSpacing(1) + self.gridLayout.setObjectName("gridLayout") + self.show_combobox = QtWidgets.QComboBox(self.model_frame) + self.show_combobox.setObjectName("show_combobox") + self.show_combobox.addItem("") + self.gridLayout.addWidget(self.show_combobox, 1, 1, 1, 1) + self.default_combobox = QtWidgets.QComboBox(self.model_frame) + self.default_combobox.setObjectName("default_combobox") + self.default_combobox.addItem("") + self.gridLayout.addWidget(self.default_combobox, 0, 1, 1, 1) + self.label_2 = QtWidgets.QLabel(self.model_frame) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) + self.label = QtWidgets.QLabel(self.model_frame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + self.gridLayout_2.addWidget(self.model_frame, 3, 0, 1, 2) + self.data_widget = ExpandableWidget(self.scrollAreaWidgetContents_2) + self.data_widget.setMinimumSize(QtCore.QSize(0, 24)) + self.data_widget.setObjectName("data_widget") + self.gridLayout_2.addWidget(self.data_widget, 5, 0, 1, 2) + self.scrollArea.setWidget(self.scrollAreaWidgetContents_2) + self.verticalLayout.addWidget(self.scrollArea) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout.setSpacing(3) + self.horizontalLayout.setObjectName("horizontalLayout") + self.fit_button = QtWidgets.QPushButton(FitDialog) + self.fit_button.setStyleSheet("font-weight: bold") + self.fit_button.setObjectName("fit_button") + self.horizontalLayout.addWidget(self.fit_button) + self.abort_button = QtWidgets.QPushButton(FitDialog) + self.abort_button.setStyleSheet("font-weight: bold") + self.abort_button.setObjectName("abort_button") + self.horizontalLayout.addWidget(self.abort_button) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.preview_checkbox = QtWidgets.QCheckBox(FitDialog) + self.preview_checkbox.setObjectName("preview_checkbox") + self.horizontalLayout.addWidget(self.preview_checkbox) + self.preview_button = QtWidgets.QPushButton(FitDialog) + self.preview_button.setCheckable(False) + self.preview_button.setChecked(False) + self.preview_button.setFlat(False) + self.preview_button.setObjectName("preview_button") + self.horizontalLayout.addWidget(self.preview_button) + self.verticalLayout.addLayout(self.horizontalLayout) + + self.retranslateUi(FitDialog) + self.stackedWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(FitDialog) + + def retranslateUi(self, FitDialog): + _translate = QtCore.QCoreApplication.translate + FitDialog.setWindowTitle(_translate("FitDialog", "Form")) + self.weight_combobox.setItemText(0, _translate("FitDialog", "None")) + self.weight_combobox.setItemText(1, _translate("FitDialog", "y")) + self.weight_combobox.setItemText(2, _translate("FitDialog", "y²")) + self.weight_combobox.setItemText(3, _translate("FitDialog", "Δy")) + self.weight_combobox.setItemText(4, _translate("FitDialog", "log(y)")) + self.newmodel_button.setText(_translate("FitDialog", "New model")) + self.deletemodel_button.setText(_translate("FitDialog", "Delete model")) + self.label_3.setText(_translate("FitDialog", "Weight")) + self.show_combobox.setItemText(0, _translate("FitDialog", "Model a")) + self.default_combobox.setItemText(0, _translate("FitDialog", "Model a")) + self.label_2.setText(_translate("FitDialog", "Show model")) + self.label.setText(_translate("FitDialog", "Default")) + self.fit_button.setText(_translate("FitDialog", "Run fit!!!")) + self.abort_button.setText(_translate("FitDialog", "Abort")) + self.preview_checkbox.setText(_translate("FitDialog", "Preview")) + self.preview_button.setText(_translate("FitDialog", "Update")) +from ..fit.fitfunction import QFunctionWidget +from ..lib.expandablewidget import ExpandableWidget diff --git a/nmreval/gui_qt/_py/fitdialog_window.py b/nmreval/gui_qt/_py/fitdialog_window.py new file mode 100644 index 0000000..ad342de --- /dev/null +++ b/nmreval/gui_qt/_py/fitdialog_window.py @@ -0,0 +1,285 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/fitdialog_window.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_FitDialog(object): + def setupUi(self, FitDialog): + FitDialog.setObjectName("FitDialog") + FitDialog.setWindowModality(QtCore.Qt.ApplicationModal) + FitDialog.resize(828, 827) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/logo.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + FitDialog.setWindowIcon(icon) + self.centralwidget = QtWidgets.QWidget(FitDialog) + self.centralwidget.setObjectName("centralwidget") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.splitter = QtWidgets.QSplitter(self.centralwidget) + self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setObjectName("splitter") + self.widget_2 = QtWidgets.QWidget(self.splitter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widget_2.sizePolicy().hasHeightForWidth()) + self.widget_2.setSizePolicy(sizePolicy) + self.widget_2.setObjectName("widget_2") + self.gridLayout_3 = QtWidgets.QGridLayout(self.widget_2) + self.gridLayout_3.setContentsMargins(3, 3, 3, 3) + self.gridLayout_3.setSpacing(3) + self.gridLayout_3.setObjectName("gridLayout_3") + self.label_3 = QtWidgets.QLabel(self.widget_2) + self.label_3.setObjectName("label_3") + self.gridLayout_3.addWidget(self.label_3, 3, 0, 1, 1) + self.weight_combobox = QtWidgets.QComboBox(self.widget_2) + self.weight_combobox.setObjectName("weight_combobox") + self.weight_combobox.addItem("") + self.weight_combobox.addItem("") + self.weight_combobox.addItem("") + self.weight_combobox.addItem("") + self.weight_combobox.addItem("") + self.gridLayout_3.addWidget(self.weight_combobox, 3, 1, 1, 1) + self.line = QtWidgets.QFrame(self.widget_2) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.gridLayout_3.addWidget(self.line, 2, 0, 1, 2) + self.tableWidget = QtWidgets.QTableWidget(self.widget_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.tableWidget.sizePolicy().hasHeightForWidth()) + self.tableWidget.setSizePolicy(sizePolicy) + self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget.setShowGrid(False) + self.tableWidget.setGridStyle(QtCore.Qt.NoPen) + self.tableWidget.setColumnCount(2) + self.tableWidget.setObjectName("tableWidget") + self.tableWidget.setRowCount(0) + self.tableWidget.horizontalHeader().setVisible(False) + self.tableWidget.horizontalHeader().setStretchLastSection(True) + self.tableWidget.verticalHeader().setVisible(False) + self.gridLayout_3.addWidget(self.tableWidget, 0, 0, 1, 2) + self.horizontalFrame = QtWidgets.QFrame(self.widget_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.horizontalFrame.sizePolicy().hasHeightForWidth()) + self.horizontalFrame.setSizePolicy(sizePolicy) + self.horizontalFrame.setObjectName("horizontalFrame") + self.gridLayout = QtWidgets.QGridLayout(self.horizontalFrame) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setHorizontalSpacing(0) + self.gridLayout.setVerticalSpacing(1) + self.gridLayout.setObjectName("gridLayout") + self.show_combobox = QtWidgets.QComboBox(self.horizontalFrame) + self.show_combobox.setObjectName("show_combobox") + self.show_combobox.addItem("") + self.gridLayout.addWidget(self.show_combobox, 1, 1, 1, 1) + self.label_2 = QtWidgets.QLabel(self.horizontalFrame) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) + self.default_combobox = QtWidgets.QComboBox(self.horizontalFrame) + self.default_combobox.setObjectName("default_combobox") + self.default_combobox.addItem("") + self.gridLayout.addWidget(self.default_combobox, 0, 1, 1, 1) + self.label = QtWidgets.QLabel(self.horizontalFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + self.gridLayout_3.addWidget(self.horizontalFrame, 1, 0, 1, 2) + self.middle_widget = QtWidgets.QWidget(self.splitter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.middle_widget.sizePolicy().hasHeightForWidth()) + self.middle_widget.setSizePolicy(sizePolicy) + self.middle_widget.setObjectName("middle_widget") + self.gridLayout_2 = QtWidgets.QGridLayout(self.middle_widget) + self.gridLayout_2.setContentsMargins(3, 3, 3, 3) + self.gridLayout_2.setSpacing(3) + self.gridLayout_2.setObjectName("gridLayout_2") + self.newmodel_button = QtWidgets.QPushButton(self.middle_widget) + self.newmodel_button.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.newmodel_button.sizePolicy().hasHeightForWidth()) + self.newmodel_button.setSizePolicy(sizePolicy) + self.newmodel_button.setObjectName("newmodel_button") + self.gridLayout_2.addWidget(self.newmodel_button, 2, 0, 1, 1) + self.functionwidget = FunctionSelectionWidget(self.middle_widget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.functionwidget.sizePolicy().hasHeightForWidth()) + self.functionwidget.setSizePolicy(sizePolicy) + self.functionwidget.setObjectName("functionwidget") + self.gridLayout_2.addWidget(self.functionwidget, 0, 0, 1, 2) + self.deletemodel_button = QtWidgets.QPushButton(self.middle_widget) + self.deletemodel_button.setEnabled(False) + self.deletemodel_button.setObjectName("deletemodel_button") + self.gridLayout_2.addWidget(self.deletemodel_button, 2, 1, 1, 1) + self.stackedWidget = QtWidgets.QStackedWidget(self.middle_widget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.stackedWidget.sizePolicy().hasHeightForWidth()) + self.stackedWidget.setSizePolicy(sizePolicy) + self.stackedWidget.setObjectName("stackedWidget") + self.page = QtWidgets.QWidget() + self.page.setObjectName("page") + self.stackedWidget.addWidget(self.page) + self.page_2 = QtWidgets.QWidget() + self.page_2.setObjectName("page_2") + self.stackedWidget.addWidget(self.page_2) + self.gridLayout_2.addWidget(self.stackedWidget, 1, 0, 1, 2) + self.verticalLayout_2.addWidget(self.splitter) + self.frame_4 = QtWidgets.QFrame(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame_4.sizePolicy().hasHeightForWidth()) + self.frame_4.setSizePolicy(sizePolicy) + self.frame_4.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.frame_4.setFrameShadow(QtWidgets.QFrame.Raised) + self.frame_4.setLineWidth(2) + self.frame_4.setMidLineWidth(0) + self.frame_4.setObjectName("frame_4") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame_4) + self.horizontalLayout_2.setContentsMargins(3, 3, 3, 3) + self.horizontalLayout_2.setSpacing(3) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem) + self.fit_button = QtWidgets.QPushButton(self.frame_4) + self.fit_button.setObjectName("fit_button") + self.horizontalLayout_2.addWidget(self.fit_button) + self.abort_button = QtWidgets.QPushButton(self.frame_4) + self.abort_button.setObjectName("abort_button") + self.horizontalLayout_2.addWidget(self.abort_button) + self.preview_button = QtWidgets.QPushButton(self.frame_4) + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/fit_preview.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.preview_button.setIcon(icon1) + self.preview_button.setCheckable(True) + self.preview_button.setObjectName("preview_button") + self.horizontalLayout_2.addWidget(self.preview_button) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem1) + self.verticalLayout_2.addWidget(self.frame_4) + FitDialog.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(FitDialog) + self.menubar.setGeometry(QtCore.QRect(0, 0, 828, 30)) + self.menubar.setObjectName("menubar") + self.menuOptions = QtWidgets.QMenu(self.menubar) + self.menuOptions.setObjectName("menuOptions") + self.menuMethod = QtWidgets.QMenu(self.menuOptions) + self.menuMethod.setObjectName("menuMethod") + self.menuLimits = QtWidgets.QMenu(self.menuOptions) + self.menuLimits.setObjectName("menuLimits") + self.menuHelp = QtWidgets.QMenu(self.menubar) + self.menuHelp.setObjectName("menuHelp") + self.menuUser = QtWidgets.QMenu(self.menubar) + self.menuUser.setObjectName("menuUser") + FitDialog.setMenuBar(self.menubar) + self.statusBar = QtWidgets.QStatusBar(FitDialog) + self.statusBar.setObjectName("statusBar") + FitDialog.setStatusBar(self.statusBar) + self.action_nm = QtWidgets.QAction(FitDialog) + self.action_nm.setCheckable(True) + self.action_nm.setObjectName("action_nm") + self.action_odr = QtWidgets.QAction(FitDialog) + self.action_odr.setCheckable(True) + self.action_odr.setObjectName("action_odr") + self.action_lm = QtWidgets.QAction(FitDialog) + self.action_lm.setCheckable(True) + self.action_lm.setChecked(True) + self.action_lm.setObjectName("action_lm") + self.actionHelp = QtWidgets.QAction(FitDialog) + self.actionHelp.setObjectName("actionHelp") + self.actionOpen_editor = QtWidgets.QAction(FitDialog) + self.actionOpen_editor.setObjectName("actionOpen_editor") + self.actionPreview_points = QtWidgets.QAction(FitDialog) + self.actionPreview_points.setObjectName("actionPreview_points") + self.actionSave_current_model = QtWidgets.QAction(FitDialog) + self.actionSave_current_model.setObjectName("actionSave_current_model") + self.action_no_range = QtWidgets.QAction(FitDialog) + self.action_no_range.setCheckable(True) + self.action_no_range.setObjectName("action_no_range") + self.action_x_range = QtWidgets.QAction(FitDialog) + self.action_x_range.setCheckable(True) + self.action_x_range.setChecked(True) + self.action_x_range.setObjectName("action_x_range") + self.action_custom_range = QtWidgets.QAction(FitDialog) + self.action_custom_range.setCheckable(True) + self.action_custom_range.setObjectName("action_custom_range") + self.menuMethod.addAction(self.action_lm) + self.menuMethod.addAction(self.action_nm) + self.menuMethod.addAction(self.action_odr) + self.menuLimits.addAction(self.action_no_range) + self.menuLimits.addAction(self.action_x_range) + self.menuLimits.addAction(self.action_custom_range) + self.menuOptions.addAction(self.menuMethod.menuAction()) + self.menuOptions.addAction(self.menuLimits.menuAction()) + self.menuOptions.addSeparator() + self.menuOptions.addAction(self.actionPreview_points) + self.menuHelp.addAction(self.actionHelp) + self.menuUser.addAction(self.actionOpen_editor) + self.menuUser.addAction(self.actionSave_current_model) + self.menubar.addAction(self.menuOptions.menuAction()) + self.menubar.addAction(self.menuUser.menuAction()) + self.menubar.addAction(self.menuHelp.menuAction()) + + self.retranslateUi(FitDialog) + QtCore.QMetaObject.connectSlotsByName(FitDialog) + + def retranslateUi(self, FitDialog): + _translate = QtCore.QCoreApplication.translate + FitDialog.setWindowTitle(_translate("FitDialog", "One must imagine Sisyphus happy.")) + self.label_3.setText(_translate("FitDialog", "Weight")) + self.weight_combobox.setItemText(0, _translate("FitDialog", "None")) + self.weight_combobox.setItemText(1, _translate("FitDialog", "y")) + self.weight_combobox.setItemText(2, _translate("FitDialog", "y²")) + self.weight_combobox.setItemText(3, _translate("FitDialog", "Δy")) + self.weight_combobox.setItemText(4, _translate("FitDialog", "log(y)")) + self.show_combobox.setItemText(0, _translate("FitDialog", "Model a")) + self.label_2.setText(_translate("FitDialog", "Show model")) + self.default_combobox.setItemText(0, _translate("FitDialog", "Model a")) + self.label.setText(_translate("FitDialog", "Default")) + self.newmodel_button.setText(_translate("FitDialog", "New model")) + self.deletemodel_button.setText(_translate("FitDialog", "Delete model")) + self.fit_button.setText(_translate("FitDialog", "Run fit!!!")) + self.abort_button.setText(_translate("FitDialog", "Abort")) + self.preview_button.setText(_translate("FitDialog", "Preview")) + self.menuOptions.setTitle(_translate("FitDialog", "Options")) + self.menuMethod.setTitle(_translate("FitDialog", "Method")) + self.menuLimits.setTitle(_translate("FitDialog", "Limits")) + self.menuHelp.setTitle(_translate("FitDialog", "Help")) + self.menuUser.setTitle(_translate("FitDialog", "User")) + self.action_nm.setText(_translate("FitDialog", "Nelder-Mead")) + self.action_odr.setText(_translate("FitDialog", "ODR")) + self.action_lm.setText(_translate("FitDialog", "Default stuff")) + self.actionHelp.setText(_translate("FitDialog", "Help!")) + self.actionOpen_editor.setText(_translate("FitDialog", "Open editor...")) + self.actionPreview_points.setText(_translate("FitDialog", "Preview points...")) + self.actionSave_current_model.setText(_translate("FitDialog", "Save current model...")) + self.action_no_range.setText(_translate("FitDialog", "None")) + self.action_x_range.setText(_translate("FitDialog", "Visible x range")) + self.action_custom_range.setText(_translate("FitDialog", "Custom...")) +from ..fit.function_selection import FunctionSelectionWidget +import images_rc diff --git a/nmreval/gui_qt/_py/fitfunctionwidget.py b/nmreval/gui_qt/_py/fitfunctionwidget.py new file mode 100644 index 0000000..3035f2f --- /dev/null +++ b/nmreval/gui_qt/_py/fitfunctionwidget.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/fitfunctionwidget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(314, 232) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth()) + Form.setSizePolicy(sizePolicy) + self.gridLayout = QtWidgets.QGridLayout(Form) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setSpacing(3) + self.gridLayout.setObjectName("gridLayout") + self.widget = ExpandableWidget(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth()) + self.widget.setSizePolicy(sizePolicy) + self.widget.setObjectName("widget") + self.gridLayout.addWidget(self.widget, 4, 0, 1, 2) + self.complex_widget = QtWidgets.QWidget(Form) + self.complex_widget.setObjectName("complex_widget") + self.gridLayout_2 = QtWidgets.QGridLayout(self.complex_widget) + self.gridLayout_2.setContentsMargins(0, 0, 0, 0) + self.gridLayout_2.setObjectName("gridLayout_2") + self.label_2 = QtWidgets.QLabel(self.complex_widget) + self.label_2.setObjectName("label_2") + self.gridLayout_2.addWidget(self.label_2, 1, 0, 1, 1) + self.complex_comboBox = QtWidgets.QComboBox(self.complex_widget) + self.complex_comboBox.setObjectName("complex_comboBox") + self.complex_comboBox.addItem("") + self.complex_comboBox.addItem("") + self.complex_comboBox.addItem("") + self.gridLayout_2.addWidget(self.complex_comboBox, 1, 1, 1, 1) + self.label = QtWidgets.QLabel(self.complex_widget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setObjectName("label") + self.gridLayout_2.addWidget(self.label, 0, 0, 1, 2) + self.gridLayout.addWidget(self.complex_widget, 5, 0, 1, 2) + self.use_function_button = QtWidgets.QToolButton(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.use_function_button.sizePolicy().hasHeightForWidth()) + self.use_function_button.setSizePolicy(sizePolicy) + self.use_function_button.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + self.use_function_button.setAutoRaise(False) + self.use_function_button.setArrowType(QtCore.Qt.RightArrow) + self.use_function_button.setObjectName("use_function_button") + self.gridLayout.addWidget(self.use_function_button, 3, 1, 1, 1) + self.fitcomboBox = QtWidgets.QComboBox(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.fitcomboBox.sizePolicy().hasHeightForWidth()) + self.fitcomboBox.setSizePolicy(sizePolicy) + self.fitcomboBox.setObjectName("fitcomboBox") + self.gridLayout.addWidget(self.fitcomboBox, 1, 0, 1, 2) + self.typecomboBox = QtWidgets.QComboBox(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.typecomboBox.sizePolicy().hasHeightForWidth()) + self.typecomboBox.setSizePolicy(sizePolicy) + self.typecomboBox.setObjectName("typecomboBox") + self.gridLayout.addWidget(self.typecomboBox, 0, 0, 1, 2) + self.fitequation = QtWidgets.QLabel(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.fitequation.sizePolicy().hasHeightForWidth()) + self.fitequation.setSizePolicy(sizePolicy) + self.fitequation.setWordWrap(True) + self.fitequation.setObjectName("fitequation") + self.gridLayout.addWidget(self.fitequation, 2, 0, 1, 2) + self.operator_combobox = QtWidgets.QComboBox(Form) + self.operator_combobox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) + self.operator_combobox.setFrame(True) + self.operator_combobox.setObjectName("operator_combobox") + self.operator_combobox.addItem("") + self.operator_combobox.addItem("") + self.operator_combobox.addItem("") + self.operator_combobox.addItem("") + self.gridLayout.addWidget(self.operator_combobox, 3, 0, 1, 1) + self.use_combobox = QtWidgets.QComboBox(Form) + self.use_combobox.setObjectName("use_combobox") + self.gridLayout.addWidget(self.use_combobox, 6, 0, 1, 2) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label_2.setText(_translate("Form", "Select part to fit")) + self.complex_comboBox.setItemText(0, _translate("Form", "Complex")) + self.complex_comboBox.setItemText(1, _translate("Form", "Real")) + self.complex_comboBox.setItemText(2, _translate("Form", "Imaginary")) + self.label.setText(_translate("Form", "Complex function found")) + self.use_function_button.setText(_translate("Form", "Use")) + self.fitequation.setText(_translate("Form", "Equation")) + self.operator_combobox.setItemText(0, _translate("Form", "Add")) + self.operator_combobox.setItemText(1, _translate("Form", "Multiply")) + self.operator_combobox.setItemText(2, _translate("Form", "Subtract")) + self.operator_combobox.setItemText(3, _translate("Form", "Divide by")) +from ..lib.expandablewidget import ExpandableWidget diff --git a/nmreval/gui_qt/_py/fitfuncwidget.py b/nmreval/gui_qt/_py/fitfuncwidget.py new file mode 100644 index 0000000..38fa341 --- /dev/null +++ b/nmreval/gui_qt/_py/fitfuncwidget.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/fitfuncwidget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_FormFit(object): + def setupUi(self, FormFit): + FormFit.setObjectName("FormFit") + FormFit.resize(292, 477) + self.verticalLayout = QtWidgets.QVBoxLayout(FormFit) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.tabWidget = QtWidgets.QTabWidget(FormFit) + self.tabWidget.setObjectName("tabWidget") + self.general_tab = QtWidgets.QWidget() + self.general_tab.setObjectName("general_tab") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.general_tab) + self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_2.setSpacing(0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.scrollArea = QtWidgets.QScrollArea(self.general_tab) + self.scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame) + self.scrollArea.setFrameShadow(QtWidgets.QFrame.Plain) + self.scrollArea.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents) + self.scrollArea.setWidgetResizable(True) + self.scrollArea.setObjectName("scrollArea") + self.scrollwidget = QtWidgets.QWidget() + self.scrollwidget.setGeometry(QtCore.QRect(0, 0, 284, 442)) + self.scrollwidget.setObjectName("scrollwidget") + self.scrollArea.setWidget(self.scrollwidget) + self.verticalLayout_2.addWidget(self.scrollArea) + self.tabWidget.addTab(self.general_tab, "") + self.data_tab = QtWidgets.QWidget() + self.data_tab.setObjectName("data_tab") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.data_tab) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.comboBox = QtWidgets.QComboBox(self.data_tab) + self.comboBox.setObjectName("comboBox") + self.verticalLayout_3.addWidget(self.comboBox) + self.scrollArea2 = QtWidgets.QScrollArea(self.data_tab) + self.scrollArea2.setFrameShape(QtWidgets.QFrame.NoFrame) + self.scrollArea2.setFrameShadow(QtWidgets.QFrame.Plain) + self.scrollArea2.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents) + self.scrollArea2.setWidgetResizable(True) + self.scrollArea2.setObjectName("scrollArea2") + self.scrollwidget2 = QtWidgets.QWidget() + self.scrollwidget2.setGeometry(QtCore.QRect(0, 0, 272, 357)) + self.scrollwidget2.setObjectName("scrollwidget2") + self.scrollArea2.setWidget(self.scrollwidget2) + self.verticalLayout_3.addWidget(self.scrollArea2) + self.tabWidget.addTab(self.data_tab, "") + self.verticalLayout.addWidget(self.tabWidget) + + self.retranslateUi(FormFit) + self.tabWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(FormFit) + + def retranslateUi(self, FormFit): + _translate = QtCore.QCoreApplication.translate + FormFit.setWindowTitle(_translate("FormFit", "Form")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.general_tab), _translate("FormFit", "General settings")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.data_tab), _translate("FormFit", "Data parameter")) diff --git a/nmreval/gui_qt/_py/fitfuncwidget_old.py b/nmreval/gui_qt/_py/fitfuncwidget_old.py new file mode 100644 index 0000000..e949870 --- /dev/null +++ b/nmreval/gui_qt/_py/fitfuncwidget_old.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/fitfuncwidget_old.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_FormFit(object): + def setupUi(self, FormFit): + FormFit.setObjectName("FormFit") + FormFit.resize(402, 523) + self.verticalLayout = QtWidgets.QVBoxLayout(FormFit) + self.verticalLayout.setContentsMargins(0, 6, 0, 0) + self.verticalLayout.setSpacing(6) + self.verticalLayout.setObjectName("verticalLayout") + self.tabWidget = QtWidgets.QTabWidget(FormFit) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.tabWidget.sizePolicy().hasHeightForWidth()) + self.tabWidget.setSizePolicy(sizePolicy) + self.tabWidget.setObjectName("tabWidget") + self.general_tab = QtWidgets.QWidget() + self.general_tab.setObjectName("general_tab") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.general_tab) + self.verticalLayout_3.setContentsMargins(2, 2, 2, 2) + self.verticalLayout_3.setSpacing(2) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.scrollArea = QtWidgets.QScrollArea(self.general_tab) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.scrollArea.sizePolicy().hasHeightForWidth()) + self.scrollArea.setSizePolicy(sizePolicy) + self.scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame) + self.scrollArea.setFrameShadow(QtWidgets.QFrame.Plain) + self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) + self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.scrollArea.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents) + self.scrollArea.setWidgetResizable(False) + self.scrollArea.setObjectName("scrollArea") + self.scrollwidget = QtWidgets.QWidget() + self.scrollwidget.setGeometry(QtCore.QRect(0, 0, 390, 478)) + self.scrollwidget.setObjectName("scrollwidget") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.scrollwidget) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.scrollArea.setWidget(self.scrollwidget) + self.verticalLayout_3.addWidget(self.scrollArea) + self.tabWidget.addTab(self.general_tab, "") + self.data_tab = QtWidgets.QWidget() + self.data_tab.setObjectName("data_tab") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.data_tab) + self.verticalLayout_2.setContentsMargins(2, 2, 2, 2) + self.verticalLayout_2.setSpacing(2) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.comboBox = QtWidgets.QComboBox(self.data_tab) + self.comboBox.setObjectName("comboBox") + self.verticalLayout_2.addWidget(self.comboBox) + self.scrollArea2 = QtWidgets.QScrollArea(self.data_tab) + self.scrollArea2.setFrameShape(QtWidgets.QFrame.NoFrame) + self.scrollArea2.setWidgetResizable(True) + self.scrollArea2.setObjectName("scrollArea2") + self.scrollwidget2 = QtWidgets.QWidget() + self.scrollwidget2.setGeometry(QtCore.QRect(0, 0, 390, 444)) + self.scrollwidget2.setObjectName("scrollwidget2") + self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.scrollwidget2) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.scrollArea2.setWidget(self.scrollwidget2) + self.verticalLayout_2.addWidget(self.scrollArea2) + self.tabWidget.addTab(self.data_tab, "") + self.verticalLayout.addWidget(self.tabWidget) + + self.retranslateUi(FormFit) + self.tabWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(FormFit) + + def retranslateUi(self, FormFit): + _translate = QtCore.QCoreApplication.translate + FormFit.setWindowTitle(_translate("FormFit", "Form")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.general_tab), _translate("FormFit", "General settings")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.data_tab), _translate("FormFit", "Data parameter")) diff --git a/nmreval/gui_qt/_py/fitmodelfixwidget.py b/nmreval/gui_qt/_py/fitmodelfixwidget.py new file mode 100644 index 0000000..ef46181 --- /dev/null +++ b/nmreval/gui_qt/_py/fitmodelfixwidget.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/fitmodelfixwidget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_FitFixParameter(object): + def setupUi(self, FitFixParameter): + FitFixParameter.setObjectName("FitFixParameter") + FitFixParameter.setWindowModality(QtCore.Qt.WindowModal) + FitFixParameter.resize(480, 267) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(FitFixParameter.sizePolicy().hasHeightForWidth()) + FitFixParameter.setSizePolicy(sizePolicy) + FitFixParameter.setAutoFillBackground(True) + self.gridLayout = QtWidgets.QGridLayout(FitFixParameter) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setSpacing(0) + self.gridLayout.setObjectName("gridLayout") + self.frame = QtWidgets.QFrame(FitFixParameter) + self.frame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame.setFrameShadow(QtWidgets.QFrame.Plain) + self.frame.setObjectName("frame") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame) + self.horizontalLayout.setContentsMargins(0, 0, 3, 0) + self.horizontalLayout.setSpacing(3) + self.horizontalLayout.setObjectName("horizontalLayout") + self.parametername = QtWidgets.QLabel(self.frame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(10) + sizePolicy.setHeightForWidth(self.parametername.sizePolicy().hasHeightForWidth()) + self.parametername.setSizePolicy(sizePolicy) + self.parametername.setFrameShape(QtWidgets.QFrame.NoFrame) + self.parametername.setIndent(6) + self.parametername.setObjectName("parametername") + self.horizontalLayout.addWidget(self.parametername) + self.label = QtWidgets.QLabel(self.frame) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.gridLayout.addWidget(self.frame, 1, 0, 1, 1) + self.parameter_line = QtWidgets.QLineEdit(FitFixParameter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.parameter_line.sizePolicy().hasHeightForWidth()) + self.parameter_line.setSizePolicy(sizePolicy) + self.parameter_line.setObjectName("parameter_line") + self.gridLayout.addWidget(self.parameter_line, 1, 1, 1, 1) + + self.retranslateUi(FitFixParameter) + QtCore.QMetaObject.connectSlotsByName(FitFixParameter) + + def retranslateUi(self, FitFixParameter): + _translate = QtCore.QCoreApplication.translate + FitFixParameter.setWindowTitle(_translate("FitFixParameter", "Form")) + self.parametername.setText(_translate("FitFixParameter", "Parameter")) + self.label.setText(_translate("FitFixParameter", "Unit")) + self.parameter_line.setText(_translate("FitFixParameter", "1")) diff --git a/nmreval/gui_qt/_py/fitmodelwidget.py b/nmreval/gui_qt/_py/fitmodelwidget.py new file mode 100644 index 0000000..a41f14b --- /dev/null +++ b/nmreval/gui_qt/_py/fitmodelwidget.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/fitmodelwidget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_FitParameter(object): + def setupUi(self, FitParameter): + FitParameter.setObjectName("FitParameter") + FitParameter.resize(365, 78) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(FitParameter.sizePolicy().hasHeightForWidth()) + FitParameter.setSizePolicy(sizePolicy) + self.verticalLayout = QtWidgets.QVBoxLayout(FitParameter) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.verticalLayout.setSpacing(1) + self.verticalLayout.setObjectName("verticalLayout") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setSpacing(3) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.parametername = QtWidgets.QLabel(FitParameter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.parametername.sizePolicy().hasHeightForWidth()) + self.parametername.setSizePolicy(sizePolicy) + self.parametername.setMinimumSize(QtCore.QSize(28, 0)) + self.parametername.setObjectName("parametername") + self.horizontalLayout_2.addWidget(self.parametername) + self.parameter_line = LineEdit(FitParameter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.parameter_line.sizePolicy().hasHeightForWidth()) + self.parameter_line.setSizePolicy(sizePolicy) + self.parameter_line.setText("") + self.parameter_line.setObjectName("parameter_line") + self.horizontalLayout_2.addWidget(self.parameter_line) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem) + self.fixed_check = QtWidgets.QCheckBox(FitParameter) + self.fixed_check.setObjectName("fixed_check") + self.horizontalLayout_2.addWidget(self.fixed_check) + self.global_checkbox = QtWidgets.QCheckBox(FitParameter) + self.global_checkbox.setObjectName("global_checkbox") + self.horizontalLayout_2.addWidget(self.global_checkbox) + self.toolButton = QtWidgets.QToolButton(FitParameter) + self.toolButton.setText("") + self.toolButton.setPopupMode(QtWidgets.QToolButton.InstantPopup) + self.toolButton.setArrowType(QtCore.Qt.RightArrow) + self.toolButton.setObjectName("toolButton") + self.horizontalLayout_2.addWidget(self.toolButton) + self.verticalLayout.addLayout(self.horizontalLayout_2) + self.frame = QtWidgets.QFrame(FitParameter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame.sizePolicy().hasHeightForWidth()) + self.frame.setSizePolicy(sizePolicy) + self.frame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame.setFrameShadow(QtWidgets.QFrame.Plain) + self.frame.setObjectName("frame") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setSpacing(3) + self.horizontalLayout.setObjectName("horizontalLayout") + self.checkBox = QtWidgets.QCheckBox(self.frame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.checkBox.sizePolicy().hasHeightForWidth()) + self.checkBox.setSizePolicy(sizePolicy) + self.checkBox.setLayoutDirection(QtCore.Qt.RightToLeft) + self.checkBox.setText("") + self.checkBox.setObjectName("checkBox") + self.horizontalLayout.addWidget(self.checkBox) + self.lineEdit = QtWidgets.QLineEdit(self.frame) + self.lineEdit.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEdit.sizePolicy().hasHeightForWidth()) + self.lineEdit.setSizePolicy(sizePolicy) + self.lineEdit.setText("") + self.lineEdit.setFrame(True) + self.lineEdit.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.lineEdit.setObjectName("lineEdit") + self.horizontalLayout.addWidget(self.lineEdit) + self.label_3 = QtWidgets.QLabel(self.frame) + self.label_3.setEnabled(True) + self.label_3.setTextFormat(QtCore.Qt.RichText) + self.label_3.setAlignment(QtCore.Qt.AlignCenter) + self.label_3.setObjectName("label_3") + self.horizontalLayout.addWidget(self.label_3) + self.lineEdit_2 = QtWidgets.QLineEdit(self.frame) + self.lineEdit_2.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEdit_2.sizePolicy().hasHeightForWidth()) + self.lineEdit_2.setSizePolicy(sizePolicy) + self.lineEdit_2.setText("") + self.lineEdit_2.setFrame(True) + self.lineEdit_2.setObjectName("lineEdit_2") + self.horizontalLayout.addWidget(self.lineEdit_2) + self.verticalLayout.addWidget(self.frame) + self.line = QtWidgets.QFrame(FitParameter) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.verticalLayout.addWidget(self.line) + + self.retranslateUi(FitParameter) + QtCore.QMetaObject.connectSlotsByName(FitParameter) + + def retranslateUi(self, FitParameter): + _translate = QtCore.QCoreApplication.translate + FitParameter.setWindowTitle(_translate("FitParameter", "Form")) + self.parametername.setText(_translate("FitParameter", "A")) + self.parameter_line.setToolTip(_translate("FitParameter", "Initial values")) + self.parameter_line.setPlaceholderText(_translate("FitParameter", "0")) + self.fixed_check.setText(_translate("FitParameter", "Fix")) + self.global_checkbox.setText(_translate("FitParameter", "Global")) + self.lineEdit.setToolTip(_translate("FitParameter", "

Lower bound. Same bound is used for all data. Leave empty for no boundary condition.

")) + self.label_3.setText(_translate("FitParameter", "Textlabel")) + self.lineEdit_2.setToolTip(_translate("FitParameter", "

Upper bound. Same bound is used for all data. Leave empty for no boundary condition.

")) +from ..lib.forms import LineEdit diff --git a/nmreval/gui_qt/_py/fitparametertable.py b/nmreval/gui_qt/_py/fitparametertable.py new file mode 100644 index 0000000..5ad7241 --- /dev/null +++ b/nmreval/gui_qt/_py/fitparametertable.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/fitparametertable.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_FitParameterDialog(object): + def setupUi(self, FitParameterDialog): + FitParameterDialog.setObjectName("FitParameterDialog") + FitParameterDialog.resize(898, 583) + self.verticalLayout = QtWidgets.QVBoxLayout(FitParameterDialog) + self.verticalLayout.setObjectName("verticalLayout") + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.verticalLayout.addLayout(self.verticalLayout_2) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.pushButton = QtWidgets.QPushButton(FitParameterDialog) + self.pushButton.setObjectName("pushButton") + self.horizontalLayout.addWidget(self.pushButton) + self.buttonBox = QtWidgets.QDialogButtonBox(FitParameterDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth()) + self.buttonBox.setSizePolicy(sizePolicy) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close) + self.buttonBox.setCenterButtons(False) + self.buttonBox.setObjectName("buttonBox") + self.horizontalLayout.addWidget(self.buttonBox) + self.verticalLayout.addLayout(self.horizontalLayout) + + self.retranslateUi(FitParameterDialog) + self.buttonBox.accepted.connect(FitParameterDialog.accept) + self.buttonBox.rejected.connect(FitParameterDialog.reject) + QtCore.QMetaObject.connectSlotsByName(FitParameterDialog) + + def retranslateUi(self, FitParameterDialog): + _translate = QtCore.QCoreApplication.translate + FitParameterDialog.setWindowTitle(_translate("FitParameterDialog", "Fitparameter")) + self.pushButton.setText(_translate("FitParameterDialog", "Copy")) diff --git a/nmreval/gui_qt/_py/fitparameterwidget.py b/nmreval/gui_qt/_py/fitparameterwidget.py new file mode 100644 index 0000000..6d282bd --- /dev/null +++ b/nmreval/gui_qt/_py/fitparameterwidget.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/fitparameterwidget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_FormFit(object): + def setupUi(self, FormFit): + FormFit.setObjectName("FormFit") + FormFit.resize(292, 477) + self.verticalLayout = QtWidgets.QVBoxLayout(FormFit) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.tabWidget = QtWidgets.QTabWidget(FormFit) + self.tabWidget.setObjectName("tabWidget") + self.general_tab = QtWidgets.QWidget() + self.general_tab.setObjectName("general_tab") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.general_tab) + self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_2.setSpacing(0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.scrollArea = QtWidgets.QScrollArea(self.general_tab) + self.scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame) + self.scrollArea.setFrameShadow(QtWidgets.QFrame.Plain) + self.scrollArea.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents) + self.scrollArea.setWidgetResizable(True) + self.scrollArea.setObjectName("scrollArea") + self.scrollwidget = QtWidgets.QWidget() + self.scrollwidget.setGeometry(QtCore.QRect(0, 0, 284, 442)) + self.scrollwidget.setObjectName("scrollwidget") + self.scrollArea.setWidget(self.scrollwidget) + self.verticalLayout_2.addWidget(self.scrollArea) + self.tabWidget.addTab(self.general_tab, "") + self.data_tab = QtWidgets.QWidget() + self.data_tab.setObjectName("data_tab") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.data_tab) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.comboBox = QtWidgets.QComboBox(self.data_tab) + self.comboBox.setObjectName("comboBox") + self.verticalLayout_3.addWidget(self.comboBox) + self.scrollArea2 = QtWidgets.QScrollArea(self.data_tab) + self.scrollArea2.setFrameShape(QtWidgets.QFrame.NoFrame) + self.scrollArea2.setFrameShadow(QtWidgets.QFrame.Plain) + self.scrollArea2.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents) + self.scrollArea2.setWidgetResizable(True) + self.scrollArea2.setObjectName("scrollArea2") + self.scrollwidget2 = QtWidgets.QWidget() + self.scrollwidget2.setGeometry(QtCore.QRect(0, 0, 272, 392)) + self.scrollwidget2.setObjectName("scrollwidget2") + self.scrollArea2.setWidget(self.scrollwidget2) + self.verticalLayout_3.addWidget(self.scrollArea2) + self.tabWidget.addTab(self.data_tab, "") + self.verticalLayout.addWidget(self.tabWidget) + + self.retranslateUi(FormFit) + self.tabWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(FormFit) + + def retranslateUi(self, FormFit): + _translate = QtCore.QCoreApplication.translate + FormFit.setWindowTitle(_translate("FormFit", "Form")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.general_tab), _translate("FormFit", "General settings")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.data_tab), _translate("FormFit", "Data parameter")) diff --git a/nmreval/gui_qt/_py/fitresult.py b/nmreval/gui_qt/_py/fitresult.py new file mode 100644 index 0000000..386e538 --- /dev/null +++ b/nmreval/gui_qt/_py/fitresult.py @@ -0,0 +1,180 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/fitresult.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(817, 584) + self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setObjectName("gridLayout") + self.sets_comboBox = ElideComboBox(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.sets_comboBox.sizePolicy().hasHeightForWidth()) + self.sets_comboBox.setSizePolicy(sizePolicy) + self.sets_comboBox.setMaximumSize(QtCore.QSize(400, 16777215)) + self.sets_comboBox.setBaseSize(QtCore.QSize(200, 0)) + self.sets_comboBox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToMinimumContentsLength) + self.sets_comboBox.setObjectName("sets_comboBox") + self.gridLayout.addWidget(self.sets_comboBox, 0, 0, 1, 1) + self.stack = QtWidgets.QToolBox(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.stack.sizePolicy().hasHeightForWidth()) + self.stack.setSizePolicy(sizePolicy) + self.stack.setObjectName("stack") + self.page = QtWidgets.QWidget() + self.page.setGeometry(QtCore.QRect(0, 0, 399, 414)) + self.page.setObjectName("page") + self.verticalLayout = QtWidgets.QVBoxLayout(self.page) + self.verticalLayout.setContentsMargins(3, 3, 3, 3) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.graphicsView = GraphicsLayoutWidget(self.page) + self.graphicsView.setObjectName("graphicsView") + self.verticalLayout.addWidget(self.graphicsView) + self.logy_box = QtWidgets.QCheckBox(self.page) + self.logy_box.setLayoutDirection(QtCore.Qt.RightToLeft) + self.logy_box.setObjectName("logy_box") + self.verticalLayout.addWidget(self.logy_box) + self.stack.addItem(self.page, "") + self.page_2 = QtWidgets.QWidget() + self.page_2.setGeometry(QtCore.QRect(0, 0, 399, 414)) + self.page_2.setObjectName("page_2") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.page_2) + self.verticalLayout_2.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_2.setSpacing(3) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.stats_tableWidget = QtWidgets.QTableWidget(self.page_2) + self.stats_tableWidget.setFrameShape(QtWidgets.QFrame.Box) + self.stats_tableWidget.setGridStyle(QtCore.Qt.NoPen) + self.stats_tableWidget.setColumnCount(1) + self.stats_tableWidget.setObjectName("stats_tableWidget") + self.stats_tableWidget.setRowCount(0) + self.stats_tableWidget.horizontalHeader().setVisible(False) + self.stats_tableWidget.horizontalHeader().setSortIndicatorShown(True) + self.verticalLayout_2.addWidget(self.stats_tableWidget) + self.stack.addItem(self.page_2, "") + self.page_3 = QtWidgets.QWidget() + self.page_3.setGeometry(QtCore.QRect(0, 0, 399, 414)) + self.page_3.setObjectName("page_3") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.page_3) + self.verticalLayout_3.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_3.setSpacing(3) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.corr_tableWidget = QtWidgets.QTableWidget(self.page_3) + self.corr_tableWidget.setFrameShape(QtWidgets.QFrame.Box) + self.corr_tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.corr_tableWidget.setGridStyle(QtCore.Qt.NoPen) + self.corr_tableWidget.setObjectName("corr_tableWidget") + self.corr_tableWidget.setColumnCount(4) + self.corr_tableWidget.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + self.corr_tableWidget.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.corr_tableWidget.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + self.corr_tableWidget.setHorizontalHeaderItem(2, item) + item = QtWidgets.QTableWidgetItem() + self.corr_tableWidget.setHorizontalHeaderItem(3, item) + self.corr_tableWidget.horizontalHeader().setStretchLastSection(True) + self.corr_tableWidget.verticalHeader().setVisible(False) + self.verticalLayout_3.addWidget(self.corr_tableWidget) + self.stack.addItem(self.page_3, "") + self.gridLayout.addWidget(self.stack, 0, 1, 4, 1) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setSpacing(3) + self.horizontalLayout.setObjectName("horizontalLayout") + self.partial_checkBox = QtWidgets.QCheckBox(Dialog) + self.partial_checkBox.setObjectName("partial_checkBox") + self.horizontalLayout.addWidget(self.partial_checkBox) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.label_2 = QtWidgets.QLabel(Dialog) + self.label_2.setObjectName("label_2") + self.horizontalLayout.addWidget(self.label_2) + self.graph_checkBox = QtWidgets.QCheckBox(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.graph_checkBox.sizePolicy().hasHeightForWidth()) + self.graph_checkBox.setSizePolicy(sizePolicy) + self.graph_checkBox.setChecked(True) + self.graph_checkBox.setObjectName("graph_checkBox") + self.horizontalLayout.addWidget(self.graph_checkBox) + self.graph_comboBox = QtWidgets.QComboBox(Dialog) + self.graph_comboBox.setEnabled(False) + self.graph_comboBox.setObjectName("graph_comboBox") + self.horizontalLayout.addWidget(self.graph_comboBox) + self.gridLayout.addLayout(self.horizontalLayout, 5, 0, 1, 2) + self.line_2 = QtWidgets.QFrame(Dialog) + self.line_2.setFrameShape(QtWidgets.QFrame.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.gridLayout.addWidget(self.line_2, 3, 0, 1, 1) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setSpacing(3) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.reject_fit_checkBox = QtWidgets.QCheckBox(Dialog) + self.reject_fit_checkBox.setObjectName("reject_fit_checkBox") + self.horizontalLayout_2.addWidget(self.reject_fit_checkBox) + self.del_prev_checkBox = QtWidgets.QCheckBox(Dialog) + self.del_prev_checkBox.setObjectName("del_prev_checkBox") + self.horizontalLayout_2.addWidget(self.del_prev_checkBox) + self.gridLayout.addLayout(self.horizontalLayout_2, 2, 0, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok|QtWidgets.QDialogButtonBox.Retry) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 6, 0, 1, 2) + self.param_tableWidget = QtWidgets.QTableWidget(Dialog) + self.param_tableWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) + self.param_tableWidget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored) + self.param_tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.param_tableWidget.setAlternatingRowColors(True) + self.param_tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.param_tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectColumns) + self.param_tableWidget.setShowGrid(False) + self.param_tableWidget.setColumnCount(0) + self.param_tableWidget.setObjectName("param_tableWidget") + self.param_tableWidget.setRowCount(0) + self.param_tableWidget.horizontalHeader().setStretchLastSection(False) + self.gridLayout.addWidget(self.param_tableWidget, 1, 0, 1, 1) + + self.retranslateUi(Dialog) + self.stack.setCurrentIndex(0) + self.stack.layout().setSpacing(0) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Fit results")) + self.logy_box.setText(_translate("Dialog", "logarithmic y axis")) + self.stack.setItemText(self.stack.indexOf(self.page), _translate("Dialog", "Plot")) + self.stack.setItemText(self.stack.indexOf(self.page_2), _translate("Dialog", "Statistics")) + item = self.corr_tableWidget.horizontalHeaderItem(0) + item.setText(_translate("Dialog", "Parameter 1")) + item = self.corr_tableWidget.horizontalHeaderItem(1) + item.setText(_translate("Dialog", "Parameter 2")) + item = self.corr_tableWidget.horizontalHeaderItem(2) + item.setText(_translate("Dialog", "Corr.")) + item = self.corr_tableWidget.horizontalHeaderItem(3) + item.setText(_translate("Dialog", "Partial Corr.")) + self.stack.setItemText(self.stack.indexOf(self.page_3), _translate("Dialog", "Correlations")) + self.partial_checkBox.setText(_translate("Dialog", "Plot partial functions")) + self.label_2.setText(_translate("Dialog", "Location of parameters:")) + self.graph_checkBox.setText(_translate("Dialog", "New graph")) + self.reject_fit_checkBox.setText(_translate("Dialog", "Reject this fit")) + self.del_prev_checkBox.setText(_translate("Dialog", "Delete previous fits")) +from ..lib.forms import ElideComboBox +from pyqtgraph import GraphicsLayoutWidget diff --git a/nmreval/gui_qt/_py/ftdialog.py b/nmreval/gui_qt/_py/ftdialog.py new file mode 100644 index 0000000..1fd694f --- /dev/null +++ b/nmreval/gui_qt/_py/ftdialog.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/ftdialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(400, 300) + self.verticalLayout = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout.setContentsMargins(3, 3, 3, 3) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.listWidget = QtWidgets.QListWidget(Dialog) + self.listWidget.setObjectName("listWidget") + self.verticalLayout.addWidget(self.listWidget) + self.mode_comboBox = QtWidgets.QComboBox(Dialog) + self.mode_comboBox.setObjectName("mode_comboBox") + self.mode_comboBox.addItem("") + self.mode_comboBox.addItem("") + self.mode_comboBox.addItem("") + self.verticalLayout.addWidget(self.mode_comboBox) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout.setSpacing(3) + self.horizontalLayout.setObjectName("horizontalLayout") + self.graph_checkBox = QtWidgets.QCheckBox(Dialog) + self.graph_checkBox.setObjectName("graph_checkBox") + self.horizontalLayout.addWidget(self.graph_checkBox) + self.graph_comboBox = QtWidgets.QComboBox(Dialog) + self.graph_comboBox.setObjectName("graph_comboBox") + self.horizontalLayout.addWidget(self.graph_comboBox) + self.verticalLayout.addLayout(self.horizontalLayout) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Logarithmic Fourier")) + self.mode_comboBox.setItemText(0, _translate("Dialog", "Real")) + self.mode_comboBox.setItemText(1, _translate("Dialog", "Imag")) + self.mode_comboBox.setItemText(2, _translate("Dialog", "Complex")) + self.graph_checkBox.setText(_translate("Dialog", "New graph")) diff --git a/nmreval/gui_qt/_py/function_tree_widget.py b/nmreval/gui_qt/_py/function_tree_widget.py new file mode 100644 index 0000000..5235d8d --- /dev/null +++ b/nmreval/gui_qt/_py/function_tree_widget.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/function_tree_widget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(314, 232) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth()) + Form.setSizePolicy(sizePolicy) + self.gridLayout = QtWidgets.QGridLayout(Form) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setSpacing(3) + self.gridLayout.setObjectName("gridLayout") + self.widget_2 = ExpandableWidget(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widget_2.sizePolicy().hasHeightForWidth()) + self.widget_2.setSizePolicy(sizePolicy) + self.widget_2.setObjectName("widget_2") + self.gridLayout.addWidget(self.widget_2, 4, 0, 1, 2) + self.widget = QtWidgets.QWidget(Form) + self.widget.setObjectName("widget") + self.gridLayout_2 = QtWidgets.QGridLayout(self.widget) + self.gridLayout_2.setContentsMargins(0, 0, 0, 0) + self.gridLayout_2.setObjectName("gridLayout_2") + self.label_2 = QtWidgets.QLabel(self.widget) + self.label_2.setObjectName("label_2") + self.gridLayout_2.addWidget(self.label_2, 1, 0, 1, 1) + self.complex_comboBox = QtWidgets.QComboBox(self.widget) + self.complex_comboBox.setObjectName("complex_comboBox") + self.complex_comboBox.addItem("") + self.complex_comboBox.addItem("") + self.complex_comboBox.addItem("") + self.gridLayout_2.addWidget(self.complex_comboBox, 1, 1, 1, 1) + self.label = QtWidgets.QLabel(self.widget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setObjectName("label") + self.gridLayout_2.addWidget(self.label, 0, 0, 1, 2) + self.gridLayout.addWidget(self.widget, 5, 0, 1, 2) + self.use_function_button = QtWidgets.QToolButton(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.use_function_button.sizePolicy().hasHeightForWidth()) + self.use_function_button.setSizePolicy(sizePolicy) + self.use_function_button.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + self.use_function_button.setAutoRaise(False) + self.use_function_button.setArrowType(QtCore.Qt.RightArrow) + self.use_function_button.setObjectName("use_function_button") + self.gridLayout.addWidget(self.use_function_button, 3, 1, 1, 1) + self.fitcomboBox = QtWidgets.QComboBox(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.fitcomboBox.sizePolicy().hasHeightForWidth()) + self.fitcomboBox.setSizePolicy(sizePolicy) + self.fitcomboBox.setObjectName("fitcomboBox") + self.gridLayout.addWidget(self.fitcomboBox, 1, 0, 1, 2) + self.typecomboBox = QtWidgets.QComboBox(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.typecomboBox.sizePolicy().hasHeightForWidth()) + self.typecomboBox.setSizePolicy(sizePolicy) + self.typecomboBox.setObjectName("typecomboBox") + self.gridLayout.addWidget(self.typecomboBox, 0, 0, 1, 2) + self.fitequation = QtWidgets.QLabel(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.fitequation.sizePolicy().hasHeightForWidth()) + self.fitequation.setSizePolicy(sizePolicy) + self.fitequation.setWordWrap(True) + self.fitequation.setObjectName("fitequation") + self.gridLayout.addWidget(self.fitequation, 2, 0, 1, 2) + self.operator_combobox = QtWidgets.QComboBox(Form) + self.operator_combobox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) + self.operator_combobox.setFrame(True) + self.operator_combobox.setObjectName("operator_combobox") + self.operator_combobox.addItem("") + self.operator_combobox.addItem("") + self.operator_combobox.addItem("") + self.operator_combobox.addItem("") + self.gridLayout.addWidget(self.operator_combobox, 3, 0, 1, 1) + self.comboBox_2 = QtWidgets.QComboBox(Form) + self.comboBox_2.setObjectName("comboBox_2") + self.gridLayout.addWidget(self.comboBox_2, 6, 0, 1, 2) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label_2.setText(_translate("Form", "Select part to fit")) + self.complex_comboBox.setItemText(0, _translate("Form", "Complex")) + self.complex_comboBox.setItemText(1, _translate("Form", "Real")) + self.complex_comboBox.setItemText(2, _translate("Form", "Imaginary")) + self.label.setText(_translate("Form", "Complex function found")) + self.use_function_button.setText(_translate("Form", "Use")) + self.fitequation.setText(_translate("Form", "Equation")) + self.operator_combobox.setItemText(0, _translate("Form", "Add")) + self.operator_combobox.setItemText(1, _translate("Form", "Multiply")) + self.operator_combobox.setItemText(2, _translate("Form", "Subtract")) + self.operator_combobox.setItemText(3, _translate("Form", "Divide by")) +from ..lib.expandablewidget import ExpandableWidget diff --git a/nmreval/gui_qt/_py/gol.py b/nmreval/gui_qt/_py/gol.py new file mode 100644 index 0000000..2d00e06 --- /dev/null +++ b/nmreval/gui_qt/_py/gol.py @@ -0,0 +1,276 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/gol.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(883, 732) + self.gridLayout_2 = QtWidgets.QGridLayout(Form) + self.gridLayout_2.setObjectName("gridLayout_2") + self.widget = QtWidgets.QWidget(Form) + self.widget.setObjectName("widget") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.widget) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.vanish_shadow = QtWidgets.QRadioButton(self.widget) + self.vanish_shadow.setChecked(True) + self.vanish_shadow.setObjectName("vanish_shadow") + self.buttonGroup = QtWidgets.QButtonGroup(Form) + self.buttonGroup.setObjectName("buttonGroup") + self.buttonGroup.addButton(self.vanish_shadow) + self.verticalLayout_3.addWidget(self.vanish_shadow) + self.full_shadow = QtWidgets.QRadioButton(self.widget) + self.full_shadow.setObjectName("full_shadow") + self.buttonGroup.addButton(self.full_shadow) + self.verticalLayout_3.addWidget(self.full_shadow) + self.radioButton = QtWidgets.QRadioButton(self.widget) + self.radioButton.setObjectName("radioButton") + self.buttonGroup.addButton(self.radioButton) + self.verticalLayout_3.addWidget(self.radioButton) + self.line = QtWidgets.QFrame(self.widget) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.verticalLayout_3.addWidget(self.line) + self.faster_button = QtWidgets.QToolButton(self.widget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.faster_button.sizePolicy().hasHeightForWidth()) + self.faster_button.setSizePolicy(sizePolicy) + self.faster_button.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + self.faster_button.setArrowType(QtCore.Qt.RightArrow) + self.faster_button.setObjectName("faster_button") + self.verticalLayout_3.addWidget(self.faster_button) + self.velocity_label = QtWidgets.QLabel(self.widget) + self.velocity_label.setObjectName("velocity_label") + self.verticalLayout_3.addWidget(self.velocity_label) + self.slower_button = QtWidgets.QToolButton(self.widget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.slower_button.sizePolicy().hasHeightForWidth()) + self.slower_button.setSizePolicy(sizePolicy) + self.slower_button.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + self.slower_button.setArrowType(QtCore.Qt.LeftArrow) + self.slower_button.setObjectName("slower_button") + self.verticalLayout_3.addWidget(self.slower_button) + self.current_step = QtWidgets.QLabel(self.widget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.current_step.sizePolicy().hasHeightForWidth()) + self.current_step.setSizePolicy(sizePolicy) + self.current_step.setObjectName("current_step") + self.verticalLayout_3.addWidget(self.current_step) + self.pause_button = QtWidgets.QPushButton(self.widget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pause_button.sizePolicy().hasHeightForWidth()) + self.pause_button.setSizePolicy(sizePolicy) + self.pause_button.setCheckable(True) + self.pause_button.setObjectName("pause_button") + self.verticalLayout_3.addWidget(self.pause_button) + self.line_3 = QtWidgets.QFrame(self.widget) + self.line_3.setFrameShape(QtWidgets.QFrame.HLine) + self.line_3.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_3.setObjectName("line_3") + self.verticalLayout_3.addWidget(self.line_3) + self.label_6 = QtWidgets.QLabel(self.widget) + self.label_6.setObjectName("label_6") + self.verticalLayout_3.addWidget(self.label_6) + self.cover_label = QtWidgets.QLabel(self.widget) + self.cover_label.setText("") + self.cover_label.setObjectName("cover_label") + self.verticalLayout_3.addWidget(self.cover_label) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_3.addItem(spacerItem) + self.gridLayout_2.addWidget(self.widget, 0, 0, 1, 1) + self.view = QtWidgets.QGraphicsView(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.view.sizePolicy().hasHeightForWidth()) + self.view.setSizePolicy(sizePolicy) + self.view.setStyleSheet("background-color: transparent") + self.view.setFrameShape(QtWidgets.QFrame.NoFrame) + self.view.setObjectName("view") + self.gridLayout_2.addWidget(self.view, 0, 1, 1, 1) + self.option_frame = QtWidgets.QFrame(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.option_frame.sizePolicy().hasHeightForWidth()) + self.option_frame.setSizePolicy(sizePolicy) + self.option_frame.setFrameShape(QtWidgets.QFrame.Box) + self.option_frame.setObjectName("option_frame") + self.gridLayout = QtWidgets.QGridLayout(self.option_frame) + self.gridLayout.setContentsMargins(3, 3, 3, 3) + self.gridLayout.setHorizontalSpacing(6) + self.gridLayout.setVerticalSpacing(3) + self.gridLayout.setObjectName("gridLayout") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.rule_label = QtWidgets.QLabel(self.option_frame) + self.rule_label.setObjectName("rule_label") + self.horizontalLayout_2.addWidget(self.rule_label) + self.rule_cb = QtWidgets.QComboBox(self.option_frame) + self.rule_cb.setObjectName("rule_cb") + self.horizontalLayout_2.addWidget(self.rule_cb) + self.gridLayout.addLayout(self.horizontalLayout_2, 3, 0, 1, 1) + self.line_2 = QtWidgets.QFrame(self.option_frame) + self.line_2.setFrameShape(QtWidgets.QFrame.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.gridLayout.addWidget(self.line_2, 2, 0, 1, 1) + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setContentsMargins(-1, 0, -1, 0) + self.verticalLayout_2.setSpacing(3) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.object_widget = QtWidgets.QWidget(self.option_frame) + self.object_widget.setObjectName("object_widget") + self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.object_widget) + self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_6.setSpacing(3) + self.horizontalLayout_6.setObjectName("horizontalLayout_6") + self.label_5 = QtWidgets.QLabel(self.object_widget) + self.label_5.setObjectName("label_5") + self.horizontalLayout_6.addWidget(self.label_5) + self.object_size = QtWidgets.QSpinBox(self.object_widget) + self.object_size.setMinimum(1) + self.object_size.setMaximum(600) + self.object_size.setObjectName("object_size") + self.horizontalLayout_6.addWidget(self.object_size) + self.verticalLayout_2.addWidget(self.object_widget) + self.rand_button_wdgt = QtWidgets.QWidget(self.option_frame) + self.rand_button_wdgt.setObjectName("rand_button_wdgt") + self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.rand_button_wdgt) + self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_7.setSpacing(3) + self.horizontalLayout_7.setObjectName("horizontalLayout_7") + self.add_random_button = QtWidgets.QPushButton(self.rand_button_wdgt) + self.add_random_button.setObjectName("add_random_button") + self.horizontalLayout_7.addWidget(self.add_random_button) + self.remove_random_button = QtWidgets.QPushButton(self.rand_button_wdgt) + self.remove_random_button.setObjectName("remove_random_button") + self.horizontalLayout_7.addWidget(self.remove_random_button) + self.verticalLayout_2.addWidget(self.rand_button_wdgt) + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.verticalLayout_2.addLayout(self.verticalLayout) + self.gridLayout.addLayout(self.verticalLayout_2, 2, 1, 4, 1) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.label_3 = QtWidgets.QLabel(self.option_frame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth()) + self.label_3.setSizePolicy(sizePolicy) + self.label_3.setObjectName("label_3") + self.horizontalLayout.addWidget(self.label_3) + self.survival_line = QtWidgets.QLineEdit(self.option_frame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.survival_line.sizePolicy().hasHeightForWidth()) + self.survival_line.setSizePolicy(sizePolicy) + self.survival_line.setObjectName("survival_line") + self.horizontalLayout.addWidget(self.survival_line) + self.label_4 = QtWidgets.QLabel(self.option_frame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4.setSizePolicy(sizePolicy) + self.label_4.setObjectName("label_4") + self.horizontalLayout.addWidget(self.label_4) + self.birth_line = QtWidgets.QLineEdit(self.option_frame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.birth_line.sizePolicy().hasHeightForWidth()) + self.birth_line.setSizePolicy(sizePolicy) + self.birth_line.setObjectName("birth_line") + self.horizontalLayout.addWidget(self.birth_line) + self.gridLayout.addLayout(self.horizontalLayout, 4, 0, 1, 1) + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.label = QtWidgets.QLabel(self.option_frame) + self.label.setObjectName("label") + self.horizontalLayout_3.addWidget(self.label) + self.width_box = QtWidgets.QSpinBox(self.option_frame) + self.width_box.setMaximum(600) + self.width_box.setProperty("value", 100) + self.width_box.setObjectName("width_box") + self.horizontalLayout_3.addWidget(self.width_box) + self.label_2 = QtWidgets.QLabel(self.option_frame) + self.label_2.setObjectName("label_2") + self.horizontalLayout_3.addWidget(self.label_2) + self.height_box = QtWidgets.QSpinBox(self.option_frame) + self.height_box.setMaximum(600) + self.height_box.setProperty("value", 100) + self.height_box.setObjectName("height_box") + self.horizontalLayout_3.addWidget(self.height_box) + self.gridLayout.addLayout(self.horizontalLayout_3, 1, 0, 1, 1) + self.object_combobox = QtWidgets.QComboBox(self.option_frame) + self.object_combobox.setObjectName("object_combobox") + self.object_combobox.addItem("") + self.object_combobox.addItem("") + self.object_combobox.addItem("") + self.object_combobox.addItem("") + self.object_combobox.addItem("") + self.gridLayout.addWidget(self.object_combobox, 1, 1, 1, 1) + self.start_button = QtWidgets.QPushButton(self.option_frame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.start_button.sizePolicy().hasHeightForWidth()) + self.start_button.setSizePolicy(sizePolicy) + self.start_button.setObjectName("start_button") + self.gridLayout.addWidget(self.start_button, 0, 0, 1, 2) + self.gridLayout_2.addWidget(self.option_frame, 1, 1, 1, 1) + self.hide_button = QtWidgets.QCheckBox(Form) + self.hide_button.setObjectName("hide_button") + self.gridLayout_2.addWidget(self.hide_button, 1, 0, 1, 1) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Game Of Life")) + self.vanish_shadow.setText(_translate("Form", "Motion blur")) + self.full_shadow.setText(_translate("Form", "Scorched earth")) + self.radioButton.setText(_translate("Form", "Nothing")) + self.faster_button.setText(_translate("Form", "Faster")) + self.velocity_label.setText(_translate("Form", "10 steps / s")) + self.slower_button.setText(_translate("Form", "Slower")) + self.current_step.setText(_translate("Form", "0 step")) + self.pause_button.setText(_translate("Form", "Pause")) + self.label_6.setText(_translate("Form", "Coverage:")) + self.rule_label.setText(_translate("Form", "Rule")) + self.label_5.setText(_translate("Form", "Size")) + self.add_random_button.setText(_translate("Form", "Add Random")) + self.remove_random_button.setText(_translate("Form", "Remove Random")) + self.label_3.setText(_translate("Form", "Survival")) + self.label_4.setText(_translate("Form", " Birth")) + self.label.setText(_translate("Form", "Width")) + self.label_2.setText(_translate("Form", "Height")) + self.object_combobox.setItemText(0, _translate("Form", "Random")) + self.object_combobox.setItemText(1, _translate("Form", "Circle")) + self.object_combobox.setItemText(2, _translate("Form", "Square")) + self.object_combobox.setItemText(3, _translate("Form", "Diamond")) + self.object_combobox.setItemText(4, _translate("Form", "Plus")) + self.start_button.setText(_translate("Form", "Start")) + self.hide_button.setText(_translate("Form", "Hide options")) diff --git a/nmreval/gui_qt/_py/gracemsgdialog.py b/nmreval/gui_qt/_py/gracemsgdialog.py new file mode 100644 index 0000000..9c3c25f --- /dev/null +++ b/nmreval/gui_qt/_py/gracemsgdialog.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/gracemsgdialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_GraceMsgDialog(object): + def setupUi(self, GraceMsgDialog): + GraceMsgDialog.setObjectName("GraceMsgDialog") + GraceMsgDialog.resize(400, 300) + self.gridLayout = QtWidgets.QGridLayout(GraceMsgDialog) + self.gridLayout.setObjectName("gridLayout") + self.graph_combo = QtWidgets.QComboBox(GraceMsgDialog) + self.graph_combo.setObjectName("graph_combo") + self.gridLayout.addWidget(self.graph_combo, 1, 1, 1, 1) + self.graph_button = QtWidgets.QRadioButton(GraceMsgDialog) + self.graph_button.setObjectName("graph_button") + self.buttonGroup = QtWidgets.QButtonGroup(GraceMsgDialog) + self.buttonGroup.setObjectName("buttonGroup") + self.buttonGroup.addButton(self.graph_button) + self.gridLayout.addWidget(self.graph_button, 1, 0, 1, 1) + self.overwrite_button = QtWidgets.QRadioButton(GraceMsgDialog) + self.overwrite_button.setChecked(True) + self.overwrite_button.setObjectName("overwrite_button") + self.buttonGroup.addButton(self.overwrite_button) + self.gridLayout.addWidget(self.overwrite_button, 0, 0, 1, 1) + self.radioButton = QtWidgets.QRadioButton(GraceMsgDialog) + self.radioButton.setObjectName("radioButton") + self.buttonGroup.addButton(self.radioButton) + self.gridLayout.addWidget(self.radioButton, 2, 0, 1, 1) + self.tableWidget = QtWidgets.QTableWidget(GraceMsgDialog) + self.tableWidget.setColumnCount(2) + self.tableWidget.setObjectName("tableWidget") + self.tableWidget.setRowCount(0) + self.tableWidget.horizontalHeader().setVisible(False) + self.gridLayout.addWidget(self.tableWidget, 3, 0, 2, 2) + self.buttonBox = QtWidgets.QDialogButtonBox(GraceMsgDialog) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 5, 0, 1, 2) + + self.retranslateUi(GraceMsgDialog) + QtCore.QMetaObject.connectSlotsByName(GraceMsgDialog) + + def retranslateUi(self, GraceMsgDialog): + _translate = QtCore.QCoreApplication.translate + GraceMsgDialog.setWindowTitle(_translate("GraceMsgDialog", "Goodness gracious, file already exists.")) + self.graph_button.setText(_translate("GraceMsgDialog", "Add to graph")) + self.overwrite_button.setText(_translate("GraceMsgDialog", "Overwrite file")) + self.radioButton.setText(_translate("GraceMsgDialog", "Replace sets")) diff --git a/nmreval/gui_qt/_py/gracereader.py b/nmreval/gui_qt/_py/gracereader.py new file mode 100644 index 0000000..b769d0d --- /dev/null +++ b/nmreval/gui_qt/_py/gracereader.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/gracereader.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(400, 613) + self.verticalLayout = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout.setObjectName("verticalLayout") + self.label = QtWidgets.QLabel(Dialog) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.treeWidget = QtWidgets.QTreeWidget(Dialog) + self.treeWidget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.treeWidget.setObjectName("treeWidget") + self.treeWidget.headerItem().setText(0, "1") + self.treeWidget.header().setVisible(False) + self.verticalLayout.addWidget(self.treeWidget) + self.tableWidget = QtWidgets.QTableWidget(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.tableWidget.sizePolicy().hasHeightForWidth()) + self.tableWidget.setSizePolicy(sizePolicy) + self.tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget.setGridStyle(QtCore.Qt.NoPen) + self.tableWidget.setRowCount(4) + self.tableWidget.setColumnCount(2) + self.tableWidget.setObjectName("tableWidget") + item = QtWidgets.QTableWidgetItem() + item.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsEnabled) + self.tableWidget.setItem(0, 0, item) + item = QtWidgets.QTableWidgetItem() + item.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsEnabled) + self.tableWidget.setItem(0, 1, item) + item = QtWidgets.QTableWidgetItem() + item.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsEnabled) + self.tableWidget.setItem(1, 0, item) + item = QtWidgets.QTableWidgetItem() + item.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsEnabled) + self.tableWidget.setItem(1, 1, item) + item = QtWidgets.QTableWidgetItem() + item.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsEnabled) + self.tableWidget.setItem(2, 0, item) + item = QtWidgets.QTableWidgetItem() + item.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsEnabled) + self.tableWidget.setItem(2, 1, item) + item = QtWidgets.QTableWidgetItem() + item.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsEnabled) + self.tableWidget.setItem(3, 0, item) + item = QtWidgets.QTableWidgetItem() + item.setFlags(QtCore.Qt.ItemIsEnabled) + self.tableWidget.setItem(3, 1, item) + self.tableWidget.horizontalHeader().setVisible(False) + self.tableWidget.horizontalHeader().setStretchLastSection(True) + self.tableWidget.verticalHeader().setVisible(False) + self.verticalLayout.addWidget(self.tableWidget) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Load data from agr")) + self.label.setText(_translate("Dialog", "Only data will be loaded, no line and symbol properties!")) + __sortingEnabled = self.tableWidget.isSortingEnabled() + self.tableWidget.setSortingEnabled(False) + item = self.tableWidget.item(0, 0) + item.setText(_translate("Dialog", "Symbol")) + item = self.tableWidget.item(1, 0) + item.setText(_translate("Dialog", "Symbol color")) + item = self.tableWidget.item(2, 0) + item.setText(_translate("Dialog", "Linestyle")) + item = self.tableWidget.item(3, 0) + item.setText(_translate("Dialog", "Line color")) + self.tableWidget.setSortingEnabled(__sortingEnabled) diff --git a/nmreval/gui_qt/_py/graph.py b/nmreval/gui_qt/_py/graph.py new file mode 100644 index 0000000..32e7c0e --- /dev/null +++ b/nmreval/gui_qt/_py/graph.py @@ -0,0 +1,275 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/graph.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_GraphWindow(object): + def setupUi(self, GraphWindow): + GraphWindow.setObjectName("GraphWindow") + GraphWindow.resize(680, 520) + GraphWindow.setBaseSize(QtCore.QSize(300, 10)) + self.verticalLayout = QtWidgets.QVBoxLayout(GraphWindow) + self.verticalLayout.setContentsMargins(3, 3, 3, 3) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.widget = QtWidgets.QWidget(GraphWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth()) + self.widget.setSizePolicy(sizePolicy) + self.widget.setObjectName("widget") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setSpacing(1) + self.horizontalLayout.setObjectName("horizontalLayout") + self.logx_button = QtWidgets.QToolButton(self.widget) + self.logx_button.setIconSize(QtCore.QSize(16, 16)) + self.logx_button.setCheckable(True) + self.logx_button.setAutoRaise(True) + self.logx_button.setObjectName("logx_button") + self.horizontalLayout.addWidget(self.logx_button) + self.logy_button = QtWidgets.QToolButton(self.widget) + self.logy_button.setIconSize(QtCore.QSize(16, 16)) + self.logy_button.setCheckable(True) + self.logy_button.setAutoRaise(True) + self.logy_button.setObjectName("logy_button") + self.horizontalLayout.addWidget(self.logy_button) + self.line = QtWidgets.QFrame(self.widget) + self.line.setFrameShape(QtWidgets.QFrame.VLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.horizontalLayout.addWidget(self.line) + self.gridbutton = QtWidgets.QToolButton(self.widget) + self.gridbutton.setCheckable(True) + self.gridbutton.setAutoRaise(True) + self.gridbutton.setObjectName("gridbutton") + self.horizontalLayout.addWidget(self.gridbutton) + self.bwbutton = QtWidgets.QToolButton(self.widget) + self.bwbutton.setCheckable(True) + self.bwbutton.setAutoRaise(True) + self.bwbutton.setObjectName("bwbutton") + self.horizontalLayout.addWidget(self.bwbutton) + self.line_2 = QtWidgets.QFrame(self.widget) + self.line_2.setFrameShape(QtWidgets.QFrame.VLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.horizontalLayout.addWidget(self.line_2) + self.legend_button = QtWidgets.QToolButton(self.widget) + self.legend_button.setIconSize(QtCore.QSize(16, 16)) + self.legend_button.setCheckable(True) + self.legend_button.setAutoRaise(True) + self.legend_button.setObjectName("legend_button") + self.horizontalLayout.addWidget(self.legend_button) + self.imag_button = QtWidgets.QToolButton(self.widget) + self.imag_button.setIconSize(QtCore.QSize(16, 16)) + self.imag_button.setCheckable(True) + self.imag_button.setChecked(True) + self.imag_button.setAutoRaise(True) + self.imag_button.setObjectName("imag_button") + self.horizontalLayout.addWidget(self.imag_button) + self.real_button = QtWidgets.QToolButton(self.widget) + self.real_button.setIconSize(QtCore.QSize(16, 16)) + self.real_button.setCheckable(True) + self.real_button.setChecked(True) + self.real_button.setAutoRaise(True) + self.real_button.setObjectName("real_button") + self.horizontalLayout.addWidget(self.real_button) + self.error_button = QtWidgets.QToolButton(self.widget) + self.error_button.setIconSize(QtCore.QSize(16, 16)) + self.error_button.setCheckable(True) + self.error_button.setAutoRaise(True) + self.error_button.setObjectName("error_button") + self.horizontalLayout.addWidget(self.error_button) + self.line_3 = QtWidgets.QFrame(self.widget) + self.line_3.setFrameShape(QtWidgets.QFrame.VLine) + self.line_3.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_3.setObjectName("line_3") + self.horizontalLayout.addWidget(self.line_3) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.limit_button = QtWidgets.QToolButton(self.widget) + self.limit_button.setCheckable(True) + self.limit_button.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + self.limit_button.setAutoRaise(True) + self.limit_button.setArrowType(QtCore.Qt.RightArrow) + self.limit_button.setObjectName("limit_button") + self.horizontalLayout.addWidget(self.limit_button) + self.label_button = QtWidgets.QToolButton(self.widget) + self.label_button.setCheckable(True) + self.label_button.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + self.label_button.setAutoRaise(True) + self.label_button.setArrowType(QtCore.Qt.RightArrow) + self.label_button.setObjectName("label_button") + self.horizontalLayout.addWidget(self.label_button) + self.verticalLayout.addWidget(self.widget) + self.line_4 = QtWidgets.QFrame(GraphWindow) + self.line_4.setFrameShape(QtWidgets.QFrame.HLine) + self.line_4.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_4.setObjectName("line_4") + self.verticalLayout.addWidget(self.line_4) + self.limit_widget = QtWidgets.QWidget(GraphWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.limit_widget.sizePolicy().hasHeightForWidth()) + self.limit_widget.setSizePolicy(sizePolicy) + self.limit_widget.setObjectName("limit_widget") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.limit_widget) + self.horizontalLayout_2.setContentsMargins(1, 1, 1, 1) + self.horizontalLayout_2.setSpacing(2) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label = QtWidgets.QLabel(self.limit_widget) + self.label.setObjectName("label") + self.horizontalLayout_2.addWidget(self.label) + self.xmin_lineedit = QtWidgets.QLineEdit(self.limit_widget) + self.xmin_lineedit.setObjectName("xmin_lineedit") + self.horizontalLayout_2.addWidget(self.xmin_lineedit) + self.label_2 = QtWidgets.QLabel(self.limit_widget) + self.label_2.setObjectName("label_2") + self.horizontalLayout_2.addWidget(self.label_2) + self.xmax_lineedit = QtWidgets.QLineEdit(self.limit_widget) + self.xmax_lineedit.setObjectName("xmax_lineedit") + self.horizontalLayout_2.addWidget(self.xmax_lineedit) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem1) + self.label_3 = QtWidgets.QLabel(self.limit_widget) + self.label_3.setObjectName("label_3") + self.horizontalLayout_2.addWidget(self.label_3) + self.ymin_lineedit = QtWidgets.QLineEdit(self.limit_widget) + self.ymin_lineedit.setObjectName("ymin_lineedit") + self.horizontalLayout_2.addWidget(self.ymin_lineedit) + self.label_4 = QtWidgets.QLabel(self.limit_widget) + self.label_4.setObjectName("label_4") + self.horizontalLayout_2.addWidget(self.label_4) + self.ymax_lineedit = QtWidgets.QLineEdit(self.limit_widget) + self.ymax_lineedit.setObjectName("ymax_lineedit") + self.horizontalLayout_2.addWidget(self.ymax_lineedit) + self.apply_button = QtWidgets.QPushButton(self.limit_widget) + icon = QtGui.QIcon.fromTheme("dialog-ok") + self.apply_button.setIcon(icon) + self.apply_button.setObjectName("apply_button") + self.horizontalLayout_2.addWidget(self.apply_button) + self.verticalLayout.addWidget(self.limit_widget) + self.label_widget = QtWidgets.QWidget(GraphWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_widget.sizePolicy().hasHeightForWidth()) + self.label_widget.setSizePolicy(sizePolicy) + self.label_widget.setObjectName("label_widget") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.label_widget) + self.horizontalLayout_3.setContentsMargins(1, 1, 1, 1) + self.horizontalLayout_3.setSpacing(2) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.label_5 = QtWidgets.QLabel(self.label_widget) + self.label_5.setObjectName("label_5") + self.horizontalLayout_3.addWidget(self.label_5) + self.title_lineedit = QtWidgets.QLineEdit(self.label_widget) + self.title_lineedit.setObjectName("title_lineedit") + self.horizontalLayout_3.addWidget(self.title_lineedit) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_3.addItem(spacerItem2) + self.label_6 = QtWidgets.QLabel(self.label_widget) + self.label_6.setObjectName("label_6") + self.horizontalLayout_3.addWidget(self.label_6) + self.xaxis_linedit = QtWidgets.QLineEdit(self.label_widget) + self.xaxis_linedit.setObjectName("xaxis_linedit") + self.horizontalLayout_3.addWidget(self.xaxis_linedit) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_3.addItem(spacerItem3) + self.label_7 = QtWidgets.QLabel(self.label_widget) + self.label_7.setObjectName("label_7") + self.horizontalLayout_3.addWidget(self.label_7) + self.yaxis_linedit = QtWidgets.QLineEdit(self.label_widget) + self.yaxis_linedit.setObjectName("yaxis_linedit") + self.horizontalLayout_3.addWidget(self.yaxis_linedit) + self.verticalLayout.addWidget(self.label_widget) + self.gridLayout = QtWidgets.QGridLayout() + self.gridLayout.setHorizontalSpacing(3) + self.gridLayout.setVerticalSpacing(0) + self.gridLayout.setObjectName("gridLayout") + self.listWidget = QtWidgets.QListWidget(GraphWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth()) + self.listWidget.setSizePolicy(sizePolicy) + self.listWidget.setObjectName("listWidget") + self.gridLayout.addWidget(self.listWidget, 1, 1, 1, 1) + self.checkBox = QtWidgets.QCheckBox(GraphWindow) + self.checkBox.setChecked(True) + self.checkBox.setObjectName("checkBox") + self.gridLayout.addWidget(self.checkBox, 0, 1, 1, 1) + self.graphic = PlotWidget(GraphWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.graphic.sizePolicy().hasHeightForWidth()) + self.graphic.setSizePolicy(sizePolicy) + self.graphic.setObjectName("graphic") + self.gridLayout.addWidget(self.graphic, 0, 0, 2, 1) + self.verticalLayout.addLayout(self.gridLayout) + self.label.setBuddy(self.xmin_lineedit) + self.label_2.setBuddy(self.xmax_lineedit) + self.label_3.setBuddy(self.ymin_lineedit) + self.label_4.setBuddy(self.ymax_lineedit) + self.label_5.setBuddy(self.title_lineedit) + self.label_6.setBuddy(self.xaxis_linedit) + self.label_7.setBuddy(self.yaxis_linedit) + + self.retranslateUi(GraphWindow) + QtCore.QMetaObject.connectSlotsByName(GraphWindow) + GraphWindow.setTabOrder(self.logx_button, self.logy_button) + GraphWindow.setTabOrder(self.logy_button, self.gridbutton) + GraphWindow.setTabOrder(self.gridbutton, self.legend_button) + GraphWindow.setTabOrder(self.legend_button, self.imag_button) + GraphWindow.setTabOrder(self.imag_button, self.error_button) + GraphWindow.setTabOrder(self.error_button, self.limit_button) + GraphWindow.setTabOrder(self.limit_button, self.label_button) + GraphWindow.setTabOrder(self.label_button, self.xmin_lineedit) + GraphWindow.setTabOrder(self.xmin_lineedit, self.xmax_lineedit) + GraphWindow.setTabOrder(self.xmax_lineedit, self.ymin_lineedit) + GraphWindow.setTabOrder(self.ymin_lineedit, self.ymax_lineedit) + GraphWindow.setTabOrder(self.ymax_lineedit, self.title_lineedit) + GraphWindow.setTabOrder(self.title_lineedit, self.xaxis_linedit) + GraphWindow.setTabOrder(self.xaxis_linedit, self.yaxis_linedit) + + def retranslateUi(self, GraphWindow): + _translate = QtCore.QCoreApplication.translate + GraphWindow.setWindowTitle(_translate("GraphWindow", "Form")) + self.logx_button.setToolTip(_translate("GraphWindow", "Change x axis linear <-> logarithmic")) + self.logx_button.setText(_translate("GraphWindow", "Log X")) + self.logy_button.setToolTip(_translate("GraphWindow", "Change y axis linear <-> logarithmic")) + self.logy_button.setText(_translate("GraphWindow", "Log Y")) + self.gridbutton.setToolTip(_translate("GraphWindow", "Show/hide grid")) + self.gridbutton.setText(_translate("GraphWindow", "Grid")) + self.bwbutton.setToolTip(_translate("GraphWindow", "Change background")) + self.bwbutton.setText(_translate("GraphWindow", "Black/white")) + self.legend_button.setToolTip(_translate("GraphWindow", "Change legend")) + self.legend_button.setText(_translate("GraphWindow", "Legend")) + self.imag_button.setToolTip(_translate("GraphWindow", "Show/hide imaginary part")) + self.imag_button.setText(_translate("GraphWindow", "Imaginary")) + self.real_button.setToolTip(_translate("GraphWindow", "Show/hide real part")) + self.real_button.setText(_translate("GraphWindow", "Real")) + self.error_button.setToolTip(_translate("GraphWindow", "Show/hide errorbars")) + self.error_button.setText(_translate("GraphWindow", "Errorbars")) + self.limit_button.setText(_translate("GraphWindow", "Limits")) + self.label_button.setText(_translate("GraphWindow", "Labels")) + self.label.setText(_translate("GraphWindow", "X: ")) + self.label_2.setText(_translate("GraphWindow", "---")) + self.label_3.setText(_translate("GraphWindow", "Y: ")) + self.label_4.setText(_translate("GraphWindow", "---")) + self.apply_button.setText(_translate("GraphWindow", "Apply")) + self.label_5.setText(_translate("GraphWindow", "Title")) + self.label_6.setText(_translate("GraphWindow", "X Axis")) + self.label_7.setText(_translate("GraphWindow", "Y Axis")) + self.checkBox.setText(_translate("GraphWindow", "Show legend")) +from pyqtgraph import PlotWidget diff --git a/nmreval/gui_qt/_py/guidelinewidget.py b/nmreval/gui_qt/_py/guidelinewidget.py new file mode 100644 index 0000000..a69a325 --- /dev/null +++ b/nmreval/gui_qt/_py/guidelinewidget.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/guidelinewidget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(431, 799) + self.gridLayout_2 = QtWidgets.QGridLayout(Form) + self.gridLayout_2.setContentsMargins(3, 3, 3, 3) + self.gridLayout_2.setSpacing(3) + self.gridLayout_2.setObjectName("gridLayout_2") + self.mode_comboBox = QtWidgets.QComboBox(Form) + self.mode_comboBox.setObjectName("mode_comboBox") + self.mode_comboBox.addItem("") + self.mode_comboBox.addItem("") + self.gridLayout_2.addWidget(self.mode_comboBox, 2, 0, 1, 2) + self.graph_comboBox = QtWidgets.QComboBox(Form) + self.graph_comboBox.setObjectName("graph_comboBox") + self.gridLayout_2.addWidget(self.graph_comboBox, 0, 0, 1, 2) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.diagonal_widget = QtWidgets.QWidget(Form) + self.diagonal_widget.setObjectName("diagonal_widget") + self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.diagonal_widget) + self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.horizontalLayout_2.addWidget(self.diagonal_widget) + self.vh_widget = QtWidgets.QWidget(Form) + self.vh_widget.setObjectName("vh_widget") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.vh_widget) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(self.vh_widget) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.vh_pos_lineEdit = QtWidgets.QLineEdit(self.vh_widget) + self.vh_pos_lineEdit.setObjectName("vh_pos_lineEdit") + self.horizontalLayout.addWidget(self.vh_pos_lineEdit) + self.horizontalLayout_2.addWidget(self.vh_widget) + self.drag_checkBox = QtWidgets.QCheckBox(Form) + self.drag_checkBox.setChecked(True) + self.drag_checkBox.setObjectName("drag_checkBox") + self.horizontalLayout_2.addWidget(self.drag_checkBox) + self.gridLayout_2.addLayout(self.horizontalLayout_2, 3, 0, 1, 2) + self.color_comboBox = ColorListEditor(Form) + self.color_comboBox.setObjectName("color_comboBox") + self.gridLayout_2.addWidget(self.color_comboBox, 6, 1, 1, 1) + self.pushButton = QtWidgets.QPushButton(Form) + self.pushButton.setObjectName("pushButton") + self.gridLayout_2.addWidget(self.pushButton, 7, 0, 1, 2) + self.label_6 = QtWidgets.QLabel(Form) + self.label_6.setObjectName("label_6") + self.gridLayout_2.addWidget(self.label_6, 5, 0, 1, 1) + self.comment_lineEdit = QtWidgets.QLineEdit(Form) + self.comment_lineEdit.setObjectName("comment_lineEdit") + self.gridLayout_2.addWidget(self.comment_lineEdit, 5, 1, 1, 1) + self.label_2 = QtWidgets.QLabel(Form) + self.label_2.setObjectName("label_2") + self.gridLayout_2.addWidget(self.label_2, 6, 0, 1, 1) + self.tableWidget = QtWidgets.QTableWidget(Form) + self.tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget.setColumnCount(2) + self.tableWidget.setObjectName("tableWidget") + self.tableWidget.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(1, item) + self.tableWidget.horizontalHeader().setVisible(True) + self.tableWidget.horizontalHeader().setStretchLastSection(True) + self.gridLayout_2.addWidget(self.tableWidget, 8, 0, 1, 2) + self.line = QtWidgets.QFrame(Form) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.gridLayout_2.addWidget(self.line, 1, 0, 1, 2) + self.line_2 = QtWidgets.QFrame(Form) + self.line_2.setFrameShape(QtWidgets.QFrame.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.gridLayout_2.addWidget(self.line_2, 4, 0, 1, 2) + self.label.setBuddy(self.vh_pos_lineEdit) + self.label_6.setBuddy(self.comment_lineEdit) + self.label_2.setBuddy(self.color_comboBox) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + Form.setTabOrder(self.graph_comboBox, self.mode_comboBox) + Form.setTabOrder(self.mode_comboBox, self.vh_pos_lineEdit) + Form.setTabOrder(self.vh_pos_lineEdit, self.drag_checkBox) + Form.setTabOrder(self.drag_checkBox, self.comment_lineEdit) + Form.setTabOrder(self.comment_lineEdit, self.color_comboBox) + Form.setTabOrder(self.color_comboBox, self.pushButton) + Form.setTabOrder(self.pushButton, self.tableWidget) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.mode_comboBox.setItemText(0, _translate("Form", "Vertical")) + self.mode_comboBox.setItemText(1, _translate("Form", "Horizontal")) + self.label.setText(_translate("Form", "Position")) + self.vh_pos_lineEdit.setText(_translate("Form", "0")) + self.drag_checkBox.setText(_translate("Form", "Drag enabled")) + self.pushButton.setText(_translate("Form", "Create line")) + self.label_6.setText(_translate("Form", "Comment")) + self.label_2.setText(_translate("Form", "Color")) + item = self.tableWidget.horizontalHeaderItem(0) + item.setText(_translate("Form", "Pos.")) + item = self.tableWidget.horizontalHeaderItem(1) + item.setText(_translate("Form", "Comment")) +from ..lib.delegates import ColorListEditor diff --git a/nmreval/gui_qt/_py/hdftree.py b/nmreval/gui_qt/_py/hdftree.py new file mode 100644 index 0000000..b0e89f1 --- /dev/null +++ b/nmreval/gui_qt/_py/hdftree.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/hdftree.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Hdf_Dialog(object): + def setupUi(self, Hdf_Dialog): + Hdf_Dialog.setObjectName("Hdf_Dialog") + Hdf_Dialog.resize(460, 772) + self.verticalLayout = QtWidgets.QVBoxLayout(Hdf_Dialog) + self.verticalLayout.setContentsMargins(4, 4, 4, 4) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.verticalLayout_3 = QtWidgets.QVBoxLayout() + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.verticalLayout.addLayout(self.verticalLayout_3) + self.widget = QtWidgets.QWidget(Hdf_Dialog) + self.widget.setObjectName("widget") + self.gridLayout = QtWidgets.QGridLayout(self.widget) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setSpacing(2) + self.gridLayout.setObjectName("gridLayout") + self.comboBox_2 = QtWidgets.QComboBox(self.widget) + self.comboBox_2.setObjectName("comboBox_2") + self.gridLayout.addWidget(self.comboBox_2, 1, 1, 1, 1) + self.label = QtWidgets.QLabel(self.widget) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + self.label_2 = QtWidgets.QLabel(self.widget) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) + self.comboBox = QtWidgets.QComboBox(self.widget) + self.comboBox.setObjectName("comboBox") + self.gridLayout.addWidget(self.comboBox, 0, 1, 1, 1) + self.verticalLayout.addWidget(self.widget) + self.widget_2 = ExpandableWidget(Hdf_Dialog) + self.widget_2.setObjectName("widget_2") + self.verticalLayout.addWidget(self.widget_2) + self.buttonBox = QtWidgets.QDialogButtonBox(Hdf_Dialog) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + + self.retranslateUi(Hdf_Dialog) + self.buttonBox.rejected.connect(Hdf_Dialog.close) + self.buttonBox.accepted.connect(Hdf_Dialog.accept) + QtCore.QMetaObject.connectSlotsByName(Hdf_Dialog) + + def retranslateUi(self, Hdf_Dialog): + _translate = QtCore.QCoreApplication.translate + Hdf_Dialog.setWindowTitle(_translate("Hdf_Dialog", "View HDF file")) + self.label.setText(_translate("Hdf_Dialog", "Label")) + self.label_2.setText(_translate("Hdf_Dialog", "Group")) +from ..lib.expandablewidget import ExpandableWidget diff --git a/nmreval/gui_qt/_py/integral_widget.py b/nmreval/gui_qt/_py/integral_widget.py new file mode 100644 index 0000000..4f16d93 --- /dev/null +++ b/nmreval/gui_qt/_py/integral_widget.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/integral_widget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(397, 681) + self.verticalLayout = QtWidgets.QVBoxLayout(Form) + self.verticalLayout.setContentsMargins(3, 3, 3, 3) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.label_2 = QtWidgets.QLabel(Form) + self.label_2.setObjectName("label_2") + self.verticalLayout.addWidget(self.label_2) + self.set_combobox = QtWidgets.QComboBox(Form) + self.set_combobox.setObjectName("set_combobox") + self.verticalLayout.addWidget(self.set_combobox) + self.treeWidget = QtWidgets.QTreeWidget(Form) + self.treeWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.treeWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.treeWidget.setHeaderHidden(True) + self.treeWidget.setObjectName("treeWidget") + self.treeWidget.headerItem().setText(0, "1") + self.verticalLayout.addWidget(self.treeWidget) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setSpacing(3) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(Form) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.pushButton = QtWidgets.QPushButton(Form) + self.pushButton.setObjectName("pushButton") + self.horizontalLayout.addWidget(self.pushButton) + self.verticalLayout.addLayout(self.horizontalLayout) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label_2.setText(_translate("Form", "TextLabel")) + self.label.setText(_translate("Form", "Save integrals as dataset")) + self.pushButton.setText(_translate("Form", "Apply")) diff --git a/nmreval/gui_qt/_py/integratederive_dialog.py b/nmreval/gui_qt/_py/integratederive_dialog.py new file mode 100644 index 0000000..0ae75f4 --- /dev/null +++ b/nmreval/gui_qt/_py/integratederive_dialog.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/integratederive_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(400, 308) + self.verticalLayout = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout.setObjectName("verticalLayout") + self.listWidget = QtWidgets.QListWidget(Dialog) + self.listWidget.setObjectName("listWidget") + self.verticalLayout.addWidget(self.listWidget) + self.widget = QtWidgets.QWidget(Dialog) + self.widget.setObjectName("widget") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(self.widget) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.start_lineedit = QtWidgets.QLineEdit(self.widget) + self.start_lineedit.setEnabled(False) + self.start_lineedit.setObjectName("start_lineedit") + self.horizontalLayout.addWidget(self.start_lineedit) + self.stop_lineedit = QtWidgets.QLineEdit(self.widget) + self.stop_lineedit.setEnabled(False) + self.stop_lineedit.setObjectName("stop_lineedit") + self.horizontalLayout.addWidget(self.stop_lineedit) + self.range_checkbox = QtWidgets.QCheckBox(self.widget) + self.range_checkbox.setChecked(True) + self.range_checkbox.setObjectName("range_checkbox") + self.horizontalLayout.addWidget(self.range_checkbox) + self.verticalLayout.addWidget(self.widget) + self.ft_comboBox = QtWidgets.QComboBox(Dialog) + self.ft_comboBox.setObjectName("ft_comboBox") + self.ft_comboBox.addItem("") + self.ft_comboBox.addItem("") + self.ft_comboBox.addItem("") + self.verticalLayout.addWidget(self.ft_comboBox) + self.log_checkbox = QtWidgets.QCheckBox(Dialog) + self.log_checkbox.setObjectName("log_checkbox") + self.verticalLayout.addWidget(self.log_checkbox) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout_2.setSpacing(3) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.newgraph_checkbox = QtWidgets.QCheckBox(Dialog) + self.newgraph_checkbox.setObjectName("newgraph_checkbox") + self.horizontalLayout_2.addWidget(self.newgraph_checkbox) + self.graph_combobox = QtWidgets.QComboBox(Dialog) + self.graph_combobox.setObjectName("graph_combobox") + self.horizontalLayout_2.addWidget(self.graph_combobox) + self.verticalLayout.addLayout(self.horizontalLayout_2) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Dialog")) + self.label.setText(_translate("Dialog", "Limits")) + self.range_checkbox.setText(_translate("Dialog", "Full")) + self.ft_comboBox.setItemText(0, _translate("Dialog", "Real")) + self.ft_comboBox.setItemText(1, _translate("Dialog", "Imag")) + self.ft_comboBox.setItemText(2, _translate("Dialog", "Complex")) + self.log_checkbox.setText(_translate("Dialog", "use logarithmic x axis")) + self.newgraph_checkbox.setText(_translate("Dialog", "New graph")) diff --git a/nmreval/gui_qt/_py/interpol_dialog.py b/nmreval/gui_qt/_py/interpol_dialog.py new file mode 100644 index 0000000..c819070 --- /dev/null +++ b/nmreval/gui_qt/_py/interpol_dialog.py @@ -0,0 +1,166 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/interpol_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(416, 494) + self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setContentsMargins(3, 3, 3, 3) + self.gridLayout.setSpacing(3) + self.gridLayout.setObjectName("gridLayout") + self.src_widget = QtWidgets.QWidget(Dialog) + self.src_widget.setObjectName("src_widget") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.src_widget) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setSpacing(3) + self.horizontalLayout.setObjectName("horizontalLayout") + self.graph_combobox = QtWidgets.QComboBox(self.src_widget) + self.graph_combobox.setObjectName("graph_combobox") + self.horizontalLayout.addWidget(self.graph_combobox) + self.set_combobox = QtWidgets.QComboBox(self.src_widget) + self.set_combobox.setObjectName("set_combobox") + self.horizontalLayout.addWidget(self.set_combobox) + self.gridLayout.addWidget(self.src_widget, 8, 0, 1, 2) + self.label_3 = QtWidgets.QLabel(Dialog) + self.label_3.setObjectName("label_3") + self.gridLayout.addWidget(self.label_3, 0, 0, 1, 1) + self.label = QtWidgets.QLabel(Dialog) + self.label.setToolTip("") + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 4, 0, 1, 1) + self.line_2 = QtWidgets.QFrame(Dialog) + self.line_2.setFrameShape(QtWidgets.QFrame.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.gridLayout.addWidget(self.line_2, 5, 0, 1, 2) + self.ylog_checkBox = QtWidgets.QCheckBox(Dialog) + self.ylog_checkBox.setObjectName("ylog_checkBox") + self.gridLayout.addWidget(self.ylog_checkBox, 2, 1, 1, 1) + self.interp_comboBox = QtWidgets.QComboBox(Dialog) + self.interp_comboBox.setToolTip("") + self.interp_comboBox.setObjectName("interp_comboBox") + self.interp_comboBox.addItem("") + self.interp_comboBox.addItem("") + self.gridLayout.addWidget(self.interp_comboBox, 4, 1, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 12, 0, 1, 2) + self.line = QtWidgets.QFrame(Dialog) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.gridLayout.addWidget(self.line, 3, 0, 1, 2) + self.label_2 = QtWidgets.QLabel(Dialog) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 6, 0, 1, 1) + self.listWidget = QtWidgets.QListWidget(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth()) + self.listWidget.setSizePolicy(sizePolicy) + self.listWidget.setObjectName("listWidget") + self.gridLayout.addWidget(self.listWidget, 1, 0, 1, 2) + self.sampling_widget = QtWidgets.QWidget(Dialog) + self.sampling_widget.setObjectName("sampling_widget") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.sampling_widget) + self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_2.setSpacing(3) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label_4 = QtWidgets.QLabel(self.sampling_widget) + self.label_4.setObjectName("label_4") + self.horizontalLayout_2.addWidget(self.label_4) + self.start_lineEdit = QtWidgets.QLineEdit(self.sampling_widget) + self.start_lineEdit.setObjectName("start_lineEdit") + self.horizontalLayout_2.addWidget(self.start_lineEdit) + self.label_5 = QtWidgets.QLabel(self.sampling_widget) + self.label_5.setObjectName("label_5") + self.horizontalLayout_2.addWidget(self.label_5) + self.stop_lineEdit = QtWidgets.QLineEdit(self.sampling_widget) + self.stop_lineEdit.setObjectName("stop_lineEdit") + self.horizontalLayout_2.addWidget(self.stop_lineEdit) + self.label_6 = QtWidgets.QLabel(self.sampling_widget) + self.label_6.setObjectName("label_6") + self.horizontalLayout_2.addWidget(self.label_6) + self.step_lineEdit = QtWidgets.QLineEdit(self.sampling_widget) + self.step_lineEdit.setObjectName("step_lineEdit") + self.horizontalLayout_2.addWidget(self.step_lineEdit) + self.logspace_checkBox = QtWidgets.QCheckBox(self.sampling_widget) + self.logspace_checkBox.setObjectName("logspace_checkBox") + self.horizontalLayout_2.addWidget(self.logspace_checkBox) + self.gridLayout.addWidget(self.sampling_widget, 7, 0, 1, 2) + self.xaxis_comboBox = QtWidgets.QComboBox(Dialog) + self.xaxis_comboBox.setObjectName("xaxis_comboBox") + self.xaxis_comboBox.addItem("") + self.xaxis_comboBox.addItem("") + self.gridLayout.addWidget(self.xaxis_comboBox, 6, 1, 1, 1) + self.line_3 = QtWidgets.QFrame(Dialog) + self.line_3.setFrameShape(QtWidgets.QFrame.HLine) + self.line_3.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_3.setObjectName("line_3") + self.gridLayout.addWidget(self.line_3, 9, 0, 1, 2) + self.dest_combobox = QtWidgets.QComboBox(Dialog) + self.dest_combobox.setObjectName("dest_combobox") + self.gridLayout.addWidget(self.dest_combobox, 10, 1, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem, 11, 0, 1, 1) + self.label_8 = QtWidgets.QLabel(Dialog) + self.label_8.setObjectName("label_8") + self.gridLayout.addWidget(self.label_8, 10, 0, 1, 1) + self.xlog_checkBox = QtWidgets.QCheckBox(Dialog) + self.xlog_checkBox.setObjectName("xlog_checkBox") + self.gridLayout.addWidget(self.xlog_checkBox, 2, 0, 1, 1) + self.label.setBuddy(self.interp_comboBox) + self.label_2.setBuddy(self.xaxis_comboBox) + self.label_4.setBuddy(self.start_lineEdit) + self.label_5.setBuddy(self.stop_lineEdit) + self.label_6.setBuddy(self.step_lineEdit) + self.label_8.setBuddy(self.dest_combobox) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + Dialog.setTabOrder(self.listWidget, self.ylog_checkBox) + Dialog.setTabOrder(self.ylog_checkBox, self.interp_comboBox) + Dialog.setTabOrder(self.interp_comboBox, self.xaxis_comboBox) + Dialog.setTabOrder(self.xaxis_comboBox, self.start_lineEdit) + Dialog.setTabOrder(self.start_lineEdit, self.stop_lineEdit) + Dialog.setTabOrder(self.stop_lineEdit, self.step_lineEdit) + Dialog.setTabOrder(self.step_lineEdit, self.logspace_checkBox) + Dialog.setTabOrder(self.logspace_checkBox, self.graph_combobox) + Dialog.setTabOrder(self.graph_combobox, self.set_combobox) + Dialog.setTabOrder(self.set_combobox, self.dest_combobox) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Data interpolation")) + self.label_3.setText(_translate("Dialog", "Source data")) + self.label.setText(_translate("Dialog", "Spline")) + self.ylog_checkBox.setToolTip(_translate("Dialog", "If your data is on a logarithmic scale in y, check this box")) + self.ylog_checkBox.setText(_translate("Dialog", "use log(y)")) + self.interp_comboBox.setItemText(0, _translate("Dialog", "Cubic")) + self.interp_comboBox.setItemText(1, _translate("Dialog", "Linear")) + self.buttonBox.setToolTip(_translate("Dialog", "Accept to create new data sets.")) + self.label_2.setText(_translate("Dialog", "New x axis")) + self.listWidget.setToolTip(_translate("Dialog", "Select sets that shall be interpolated. No selection will create interpolations of all visible sets.")) + self.label_4.setText(_translate("Dialog", "Start")) + self.label_5.setText(_translate("Dialog", "Stop")) + self.label_6.setText(_translate("Dialog", "Steps")) + self.logspace_checkBox.setText(_translate("Dialog", "log-spaced?")) + self.xaxis_comboBox.setItemText(0, _translate("Dialog", "new values")) + self.xaxis_comboBox.setItemText(1, _translate("Dialog", "from data")) + self.label_8.setText(_translate("Dialog", "Add interpolated data to")) + self.xlog_checkBox.setText(_translate("Dialog", "use log(x)")) diff --git a/nmreval/gui_qt/_py/lineedit_dialog.py b/nmreval/gui_qt/_py/lineedit_dialog.py new file mode 100644 index 0000000..5a1bf2c --- /dev/null +++ b/nmreval/gui_qt/_py/lineedit_dialog.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/lineedit_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_LineEdit_Dialog(object): + def setupUi(self, LineEdit_Dialog): + LineEdit_Dialog.setObjectName("LineEdit_Dialog") + LineEdit_Dialog.resize(400, 84) + self.formLayout = QtWidgets.QFormLayout(LineEdit_Dialog) + self.formLayout.setFieldGrowthPolicy(QtWidgets.QFormLayout.ExpandingFieldsGrow) + self.formLayout.setObjectName("formLayout") + self.label = QtWidgets.QLabel(LineEdit_Dialog) + self.label.setObjectName("label") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label) + self.new_string = QtWidgets.QLineEdit(LineEdit_Dialog) + self.new_string.setObjectName("new_string") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.new_string) + self.buttonBox = QtWidgets.QDialogButtonBox(LineEdit_Dialog) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.SpanningRole, self.buttonBox) + + self.retranslateUi(LineEdit_Dialog) + self.buttonBox.accepted.connect(LineEdit_Dialog.accept) + self.buttonBox.rejected.connect(LineEdit_Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(LineEdit_Dialog) + + def retranslateUi(self, LineEdit_Dialog): + _translate = QtCore.QCoreApplication.translate + LineEdit_Dialog.setWindowTitle(_translate("LineEdit_Dialog", "Dialog")) + self.label.setText(_translate("LineEdit_Dialog", "Label")) diff --git a/nmreval/gui_qt/_py/mean_form.py b/nmreval/gui_qt/_py/mean_form.py new file mode 100644 index 0000000..f120794 --- /dev/null +++ b/nmreval/gui_qt/_py/mean_form.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/mean_form.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_mean_form(object): + def setupUi(self, mean_form): + mean_form.setObjectName("mean_form") + mean_form.resize(712, 34) + self.horizontalLayout = QtWidgets.QHBoxLayout(mean_form) + self.horizontalLayout.setContentsMargins(1, 1, 1, 1) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(mean_form) + self.label.setAlignment(QtCore.Qt.AlignCenter) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.digit_checkbox = QtWidgets.QCheckBox(mean_form) + self.digit_checkbox.setChecked(True) + self.digit_checkbox.setObjectName("digit_checkbox") + self.horizontalLayout.addWidget(self.digit_checkbox) + self.lineEdit = QtWidgets.QLineEdit(mean_form) + self.lineEdit.setObjectName("lineEdit") + self.horizontalLayout.addWidget(self.lineEdit) + self.data_checkbox = QtWidgets.QCheckBox(mean_form) + self.data_checkbox.setObjectName("data_checkbox") + self.horizontalLayout.addWidget(self.data_checkbox) + self.frame = QtWidgets.QFrame(mean_form) + self.frame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.frame.setObjectName("frame") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame) + self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_2.setSpacing(2) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.graph_combobox = QtWidgets.QComboBox(self.frame) + self.graph_combobox.setObjectName("graph_combobox") + self.horizontalLayout_2.addWidget(self.graph_combobox) + self.set_combobox = QtWidgets.QComboBox(self.frame) + self.set_combobox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) + self.set_combobox.setObjectName("set_combobox") + self.horizontalLayout_2.addWidget(self.set_combobox) + self.horizontalLayout.addWidget(self.frame) + + self.retranslateUi(mean_form) + QtCore.QMetaObject.connectSlotsByName(mean_form) + + def retranslateUi(self, mean_form): + _translate = QtCore.QCoreApplication.translate + mean_form.setWindowTitle(_translate("mean_form", "Form")) + self.label.setText(_translate("mean_form", "TextLabel")) + self.digit_checkbox.setText(_translate("mean_form", "Digit")) + self.lineEdit.setText(_translate("mean_form", "1")) + self.data_checkbox.setText(_translate("mean_form", "Data")) diff --git a/nmreval/gui_qt/_py/meandialog.py b/nmreval/gui_qt/_py/meandialog.py new file mode 100644 index 0000000..9a59fcf --- /dev/null +++ b/nmreval/gui_qt/_py/meandialog.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/meandialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_calc_means_dialog(object): + def setupUi(self, calc_means_dialog): + calc_means_dialog.setObjectName("calc_means_dialog") + calc_means_dialog.resize(481, 322) + self.verticalLayout_2 = QtWidgets.QVBoxLayout(calc_means_dialog) + self.verticalLayout_2.setSpacing(3) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.dist_combobox = QtWidgets.QComboBox(calc_means_dialog) + self.dist_combobox.setObjectName("dist_combobox") + self.verticalLayout_2.addWidget(self.dist_combobox) + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.verticalLayout_2.addLayout(self.verticalLayout) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.from_combobox = QtWidgets.QComboBox(calc_means_dialog) + self.from_combobox.setObjectName("from_combobox") + self.from_combobox.addItem("") + self.from_combobox.addItem("") + self.from_combobox.addItem("") + self.from_combobox.addItem("") + self.horizontalLayout.addWidget(self.from_combobox) + self.label_4 = QtWidgets.QLabel(calc_means_dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setPointSize(20) + self.label_4.setFont(font) + self.label_4.setObjectName("label_4") + self.horizontalLayout.addWidget(self.label_4) + self.to_combobox = QtWidgets.QComboBox(calc_means_dialog) + self.to_combobox.setObjectName("to_combobox") + self.to_combobox.addItem("") + self.to_combobox.addItem("") + self.to_combobox.addItem("") + self.to_combobox.addItem("") + self.horizontalLayout.addWidget(self.to_combobox) + self.verticalLayout_2.addLayout(self.horizontalLayout) + self.line = QtWidgets.QFrame(calc_means_dialog) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.verticalLayout_2.addWidget(self.line) + self.label = QtWidgets.QLabel(calc_means_dialog) + self.label.setObjectName("label") + self.verticalLayout_2.addWidget(self.label) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_2.addItem(spacerItem) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.checkBox = QtWidgets.QCheckBox(calc_means_dialog) + self.checkBox.setObjectName("checkBox") + self.horizontalLayout_2.addWidget(self.checkBox) + self.graph_combobox = QtWidgets.QComboBox(calc_means_dialog) + self.graph_combobox.setObjectName("graph_combobox") + self.horizontalLayout_2.addWidget(self.graph_combobox) + self.verticalLayout_2.addLayout(self.horizontalLayout_2) + self.buttonBox = QtWidgets.QDialogButtonBox(calc_means_dialog) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout_2.addWidget(self.buttonBox) + + self.retranslateUi(calc_means_dialog) + self.to_combobox.setCurrentIndex(1) + QtCore.QMetaObject.connectSlotsByName(calc_means_dialog) + + def retranslateUi(self, calc_means_dialog): + _translate = QtCore.QCoreApplication.translate + calc_means_dialog.setWindowTitle(_translate("calc_means_dialog", "Mean times")) + self.from_combobox.setItemText(0, _translate("calc_means_dialog", "Function value: τ")) + self.from_combobox.setItemText(1, _translate("calc_means_dialog", "Peak time: τₚ")) + self.from_combobox.setItemText(2, _translate("calc_means_dialog", "Arithmetic mean: ⟨τ⟩")) + self.from_combobox.setItemText(3, _translate("calc_means_dialog", "Geometric mean: exp( ⟨ln(τ)⟩ )")) + self.label_4.setText(_translate("calc_means_dialog", " ➝ ")) + self.to_combobox.setItemText(0, _translate("calc_means_dialog", "Function value: τ")) + self.to_combobox.setItemText(1, _translate("calc_means_dialog", "Peak time: τₚ")) + self.to_combobox.setItemText(2, _translate("calc_means_dialog", "Arithmetic mean: ⟨τ⟩")) + self.to_combobox.setItemText(3, _translate("calc_means_dialog", "Geometric mean: exp( ⟨ln(τ)⟩ )")) + self.label.setText(_translate("calc_means_dialog", "TextLabel")) + self.checkBox.setText(_translate("calc_means_dialog", "New graph")) diff --git a/nmreval/gui_qt/_py/modelwidget.py b/nmreval/gui_qt/_py/modelwidget.py new file mode 100644 index 0000000..df2c5ac --- /dev/null +++ b/nmreval/gui_qt/_py/modelwidget.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/modelwidget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(188, 44) + self.horizontalLayout = QtWidgets.QHBoxLayout(Form) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(Form) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.lineEdit = QtWidgets.QLineEdit(Form) + self.lineEdit.setObjectName("lineEdit") + self.horizontalLayout.addWidget(self.lineEdit) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label.setText(_translate("Form", "TextLabel")) diff --git a/nmreval/gui_qt/_py/move_dialog.py b/nmreval/gui_qt/_py/move_dialog.py new file mode 100644 index 0000000..4234ddb --- /dev/null +++ b/nmreval/gui_qt/_py/move_dialog.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/move_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_MoveDialog(object): + def setupUi(self, MoveDialog): + MoveDialog.setObjectName("MoveDialog") + MoveDialog.resize(395, 345) + self.gridLayout = QtWidgets.QGridLayout(MoveDialog) + self.gridLayout.setVerticalSpacing(1) + self.gridLayout.setObjectName("gridLayout") + self.tocomboBox = QtWidgets.QComboBox(MoveDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.tocomboBox.sizePolicy().hasHeightForWidth()) + self.tocomboBox.setSizePolicy(sizePolicy) + self.tocomboBox.setObjectName("tocomboBox") + self.gridLayout.addWidget(self.tocomboBox, 3, 1, 1, 1) + self.fromcomboBox = QtWidgets.QComboBox(MoveDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.fromcomboBox.sizePolicy().hasHeightForWidth()) + self.fromcomboBox.setSizePolicy(sizePolicy) + self.fromcomboBox.setObjectName("fromcomboBox") + self.gridLayout.addWidget(self.fromcomboBox, 0, 1, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(MoveDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 6, 0, 1, 2) + self.label_2 = QtWidgets.QLabel(MoveDialog) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 3, 0, 1, 1) + self.line = QtWidgets.QFrame(MoveDialog) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.gridLayout.addWidget(self.line, 4, 0, 1, 2) + self.label = QtWidgets.QLabel(MoveDialog) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout.setObjectName("horizontalLayout") + self.copy_button = QtWidgets.QRadioButton(MoveDialog) + self.copy_button.setObjectName("copy_button") + self.buttonGroup = QtWidgets.QButtonGroup(MoveDialog) + self.buttonGroup.setObjectName("buttonGroup") + self.buttonGroup.addButton(self.copy_button) + self.horizontalLayout.addWidget(self.copy_button) + self.move_button = QtWidgets.QRadioButton(MoveDialog) + self.move_button.setChecked(True) + self.move_button.setObjectName("move_button") + self.buttonGroup.addButton(self.move_button) + self.horizontalLayout.addWidget(self.move_button) + self.gridLayout.addLayout(self.horizontalLayout, 5, 0, 1, 2) + self.listWidget = QtWidgets.QListWidget(MoveDialog) + self.listWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.listWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) + self.listWidget.setObjectName("listWidget") + self.gridLayout.addWidget(self.listWidget, 1, 1, 1, 1) + self.label_2.setBuddy(self.tocomboBox) + self.label.setBuddy(self.fromcomboBox) + + self.retranslateUi(MoveDialog) + QtCore.QMetaObject.connectSlotsByName(MoveDialog) + MoveDialog.setTabOrder(self.fromcomboBox, self.listWidget) + MoveDialog.setTabOrder(self.listWidget, self.tocomboBox) + MoveDialog.setTabOrder(self.tocomboBox, self.buttonBox) + + def retranslateUi(self, MoveDialog): + _translate = QtCore.QCoreApplication.translate + MoveDialog.setWindowTitle(_translate("MoveDialog", "Insert Reel 2 Real song.")) + self.label_2.setText(_translate("MoveDialog", "To")) + self.label.setText(_translate("MoveDialog", "From")) + self.copy_button.setText(_translate("MoveDialog", "Copy")) + self.move_button.setText(_translate("MoveDialog", "Move")) diff --git a/nmreval/gui_qt/_py/namespace_widget.py b/nmreval/gui_qt/_py/namespace_widget.py new file mode 100644 index 0000000..e0f508b --- /dev/null +++ b/nmreval/gui_qt/_py/namespace_widget.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/namespace_widget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(400, 300) + self.gridLayout_2 = QtWidgets.QGridLayout(Form) + self.gridLayout_2.setContentsMargins(1, 1, 1, 1) + self.gridLayout_2.setSpacing(3) + self.gridLayout_2.setObjectName("gridLayout_2") + self.groups_comboBox = QtWidgets.QComboBox(Form) + self.groups_comboBox.setObjectName("groups_comboBox") + self.gridLayout_2.addWidget(self.groups_comboBox, 0, 0, 1, 1) + self.subgroups_comboBox = QtWidgets.QComboBox(Form) + self.subgroups_comboBox.setObjectName("subgroups_comboBox") + self.gridLayout_2.addWidget(self.subgroups_comboBox, 0, 1, 1, 1) + self.namespace_table = QtWidgets.QTableWidget(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.namespace_table.sizePolicy().hasHeightForWidth()) + self.namespace_table.setSizePolicy(sizePolicy) + self.namespace_table.setMinimumSize(QtCore.QSize(0, 0)) + self.namespace_table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.namespace_table.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.namespace_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.namespace_table.setTextElideMode(QtCore.Qt.ElideNone) + self.namespace_table.setColumnCount(2) + self.namespace_table.setObjectName("namespace_table") + self.namespace_table.setRowCount(5) + item = QtWidgets.QTableWidgetItem() + self.namespace_table.setVerticalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.namespace_table.setVerticalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + self.namespace_table.setVerticalHeaderItem(2, item) + item = QtWidgets.QTableWidgetItem() + self.namespace_table.setVerticalHeaderItem(3, item) + item = QtWidgets.QTableWidgetItem() + self.namespace_table.setVerticalHeaderItem(4, item) + self.namespace_table.horizontalHeader().setVisible(False) + self.namespace_table.horizontalHeader().setStretchLastSection(True) + self.namespace_table.verticalHeader().setVisible(False) + self.gridLayout_2.addWidget(self.namespace_table, 1, 0, 1, 2) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + item = self.namespace_table.verticalHeaderItem(0) + item.setText(_translate("Form", "Neue Zeile")) + item = self.namespace_table.verticalHeaderItem(1) + item.setText(_translate("Form", "Neue Zeile")) + item = self.namespace_table.verticalHeaderItem(2) + item.setText(_translate("Form", "Neue Zeile")) + item = self.namespace_table.verticalHeaderItem(3) + item.setText(_translate("Form", "Neue Zeile")) + item = self.namespace_table.verticalHeaderItem(4) + item.setText(_translate("Form", "Neue Zeile")) diff --git a/nmreval/gui_qt/_py/option_selection.py b/nmreval/gui_qt/_py/option_selection.py new file mode 100644 index 0000000..456ec65 --- /dev/null +++ b/nmreval/gui_qt/_py/option_selection.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/option_selection.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(400, 182) + self.gridLayout = QtWidgets.QGridLayout(Form) + self.gridLayout.setObjectName("gridLayout") + self.tableWidget = QtWidgets.QTableWidget(Form) + self.tableWidget.setObjectName("tableWidget") + self.tableWidget.setColumnCount(2) + self.tableWidget.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(1, item) + self.gridLayout.addWidget(self.tableWidget, 1, 1, 1, 1) + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.label_2 = QtWidgets.QLabel(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth()) + self.label_2.setSizePolicy(sizePolicy) + self.label_2.setObjectName("label_2") + self.verticalLayout.addWidget(self.label_2) + self.lineEdit = QtWidgets.QLineEdit(Form) + self.lineEdit.setObjectName("lineEdit") + self.verticalLayout.addWidget(self.lineEdit) + self.label = QtWidgets.QLabel(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.comboBox = QtWidgets.QComboBox(Form) + self.comboBox.setObjectName("comboBox") + self.verticalLayout.addWidget(self.comboBox) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem) + self.gridLayout.addLayout(self.verticalLayout, 1, 0, 1, 1) + self.pushButton = QtWidgets.QPushButton(Form) + self.pushButton.setObjectName("pushButton") + self.gridLayout.addWidget(self.pushButton, 2, 1, 1, 1) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + item = self.tableWidget.horizontalHeaderItem(0) + item.setText(_translate("Form", "Name")) + item = self.tableWidget.horizontalHeaderItem(1) + item.setText(_translate("Form", "Value")) + self.label_2.setText(_translate("Form", "Nice name")) + self.label.setText(_translate("Form", "TextLabel")) + self.pushButton.setText(_translate("Form", "Add option")) diff --git a/nmreval/gui_qt/_py/parameterform.py b/nmreval/gui_qt/_py/parameterform.py new file mode 100644 index 0000000..5bf7ba2 --- /dev/null +++ b/nmreval/gui_qt/_py/parameterform.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/parameterform.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_parameterform(object): + def setupUi(self, parameterform): + parameterform.setObjectName("parameterform") + parameterform.setWindowModality(QtCore.Qt.WindowModal) + parameterform.resize(290, 37) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(parameterform.sizePolicy().hasHeightForWidth()) + parameterform.setSizePolicy(sizePolicy) + parameterform.setAutoFillBackground(True) + self.horizontalLayout = QtWidgets.QHBoxLayout(parameterform) + self.horizontalLayout.setContentsMargins(1, 1, 1, 1) + self.horizontalLayout.setSpacing(2) + self.horizontalLayout.setObjectName("horizontalLayout") + self.line_2 = QtWidgets.QFrame(parameterform) + self.line_2.setFrameShape(QtWidgets.QFrame.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.horizontalLayout.addWidget(self.line_2) + self.label = QtWidgets.QLabel(parameterform) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(10) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setFrameShape(QtWidgets.QFrame.NoFrame) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + spacerItem = QtWidgets.QSpacerItem(65, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.vals = QtWidgets.QLineEdit(parameterform) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.vals.sizePolicy().hasHeightForWidth()) + self.vals.setSizePolicy(sizePolicy) + self.vals.setObjectName("vals") + self.horizontalLayout.addWidget(self.vals) + self.checkBox = QtWidgets.QCheckBox(parameterform) + self.checkBox.setObjectName("checkBox") + self.horizontalLayout.addWidget(self.checkBox) + + self.retranslateUi(parameterform) + QtCore.QMetaObject.connectSlotsByName(parameterform) + + def retranslateUi(self, parameterform): + _translate = QtCore.QCoreApplication.translate + parameterform.setWindowTitle(_translate("parameterform", "Form")) + self.label.setText(_translate("parameterform", "Name")) + self.vals.setText(_translate("parameterform", "1")) + self.checkBox.setText(_translate("parameterform", "Fix?")) diff --git a/nmreval/gui_qt/_py/phase_corr_dialog.py b/nmreval/gui_qt/_py/phase_corr_dialog.py new file mode 100644 index 0000000..02c5898 --- /dev/null +++ b/nmreval/gui_qt/_py/phase_corr_dialog.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/phase_corr_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_SignalEdit(object): + def setupUi(self, SignalEdit): + SignalEdit.setObjectName("SignalEdit") + SignalEdit.resize(919, 595) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(SignalEdit.sizePolicy().hasHeightForWidth()) + SignalEdit.setSizePolicy(sizePolicy) + self.gridLayout = QtWidgets.QGridLayout(SignalEdit) + self.gridLayout.setContentsMargins(6, 6, 6, 6) + self.gridLayout.setSpacing(3) + self.gridLayout.setObjectName("gridLayout") + self.graphicsView = PlotWidget(SignalEdit) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.graphicsView.sizePolicy().hasHeightForWidth()) + self.graphicsView.setSizePolicy(sizePolicy) + self.graphicsView.setObjectName("graphicsView") + self.gridLayout.addWidget(self.graphicsView, 0, 0, 1, 8) + self.pivot_lineedit = QtWidgets.QLineEdit(SignalEdit) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pivot_lineedit.sizePolicy().hasHeightForWidth()) + self.pivot_lineedit.setSizePolicy(sizePolicy) + self.pivot_lineedit.setInputMethodHints(QtCore.Qt.ImhDigitsOnly) + self.pivot_lineedit.setObjectName("pivot_lineedit") + self.gridLayout.addWidget(self.pivot_lineedit, 1, 7, 1, 1) + self.ph0slider = QtWidgets.QDoubleSpinBox(SignalEdit) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.ph0slider.sizePolicy().hasHeightForWidth()) + self.ph0slider.setSizePolicy(sizePolicy) + self.ph0slider.setMinimum(-180.0) + self.ph0slider.setMaximum(180.0) + self.ph0slider.setObjectName("ph0slider") + self.gridLayout.addWidget(self.ph0slider, 1, 1, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(SignalEdit) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 2, 1, 1, 7) + self.ph1slider = QtWidgets.QDoubleSpinBox(SignalEdit) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.ph1slider.sizePolicy().hasHeightForWidth()) + self.ph1slider.setSizePolicy(sizePolicy) + self.ph1slider.setMinimum(-360.0) + self.ph1slider.setMaximum(360.0) + self.ph1slider.setObjectName("ph1slider") + self.gridLayout.addWidget(self.ph1slider, 1, 4, 1, 1) + self.label_8 = QtWidgets.QLabel(SignalEdit) + self.label_8.setObjectName("label_8") + self.gridLayout.addWidget(self.label_8, 1, 6, 1, 1) + self.label_6 = QtWidgets.QLabel(SignalEdit) + self.label_6.setObjectName("label_6") + self.gridLayout.addWidget(self.label_6, 1, 3, 1, 1) + self.label = QtWidgets.QLabel(SignalEdit) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 1, 0, 1, 1) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem, 1, 2, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem1, 1, 5, 1, 1) + + self.retranslateUi(SignalEdit) + self.buttonBox.accepted.connect(SignalEdit.accept) + self.buttonBox.rejected.connect(SignalEdit.close) + QtCore.QMetaObject.connectSlotsByName(SignalEdit) + + def retranslateUi(self, SignalEdit): + _translate = QtCore.QCoreApplication.translate + SignalEdit.setWindowTitle(_translate("SignalEdit", "Phase correction")) + self.pivot_lineedit.setText(_translate("SignalEdit", "0")) + self.label_8.setText(_translate("SignalEdit", "Pivot")) + self.label_6.setText(_translate("SignalEdit", "Phase 1")) + self.label.setText(_translate("SignalEdit", "Phase 0")) +from pyqtgraph import PlotWidget diff --git a/nmreval/gui_qt/_py/plotConfigTemplate.py b/nmreval/gui_qt/_py/plotConfigTemplate.py new file mode 100644 index 0000000..a88d8db --- /dev/null +++ b/nmreval/gui_qt/_py/plotConfigTemplate.py @@ -0,0 +1,179 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/plotConfigTemplate.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(481, 840) + self.averageGroup = QtWidgets.QGroupBox(Form) + self.averageGroup.setGeometry(QtCore.QRect(0, 640, 242, 182)) + self.averageGroup.setCheckable(True) + self.averageGroup.setChecked(False) + self.averageGroup.setObjectName("averageGroup") + self.gridLayout_5 = QtWidgets.QGridLayout(self.averageGroup) + self.gridLayout_5.setContentsMargins(0, 0, 0, 0) + self.gridLayout_5.setSpacing(0) + self.gridLayout_5.setObjectName("gridLayout_5") + self.avgParamList = QtWidgets.QListWidget(self.averageGroup) + self.avgParamList.setObjectName("avgParamList") + self.gridLayout_5.addWidget(self.avgParamList, 0, 0, 1, 1) + self.decimateGroup = QtWidgets.QFrame(Form) + self.decimateGroup.setGeometry(QtCore.QRect(10, 140, 191, 171)) + self.decimateGroup.setObjectName("decimateGroup") + self.gridLayout_4 = QtWidgets.QGridLayout(self.decimateGroup) + self.gridLayout_4.setContentsMargins(0, 0, 0, 0) + self.gridLayout_4.setSpacing(0) + self.gridLayout_4.setObjectName("gridLayout_4") + self.clipToViewCheck = QtWidgets.QCheckBox(self.decimateGroup) + self.clipToViewCheck.setObjectName("clipToViewCheck") + self.gridLayout_4.addWidget(self.clipToViewCheck, 7, 0, 1, 3) + self.maxTracesCheck = QtWidgets.QCheckBox(self.decimateGroup) + self.maxTracesCheck.setObjectName("maxTracesCheck") + self.gridLayout_4.addWidget(self.maxTracesCheck, 8, 0, 1, 2) + self.downsampleCheck = QtWidgets.QCheckBox(self.decimateGroup) + self.downsampleCheck.setObjectName("downsampleCheck") + self.gridLayout_4.addWidget(self.downsampleCheck, 0, 0, 1, 3) + self.peakRadio = QtWidgets.QRadioButton(self.decimateGroup) + self.peakRadio.setChecked(True) + self.peakRadio.setObjectName("peakRadio") + self.gridLayout_4.addWidget(self.peakRadio, 6, 1, 1, 2) + self.maxTracesSpin = QtWidgets.QSpinBox(self.decimateGroup) + self.maxTracesSpin.setObjectName("maxTracesSpin") + self.gridLayout_4.addWidget(self.maxTracesSpin, 8, 2, 1, 1) + self.forgetTracesCheck = QtWidgets.QCheckBox(self.decimateGroup) + self.forgetTracesCheck.setObjectName("forgetTracesCheck") + self.gridLayout_4.addWidget(self.forgetTracesCheck, 9, 0, 1, 3) + self.meanRadio = QtWidgets.QRadioButton(self.decimateGroup) + self.meanRadio.setObjectName("meanRadio") + self.gridLayout_4.addWidget(self.meanRadio, 3, 1, 1, 2) + self.subsampleRadio = QtWidgets.QRadioButton(self.decimateGroup) + self.subsampleRadio.setObjectName("subsampleRadio") + self.gridLayout_4.addWidget(self.subsampleRadio, 2, 1, 1, 2) + self.autoDownsampleCheck = QtWidgets.QCheckBox(self.decimateGroup) + self.autoDownsampleCheck.setChecked(True) + self.autoDownsampleCheck.setObjectName("autoDownsampleCheck") + self.gridLayout_4.addWidget(self.autoDownsampleCheck, 1, 2, 1, 1) + spacerItem = QtWidgets.QSpacerItem(30, 20, QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Minimum) + self.gridLayout_4.addItem(spacerItem, 2, 0, 1, 1) + self.downsampleSpin = QtWidgets.QSpinBox(self.decimateGroup) + self.downsampleSpin.setMinimum(1) + self.downsampleSpin.setMaximum(100000) + self.downsampleSpin.setProperty("value", 1) + self.downsampleSpin.setObjectName("downsampleSpin") + self.gridLayout_4.addWidget(self.downsampleSpin, 1, 1, 1, 1) + self.transformGroup = QtWidgets.QFrame(Form) + self.transformGroup.setGeometry(QtCore.QRect(10, 10, 171, 101)) + self.transformGroup.setObjectName("transformGroup") + self.gridLayout = QtWidgets.QGridLayout(self.transformGroup) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setSpacing(0) + self.gridLayout.setObjectName("gridLayout") + self.logYCheck = QtWidgets.QCheckBox(self.transformGroup) + self.logYCheck.setObjectName("logYCheck") + self.gridLayout.addWidget(self.logYCheck, 2, 0, 1, 1) + self.logXCheck = QtWidgets.QCheckBox(self.transformGroup) + self.logXCheck.setObjectName("logXCheck") + self.gridLayout.addWidget(self.logXCheck, 1, 0, 1, 1) + self.fftCheck = QtWidgets.QCheckBox(self.transformGroup) + self.fftCheck.setObjectName("fftCheck") + self.gridLayout.addWidget(self.fftCheck, 0, 0, 1, 1) + self.derivativeCheck = QtWidgets.QCheckBox(self.transformGroup) + self.derivativeCheck.setObjectName("derivativeCheck") + self.gridLayout.addWidget(self.derivativeCheck, 3, 0, 1, 1) + self.phasemapCheck = QtWidgets.QCheckBox(self.transformGroup) + self.phasemapCheck.setObjectName("phasemapCheck") + self.gridLayout.addWidget(self.phasemapCheck, 4, 0, 1, 1) + self.pointsGroup = QtWidgets.QGroupBox(Form) + self.pointsGroup.setGeometry(QtCore.QRect(10, 550, 234, 58)) + self.pointsGroup.setCheckable(True) + self.pointsGroup.setObjectName("pointsGroup") + self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.pointsGroup) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.autoPointsCheck = QtWidgets.QCheckBox(self.pointsGroup) + self.autoPointsCheck.setChecked(True) + self.autoPointsCheck.setObjectName("autoPointsCheck") + self.verticalLayout_5.addWidget(self.autoPointsCheck) + self.gridGroup = QtWidgets.QFrame(Form) + self.gridGroup.setGeometry(QtCore.QRect(10, 460, 221, 81)) + self.gridGroup.setObjectName("gridGroup") + self.gridLayout_2 = QtWidgets.QGridLayout(self.gridGroup) + self.gridLayout_2.setObjectName("gridLayout_2") + self.xGridCheck = QtWidgets.QCheckBox(self.gridGroup) + self.xGridCheck.setObjectName("xGridCheck") + self.gridLayout_2.addWidget(self.xGridCheck, 0, 0, 1, 2) + self.yGridCheck = QtWidgets.QCheckBox(self.gridGroup) + self.yGridCheck.setObjectName("yGridCheck") + self.gridLayout_2.addWidget(self.yGridCheck, 1, 0, 1, 2) + self.gridAlphaSlider = QtWidgets.QSlider(self.gridGroup) + self.gridAlphaSlider.setMaximum(255) + self.gridAlphaSlider.setProperty("value", 128) + self.gridAlphaSlider.setOrientation(QtCore.Qt.Horizontal) + self.gridAlphaSlider.setObjectName("gridAlphaSlider") + self.gridLayout_2.addWidget(self.gridAlphaSlider, 2, 1, 1, 1) + self.label = QtWidgets.QLabel(self.gridGroup) + self.label.setObjectName("label") + self.gridLayout_2.addWidget(self.label, 2, 0, 1, 1) + self.alphaGroup = QtWidgets.QGroupBox(Form) + self.alphaGroup.setGeometry(QtCore.QRect(10, 390, 234, 60)) + self.alphaGroup.setCheckable(True) + self.alphaGroup.setObjectName("alphaGroup") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.alphaGroup) + self.horizontalLayout.setObjectName("horizontalLayout") + self.autoAlphaCheck = QtWidgets.QCheckBox(self.alphaGroup) + self.autoAlphaCheck.setChecked(False) + self.autoAlphaCheck.setObjectName("autoAlphaCheck") + self.horizontalLayout.addWidget(self.autoAlphaCheck) + self.alphaSlider = QtWidgets.QSlider(self.alphaGroup) + self.alphaSlider.setMaximum(1000) + self.alphaSlider.setProperty("value", 1000) + self.alphaSlider.setOrientation(QtCore.Qt.Horizontal) + self.alphaSlider.setObjectName("alphaSlider") + self.horizontalLayout.addWidget(self.alphaSlider) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "PyQtGraph")) + self.averageGroup.setToolTip(_translate("Form", "Display averages of the curves displayed in this plot. The parameter list allows you to choose parameters to average over (if any are available).")) + self.averageGroup.setTitle(_translate("Form", "Average")) + self.clipToViewCheck.setToolTip(_translate("Form", "Plot only the portion of each curve that is visible. This assumes X values are uniformly spaced.")) + self.clipToViewCheck.setText(_translate("Form", "Clip to View")) + self.maxTracesCheck.setToolTip(_translate("Form", "If multiple curves are displayed in this plot, check this box to limit the number of traces that are displayed.")) + self.maxTracesCheck.setText(_translate("Form", "Max Traces:")) + self.downsampleCheck.setText(_translate("Form", "Downsample")) + self.peakRadio.setToolTip(_translate("Form", "Downsample by drawing a saw wave that follows the min and max of the original data. This method produces the best visual representation of the data but is slower.")) + self.peakRadio.setText(_translate("Form", "Peak")) + self.maxTracesSpin.setToolTip(_translate("Form", "If multiple curves are displayed in this plot, check \"Max Traces\" and set this value to limit the number of traces that are displayed.")) + self.forgetTracesCheck.setToolTip(_translate("Form", "If MaxTraces is checked, remove curves from memory after they are hidden (saves memory, but traces can not be un-hidden).")) + self.forgetTracesCheck.setText(_translate("Form", "Forget hidden traces")) + self.meanRadio.setToolTip(_translate("Form", "Downsample by taking the mean of N samples.")) + self.meanRadio.setText(_translate("Form", "Mean")) + self.subsampleRadio.setToolTip(_translate("Form", "Downsample by taking the first of N samples. This method is fastest and least accurate.")) + self.subsampleRadio.setText(_translate("Form", "Subsample")) + self.autoDownsampleCheck.setToolTip(_translate("Form", "Automatically downsample data based on the visible range. This assumes X values are uniformly spaced.")) + self.autoDownsampleCheck.setText(_translate("Form", "Auto")) + self.downsampleSpin.setToolTip(_translate("Form", "Downsample data before plotting. (plot every Nth sample)")) + self.downsampleSpin.setSuffix(_translate("Form", "x")) + self.logYCheck.setText(_translate("Form", "Log Y")) + self.logXCheck.setText(_translate("Form", "Log X")) + self.fftCheck.setText(_translate("Form", "Power Spectrum (FFT)")) + self.derivativeCheck.setText(_translate("Form", "dy/dx")) + self.phasemapCheck.setText(_translate("Form", "Y vs. Y\'")) + self.pointsGroup.setTitle(_translate("Form", "Points")) + self.autoPointsCheck.setText(_translate("Form", "Auto")) + self.xGridCheck.setText(_translate("Form", "Show X Grid")) + self.yGridCheck.setText(_translate("Form", "Show Y Grid")) + self.label.setText(_translate("Form", "Opacity")) + self.alphaGroup.setTitle(_translate("Form", "Alpha")) + self.autoAlphaCheck.setText(_translate("Form", "Auto")) diff --git a/nmreval/gui_qt/_py/pokemon.py b/nmreval/gui_qt/_py/pokemon.py new file mode 100644 index 0000000..e601c7e --- /dev/null +++ b/nmreval/gui_qt/_py/pokemon.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/pokemon.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(400, 359) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth()) + Dialog.setSizePolicy(sizePolicy) + self.verticalLayout = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout.setObjectName("verticalLayout") + self.tabWidget = QtWidgets.QTabWidget(Dialog) + self.tabWidget.setObjectName("tabWidget") + self.verticalLayout.addWidget(self.tabWidget) + self.formLayout = QtWidgets.QFormLayout() + self.formLayout.setObjectName("formLayout") + self.label = QtWidgets.QLabel(Dialog) + self.label.setObjectName("label") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label) + self.pokedex_nr = QtWidgets.QLabel(Dialog) + self.pokedex_nr.setObjectName("pokedex_nr") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.pokedex_nr) + self.label_2 = QtWidgets.QLabel(Dialog) + self.label_2.setObjectName("label_2") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_2) + self.name = QtWidgets.QComboBox(Dialog) + self.name.setObjectName("name") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.name) + self.label_3 = QtWidgets.QLabel(Dialog) + self.label_3.setObjectName("label_3") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_3) + self.category = QtWidgets.QLabel(Dialog) + self.category.setObjectName("category") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.category) + self.label_4 = QtWidgets.QLabel(Dialog) + self.label_4.setObjectName("label_4") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_4) + self.poketype = QtWidgets.QLabel(Dialog) + self.poketype.setObjectName("poketype") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.poketype) + self.label_5 = QtWidgets.QLabel(Dialog) + self.label_5.setObjectName("label_5") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_5) + self.height = QtWidgets.QLabel(Dialog) + self.height.setObjectName("height") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.height) + self.label_6 = QtWidgets.QLabel(Dialog) + self.label_6.setObjectName("label_6") + self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_6) + self.weight = QtWidgets.QLabel(Dialog) + self.weight.setObjectName("weight") + self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.weight) + self.label_7 = QtWidgets.QLabel(Dialog) + self.label_7.setObjectName("label_7") + self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_7) + self.color = QtWidgets.QLabel(Dialog) + self.color.setObjectName("color") + self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.color) + self.label_8 = QtWidgets.QLabel(Dialog) + self.label_8.setObjectName("label_8") + self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_8) + self.info = QtWidgets.QLabel(Dialog) + self.info.setObjectName("info") + self.formLayout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.info) + self.verticalLayout.addLayout(self.formLayout) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.prev_button = QtWidgets.QToolButton(Dialog) + self.prev_button.setObjectName("prev_button") + self.horizontalLayout_2.addWidget(self.prev_button) + self.next_button = QtWidgets.QToolButton(Dialog) + self.next_button.setObjectName("next_button") + self.horizontalLayout_2.addWidget(self.next_button) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close|QtWidgets.QDialogButtonBox.Retry) + self.buttonBox.setCenterButtons(False) + self.buttonBox.setObjectName("buttonBox") + self.horizontalLayout_2.addWidget(self.buttonBox) + self.verticalLayout.addLayout(self.horizontalLayout_2) + self.label_2.setBuddy(self.name) + + self.retranslateUi(Dialog) + self.tabWidget.setCurrentIndex(-1) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Random Pokémon")) + self.label.setText(_translate("Dialog", "National-Dex")) + self.pokedex_nr.setText(_translate("Dialog", "TextLabel")) + self.label_2.setText(_translate("Dialog", "Name")) + self.label_3.setText(_translate("Dialog", "Kategorie")) + self.category.setText(_translate("Dialog", "TextLabel")) + self.label_4.setText(_translate("Dialog", "Typ")) + self.poketype.setText(_translate("Dialog", "TextLabel")) + self.label_5.setText(_translate("Dialog", "Größe")) + self.height.setText(_translate("Dialog", "TextLabel")) + self.label_6.setText(_translate("Dialog", "Gewicht")) + self.weight.setText(_translate("Dialog", "TextLabel")) + self.label_7.setText(_translate("Dialog", "Farbe")) + self.color.setText(_translate("Dialog", "TextLabel")) + self.label_8.setText(_translate("Dialog", "Mehr...")) + self.info.setText(_translate("Dialog", "TextLabel")) + self.prev_button.setText(_translate("Dialog", "Prev.")) + self.next_button.setText(_translate("Dialog", "Next")) diff --git a/nmreval/gui_qt/_py/propwidget.py b/nmreval/gui_qt/_py/propwidget.py new file mode 100644 index 0000000..a3c4c3b --- /dev/null +++ b/nmreval/gui_qt/_py/propwidget.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/propwidget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(400, 300) + self.verticalLayout = QtWidgets.QVBoxLayout(Form) + self.verticalLayout.setContentsMargins(2, 2, 2, 2) + self.verticalLayout.setSpacing(2) + self.verticalLayout.setObjectName("verticalLayout") + self.tabWidget = QtWidgets.QTabWidget(Form) + self.tabWidget.setObjectName("tabWidget") + self.tabWidgetPage2 = QtWidgets.QWidget() + self.tabWidgetPage2.setObjectName("tabWidgetPage2") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.tabWidgetPage2) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_3.setSpacing(0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.tableWidget_2 = QtWidgets.QTableWidget(self.tabWidgetPage2) + self.tableWidget_2.setObjectName("tableWidget_2") + self.tableWidget_2.setColumnCount(0) + self.tableWidget_2.setRowCount(0) + self.verticalLayout_3.addWidget(self.tableWidget_2) + self.tabWidget.addTab(self.tabWidgetPage2, "") + self.tabWidgetPage1 = QtWidgets.QWidget() + self.tabWidgetPage1.setObjectName("tabWidgetPage1") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tabWidgetPage1) + self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_2.setSpacing(0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.tableWidget = QtWidgets.QTableWidget(self.tabWidgetPage1) + self.tableWidget.setObjectName("tableWidget") + self.tableWidget.setColumnCount(0) + self.tableWidget.setRowCount(0) + self.verticalLayout_2.addWidget(self.tableWidget) + self.tabWidget.addTab(self.tabWidgetPage1, "") + self.verticalLayout.addWidget(self.tabWidget) + + self.retranslateUi(Form) + self.tabWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabWidgetPage2), _translate("Form", "General")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabWidgetPage1), _translate("Form", "Symbol")) diff --git a/nmreval/gui_qt/_py/ptstab.py b/nmreval/gui_qt/_py/ptstab.py new file mode 100644 index 0000000..677b38b --- /dev/null +++ b/nmreval/gui_qt/_py/ptstab.py @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/ptstab.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(316, 747) + self.verticalLayout = QtWidgets.QVBoxLayout(Form) + self.verticalLayout.setContentsMargins(3, 3, 3, 3) + self.verticalLayout.setObjectName("verticalLayout") + self.peaktable = QtWidgets.QListWidget(Form) + self.peaktable.setEditTriggers(QtWidgets.QAbstractItemView.DoubleClicked|QtWidgets.QAbstractItemView.EditKeyPressed) + self.peaktable.setObjectName("peaktable") + self.verticalLayout.addWidget(self.peaktable) + self.groupBox = QtWidgets.QGroupBox(Form) + self.groupBox.setObjectName("groupBox") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.groupBox) + self.horizontalLayout.setContentsMargins(3, 3, 3, 3) + self.horizontalLayout.setSpacing(3) + self.horizontalLayout.setObjectName("horizontalLayout") + self.left_pt = QtWidgets.QSpinBox(self.groupBox) + self.left_pt.setMaximum(999) + self.left_pt.setObjectName("left_pt") + self.horizontalLayout.addWidget(self.left_pt) + self.right_pt = QtWidgets.QSpinBox(self.groupBox) + self.right_pt.setMaximum(999) + self.right_pt.setObjectName("right_pt") + self.horizontalLayout.addWidget(self.right_pt) + self.average_combobox = QtWidgets.QComboBox(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.average_combobox.sizePolicy().hasHeightForWidth()) + self.average_combobox.setSizePolicy(sizePolicy) + self.average_combobox.setObjectName("average_combobox") + self.average_combobox.addItem("") + self.average_combobox.addItem("") + self.average_combobox.addItem("") + self.horizontalLayout.addWidget(self.average_combobox) + self.verticalLayout.addWidget(self.groupBox) + self.groupBox_2 = QtWidgets.QGroupBox(Form) + self.groupBox_2.setCheckable(True) + self.groupBox_2.setChecked(False) + self.groupBox_2.setObjectName("groupBox_2") + self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.groupBox_2) + self.horizontalLayout_5.setContentsMargins(3, 3, 3, 3) + self.horizontalLayout_5.setSpacing(2) + self.horizontalLayout_5.setObjectName("horizontalLayout_5") + self.special_comboBox = QtWidgets.QComboBox(self.groupBox_2) + self.special_comboBox.setObjectName("special_comboBox") + self.special_comboBox.addItem("") + self.special_comboBox.addItem("") + self.special_comboBox.addItem("") + self.special_comboBox.addItem("") + self.horizontalLayout_5.addWidget(self.special_comboBox) + self.verticalLayout.addWidget(self.groupBox_2) + self.groupBox_3 = QtWidgets.QGroupBox(Form) + self.groupBox_3.setObjectName("groupBox_3") + self.gridLayout = QtWidgets.QGridLayout(self.groupBox_3) + self.gridLayout.setContentsMargins(3, 3, 3, 3) + self.gridLayout.setSpacing(3) + self.gridLayout.setObjectName("gridLayout") + self.xbutton = QtWidgets.QCheckBox(self.groupBox_3) + self.xbutton.setObjectName("xbutton") + self.gridLayout.addWidget(self.xbutton, 0, 0, 1, 1) + self.ybutton = QtWidgets.QCheckBox(self.groupBox_3) + self.ybutton.setChecked(True) + self.ybutton.setObjectName("ybutton") + self.gridLayout.addWidget(self.ybutton, 0, 1, 1, 1) + self.graph_checkbox = QtWidgets.QCheckBox(self.groupBox_3) + self.graph_checkbox.setChecked(True) + self.graph_checkbox.setObjectName("graph_checkbox") + self.gridLayout.addWidget(self.graph_checkbox, 1, 0, 1, 1) + self.graph_combobox = QtWidgets.QComboBox(self.groupBox_3) + self.graph_combobox.setEnabled(False) + self.graph_combobox.setObjectName("graph_combobox") + self.gridLayout.addWidget(self.graph_combobox, 1, 1, 1, 1) + self.verticalLayout.addWidget(self.groupBox_3) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout_2.setSpacing(2) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.okButton = QtWidgets.QPushButton(Form) + icon = QtGui.QIcon.fromTheme("dialog-ok") + self.okButton.setIcon(icon) + self.okButton.setObjectName("okButton") + self.horizontalLayout_2.addWidget(self.okButton) + self.deleteButton = QtWidgets.QPushButton(Form) + icon = QtGui.QIcon.fromTheme("dialog-cancel") + self.deleteButton.setIcon(icon) + self.deleteButton.setObjectName("deleteButton") + self.horizontalLayout_2.addWidget(self.deleteButton) + self.verticalLayout.addLayout(self.horizontalLayout_2) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.peaktable.setToolTip(_translate("Form", "Edit by entering new value: \n" +"Single number for points (e.g. 1e-6); \n" +"two numbers separated by space for regions (e.g. 1e-6 5e-6). \n" +"Changing between regions and points is NOT possible")) + self.groupBox.setTitle(_translate("Form", "Average")) + self.left_pt.setSuffix(_translate("Form", " pts")) + self.left_pt.setPrefix(_translate("Form", "- ")) + self.right_pt.setSuffix(_translate("Form", " pts")) + self.right_pt.setPrefix(_translate("Form", "+ ")) + self.average_combobox.setItemText(0, _translate("Form", "Mean")) + self.average_combobox.setItemText(1, _translate("Form", "Sum")) + self.average_combobox.setItemText(2, _translate("Form", "Integral")) + self.groupBox_2.setTitle(_translate("Form", "Special value")) + self.special_comboBox.setToolTip(_translate("Form", "Automatic selection of respective points")) + self.special_comboBox.setItemText(0, _translate("Form", "max(y)")) + self.special_comboBox.setItemText(1, _translate("Form", "max(abs(y))")) + self.special_comboBox.setItemText(2, _translate("Form", "min(y)")) + self.special_comboBox.setItemText(3, _translate("Form", "min(abs(y))")) + self.groupBox_3.setTitle(_translate("Form", "Result")) + self.xbutton.setText(_translate("Form", "x")) + self.ybutton.setText(_translate("Form", "y")) + self.graph_checkbox.setText(_translate("Form", "New graph?")) + self.okButton.setText(_translate("Form", "Apply")) + self.deleteButton.setText(_translate("Form", "Delete selected")) diff --git a/nmreval/gui_qt/_py/qfiledialog.py b/nmreval/gui_qt/_py/qfiledialog.py new file mode 100644 index 0000000..52829e2 --- /dev/null +++ b/nmreval/gui_qt/_py/qfiledialog.py @@ -0,0 +1,179 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/qfiledialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_QFileDialog(object): + def setupUi(self, QFileDialog): + QFileDialog.setObjectName("QFileDialog") + QFileDialog.resize(521, 316) + QFileDialog.setSizeGripEnabled(True) + self.gridlayout = QtWidgets.QGridLayout(QFileDialog) + self.gridlayout.setObjectName("gridlayout") + self.lookInLabel = QtWidgets.QLabel(QFileDialog) + self.lookInLabel.setObjectName("lookInLabel") + self.gridlayout.addWidget(self.lookInLabel, 0, 0, 1, 1) + self.hboxlayout = QtWidgets.QHBoxLayout() + self.hboxlayout.setObjectName("hboxlayout") + self.lookInCombo = QtWidgets.QComboBox(QFileDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lookInCombo.sizePolicy().hasHeightForWidth()) + self.lookInCombo.setSizePolicy(sizePolicy) + self.lookInCombo.setMinimumSize(QtCore.QSize(50, 0)) + self.lookInCombo.setObjectName("lookInCombo") + self.hboxlayout.addWidget(self.lookInCombo) + self.backButton = QtWidgets.QToolButton(QFileDialog) + self.backButton.setObjectName("backButton") + self.hboxlayout.addWidget(self.backButton) + self.forwardButton = QtWidgets.QToolButton(QFileDialog) + self.forwardButton.setObjectName("forwardButton") + self.hboxlayout.addWidget(self.forwardButton) + self.toParentButton = QtWidgets.QToolButton(QFileDialog) + self.toParentButton.setObjectName("toParentButton") + self.hboxlayout.addWidget(self.toParentButton) + self.newFolderButton = QtWidgets.QToolButton(QFileDialog) + self.newFolderButton.setObjectName("newFolderButton") + self.hboxlayout.addWidget(self.newFolderButton) + self.listModeButton = QtWidgets.QToolButton(QFileDialog) + self.listModeButton.setObjectName("listModeButton") + self.hboxlayout.addWidget(self.listModeButton) + self.detailModeButton = QtWidgets.QToolButton(QFileDialog) + self.detailModeButton.setObjectName("detailModeButton") + self.hboxlayout.addWidget(self.detailModeButton) + self.gridlayout.addLayout(self.hboxlayout, 0, 1, 1, 2) + self.splitter = QtWidgets.QSplitter(QFileDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.splitter.sizePolicy().hasHeightForWidth()) + self.splitter.setSizePolicy(sizePolicy) + self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setChildrenCollapsible(False) + self.splitter.setObjectName("splitter") + self.sidebar = QtWidgets.QListWidget(self.splitter) + self.sidebar.setObjectName("sidebar") + self.frame = QtWidgets.QFrame(self.splitter) + self.frame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.frame.setObjectName("frame") + self.vboxlayout = QtWidgets.QVBoxLayout(self.frame) + self.vboxlayout.setContentsMargins(0, 0, 0, 0) + self.vboxlayout.setSpacing(0) + self.vboxlayout.setObjectName("vboxlayout") + self.stackedWidget = QtWidgets.QStackedWidget(self.frame) + self.stackedWidget.setObjectName("stackedWidget") + self.page = QtWidgets.QWidget() + self.page.setObjectName("page") + self.vboxlayout1 = QtWidgets.QVBoxLayout(self.page) + self.vboxlayout1.setContentsMargins(0, 0, 0, 0) + self.vboxlayout1.setSpacing(0) + self.vboxlayout1.setObjectName("vboxlayout1") + self.listView = QtWidgets.QListView(self.page) + self.listView.setObjectName("listView") + self.vboxlayout1.addWidget(self.listView) + self.stackedWidget.addWidget(self.page) + self.page_2 = QtWidgets.QWidget() + self.page_2.setObjectName("page_2") + self.vboxlayout2 = QtWidgets.QVBoxLayout(self.page_2) + self.vboxlayout2.setContentsMargins(0, 0, 0, 0) + self.vboxlayout2.setSpacing(0) + self.vboxlayout2.setObjectName("vboxlayout2") + self.treeView = QtWidgets.QTreeView(self.page_2) + self.treeView.setObjectName("treeView") + self.vboxlayout2.addWidget(self.treeView) + self.stackedWidget.addWidget(self.page_2) + self.vboxlayout.addWidget(self.stackedWidget) + self.gridlayout.addWidget(self.splitter, 1, 0, 1, 3) + self.fileNameLabel = QtWidgets.QLabel(QFileDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.fileNameLabel.sizePolicy().hasHeightForWidth()) + self.fileNameLabel.setSizePolicy(sizePolicy) + self.fileNameLabel.setMinimumSize(QtCore.QSize(0, 0)) + self.fileNameLabel.setObjectName("fileNameLabel") + self.gridlayout.addWidget(self.fileNameLabel, 2, 0, 1, 1) + self.fileNameEdit = QtWidgets.QLineEdit(QFileDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.fileNameEdit.sizePolicy().hasHeightForWidth()) + self.fileNameEdit.setSizePolicy(sizePolicy) + self.fileNameEdit.setObjectName("fileNameEdit") + self.gridlayout.addWidget(self.fileNameEdit, 2, 1, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(QFileDialog) + self.buttonBox.setOrientation(QtCore.Qt.Vertical) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridlayout.addWidget(self.buttonBox, 2, 2, 2, 1) + self.fileTypeLabel = QtWidgets.QLabel(QFileDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.fileTypeLabel.sizePolicy().hasHeightForWidth()) + self.fileTypeLabel.setSizePolicy(sizePolicy) + self.fileTypeLabel.setObjectName("fileTypeLabel") + self.gridlayout.addWidget(self.fileTypeLabel, 3, 0, 1, 1) + self.fileTypeCombo = QtWidgets.QComboBox(QFileDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.fileTypeCombo.sizePolicy().hasHeightForWidth()) + self.fileTypeCombo.setSizePolicy(sizePolicy) + self.fileTypeCombo.setObjectName("fileTypeCombo") + self.gridlayout.addWidget(self.fileTypeCombo, 3, 1, 1, 1) + + self.retranslateUi(QFileDialog) + self.stackedWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(QFileDialog) + QFileDialog.setTabOrder(self.lookInCombo, self.backButton) + QFileDialog.setTabOrder(self.backButton, self.forwardButton) + QFileDialog.setTabOrder(self.forwardButton, self.toParentButton) + QFileDialog.setTabOrder(self.toParentButton, self.newFolderButton) + QFileDialog.setTabOrder(self.newFolderButton, self.listModeButton) + QFileDialog.setTabOrder(self.listModeButton, self.detailModeButton) + QFileDialog.setTabOrder(self.detailModeButton, self.sidebar) + QFileDialog.setTabOrder(self.sidebar, self.treeView) + QFileDialog.setTabOrder(self.treeView, self.listView) + QFileDialog.setTabOrder(self.listView, self.fileNameEdit) + QFileDialog.setTabOrder(self.fileNameEdit, self.buttonBox) + QFileDialog.setTabOrder(self.buttonBox, self.fileTypeCombo) + + def retranslateUi(self, QFileDialog): + _translate = QtCore.QCoreApplication.translate + self.lookInLabel.setText(_translate("QFileDialog", "Look in:")) + self.backButton.setToolTip(_translate("QFileDialog", "Back")) + self.backButton.setAccessibleName(_translate("QFileDialog", "Back")) + self.backButton.setAccessibleDescription(_translate("QFileDialog", "Go back")) + self.backButton.setShortcut(_translate("QFileDialog", "Alt+Left")) + self.forwardButton.setToolTip(_translate("QFileDialog", "Forward")) + self.forwardButton.setAccessibleName(_translate("QFileDialog", "Forward")) + self.forwardButton.setAccessibleDescription(_translate("QFileDialog", "Go forward")) + self.forwardButton.setShortcut(_translate("QFileDialog", "Alt+Right")) + self.toParentButton.setToolTip(_translate("QFileDialog", "Parent Directory")) + self.toParentButton.setAccessibleName(_translate("QFileDialog", "Parent Directory")) + self.toParentButton.setAccessibleDescription(_translate("QFileDialog", "Go to the parent directory")) + self.toParentButton.setShortcut(_translate("QFileDialog", "Alt+Up")) + self.newFolderButton.setToolTip(_translate("QFileDialog", "Create New Folder")) + self.newFolderButton.setAccessibleName(_translate("QFileDialog", "Create New Folder")) + self.newFolderButton.setAccessibleDescription(_translate("QFileDialog", "Create a New Folder")) + self.listModeButton.setToolTip(_translate("QFileDialog", "List View")) + self.listModeButton.setAccessibleName(_translate("QFileDialog", "List View")) + self.listModeButton.setAccessibleDescription(_translate("QFileDialog", "Change to list view mode")) + self.detailModeButton.setToolTip(_translate("QFileDialog", "Detail View")) + self.detailModeButton.setAccessibleName(_translate("QFileDialog", "Detail View")) + self.detailModeButton.setAccessibleDescription(_translate("QFileDialog", "Change to detail view mode")) + self.sidebar.setAccessibleName(_translate("QFileDialog", "Sidebar")) + self.sidebar.setAccessibleDescription(_translate("QFileDialog", "List of places and bookmarks")) + self.listView.setAccessibleName(_translate("QFileDialog", "Files")) + self.treeView.setAccessibleName(_translate("QFileDialog", "Files")) + self.fileTypeLabel.setText(_translate("QFileDialog", "Files of type:")) diff --git a/nmreval/gui_qt/_py/save_fit_parameter.py b/nmreval/gui_qt/_py/save_fit_parameter.py new file mode 100644 index 0000000..4db6c00 --- /dev/null +++ b/nmreval/gui_qt/_py/save_fit_parameter.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/save_fit_parameter.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_fitparameter_save_dialog(object): + def setupUi(self, fitparameter_save_dialog): + fitparameter_save_dialog.setObjectName("fitparameter_save_dialog") + fitparameter_save_dialog.resize(578, 537) + self.gridLayout = QtWidgets.QGridLayout(fitparameter_save_dialog) + self.gridLayout.setObjectName("gridLayout") + self.save_path_line = QtWidgets.QLineEdit(fitparameter_save_dialog) + self.save_path_line.setObjectName("save_path_line") + self.gridLayout.addWidget(self.save_path_line, 0, 1, 1, 6) + self.save_path_button = QtWidgets.QToolButton(fitparameter_save_dialog) + self.save_path_button.setObjectName("save_path_button") + self.gridLayout.addWidget(self.save_path_button, 0, 0, 1, 1) + self.comment_line = QtWidgets.QLineEdit(fitparameter_save_dialog) + self.comment_line.setObjectName("comment_line") + self.gridLayout.addWidget(self.comment_line, 6, 6, 1, 1) + self.prec_spinbox = QtWidgets.QSpinBox(fitparameter_save_dialog) + self.prec_spinbox.setProperty("value", 8) + self.prec_spinbox.setObjectName("prec_spinbox") + self.gridLayout.addWidget(self.prec_spinbox, 6, 3, 1, 1) + self.line_2 = QtWidgets.QFrame(fitparameter_save_dialog) + self.line_2.setFrameShape(QtWidgets.QFrame.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.gridLayout.addWidget(self.line_2, 4, 0, 1, 7) + self.label_5 = QtWidgets.QLabel(fitparameter_save_dialog) + self.label_5.setObjectName("label_5") + self.gridLayout.addWidget(self.label_5, 3, 0, 1, 1) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.col_line = QtWidgets.QLineEdit(fitparameter_save_dialog) + self.col_line.setObjectName("col_line") + self.horizontalLayout.addWidget(self.col_line) + self.usage_button = QtWidgets.QToolButton(fitparameter_save_dialog) + self.usage_button.setObjectName("usage_button") + self.horizontalLayout.addWidget(self.usage_button) + self.gridLayout.addLayout(self.horizontalLayout, 3, 1, 1, 6) + self.header_edit = QtWidgets.QTextEdit(fitparameter_save_dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.header_edit.sizePolicy().hasHeightForWidth()) + self.header_edit.setSizePolicy(sizePolicy) + self.header_edit.setObjectName("header_edit") + self.gridLayout.addWidget(self.header_edit, 5, 1, 1, 6) + self.label_4 = QtWidgets.QLabel(fitparameter_save_dialog) + self.label_4.setObjectName("label_4") + self.gridLayout.addWidget(self.label_4, 6, 2, 1, 1) + self.line = QtWidgets.QFrame(fitparameter_save_dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.line.sizePolicy().hasHeightForWidth()) + self.line.setSizePolicy(sizePolicy) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.gridLayout.addWidget(self.line, 1, 0, 1, 7) + self.missing_value_line = QtWidgets.QLineEdit(fitparameter_save_dialog) + self.missing_value_line.setObjectName("missing_value_line") + self.gridLayout.addWidget(self.missing_value_line, 6, 1, 1, 1) + self.label_2 = QtWidgets.QLabel(fitparameter_save_dialog) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 6, 4, 1, 1) + self.tableWidget = QtWidgets.QTableWidget(fitparameter_save_dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.tableWidget.sizePolicy().hasHeightForWidth()) + self.tableWidget.setSizePolicy(sizePolicy) + self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.tableWidget.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly) + self.tableWidget.setAlternatingRowColors(True) + self.tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget.setColumnCount(2) + self.tableWidget.setObjectName("tableWidget") + self.tableWidget.setRowCount(0) + self.tableWidget.horizontalHeader().setVisible(False) + self.tableWidget.horizontalHeader().setStretchLastSection(True) + self.gridLayout.addWidget(self.tableWidget, 2, 0, 1, 7) + self.buttonBox = QtWidgets.QDialogButtonBox(fitparameter_save_dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 7, 0, 1, 7) + self.label = QtWidgets.QLabel(fitparameter_save_dialog) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 6, 0, 1, 1) + self.header_checkBox = QtWidgets.QCheckBox(fitparameter_save_dialog) + self.header_checkBox.setObjectName("header_checkBox") + self.gridLayout.addWidget(self.header_checkBox, 5, 0, 1, 1) + self.label_5.setBuddy(self.col_line) + self.label_2.setBuddy(self.comment_line) + self.label.setBuddy(self.missing_value_line) + + self.retranslateUi(fitparameter_save_dialog) + self.buttonBox.accepted.connect(fitparameter_save_dialog.accept) + self.buttonBox.rejected.connect(fitparameter_save_dialog.reject) + QtCore.QMetaObject.connectSlotsByName(fitparameter_save_dialog) + fitparameter_save_dialog.setTabOrder(self.save_path_button, self.save_path_line) + fitparameter_save_dialog.setTabOrder(self.save_path_line, self.tableWidget) + fitparameter_save_dialog.setTabOrder(self.tableWidget, self.header_edit) + fitparameter_save_dialog.setTabOrder(self.header_edit, self.missing_value_line) + fitparameter_save_dialog.setTabOrder(self.missing_value_line, self.comment_line) + + def retranslateUi(self, fitparameter_save_dialog): + _translate = QtCore.QCoreApplication.translate + fitparameter_save_dialog.setWindowTitle(_translate("fitparameter_save_dialog", "Save parameter")) + self.save_path_button.setText(_translate("fitparameter_save_dialog", "Save path...")) + self.comment_line.setText(_translate("fitparameter_save_dialog", "#")) + self.label_5.setText(_translate("fitparameter_save_dialog", "Columns")) + self.col_line.setPlaceholderText(_translate("fitparameter_save_dialog", "e.g. x; 1000/x; mean(T_1,beta); {beta/beta_1}; M_0*x")) + self.usage_button.setText(_translate("fitparameter_save_dialog", "Usage?")) + self.header_edit.setPlaceholderText(_translate("fitparameter_save_dialog", "Header ends always with column description. Additional header lines are commented automatically")) + self.label_4.setText(_translate("fitparameter_save_dialog", "Precision")) + self.missing_value_line.setText(_translate("fitparameter_save_dialog", "1e308")) + self.label_2.setText(_translate("fitparameter_save_dialog", "Comment")) + self.buttonBox.setToolTip(_translate("fitparameter_save_dialog", "Number of significant digits.")) + self.label.setText(_translate("fitparameter_save_dialog", "Missing values")) + self.header_checkBox.setText(_translate("fitparameter_save_dialog", "Header")) diff --git a/nmreval/gui_qt/_py/save_fitmodel_dialog.py b/nmreval/gui_qt/_py/save_fitmodel_dialog.py new file mode 100644 index 0000000..25f058a --- /dev/null +++ b/nmreval/gui_qt/_py/save_fitmodel_dialog.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/save_fitmodel_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_SaveDialog(object): + def setupUi(self, SaveDialog): + SaveDialog.setObjectName("SaveDialog") + SaveDialog.resize(400, 166) + self.gridLayout = QtWidgets.QGridLayout(SaveDialog) + self.gridLayout.setObjectName("gridLayout") + self.label_2 = QtWidgets.QLabel(SaveDialog) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(SaveDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 3, 1, 1, 1) + self.comboBox = QtWidgets.QComboBox(SaveDialog) + self.comboBox.setObjectName("comboBox") + self.gridLayout.addWidget(self.comboBox, 1, 1, 1, 1) + self.label = QtWidgets.QLabel(SaveDialog) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + self.lineEdit = QtWidgets.QLineEdit(SaveDialog) + self.lineEdit.setObjectName("lineEdit") + self.gridLayout.addWidget(self.lineEdit, 0, 1, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem, 4, 1, 1, 1) + self.frame = QtWidgets.QFrame(SaveDialog) + self.frame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame.setFrameShadow(QtWidgets.QFrame.Plain) + self.frame.setObjectName("frame") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setSpacing(0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.lineEdit_2 = QtWidgets.QLineEdit(self.frame) + self.lineEdit_2.setObjectName("lineEdit_2") + self.horizontalLayout.addWidget(self.lineEdit_2) + self.toolButton = QtWidgets.QToolButton(self.frame) + self.toolButton.setObjectName("toolButton") + self.horizontalLayout.addWidget(self.toolButton) + self.gridLayout.addWidget(self.frame, 2, 1, 1, 1) + + self.retranslateUi(SaveDialog) + self.buttonBox.accepted.connect(SaveDialog.accept) + self.buttonBox.rejected.connect(SaveDialog.reject) + QtCore.QMetaObject.connectSlotsByName(SaveDialog) + + def retranslateUi(self, SaveDialog): + _translate = QtCore.QCoreApplication.translate + SaveDialog.setWindowTitle(_translate("SaveDialog", "Dialog")) + self.label_2.setText(_translate("SaveDialog", "Group")) + self.label.setText(_translate("SaveDialog", "Name")) + self.toolButton.setText(_translate("SaveDialog", "OK")) diff --git a/nmreval/gui_qt/_py/save_options.py b/nmreval/gui_qt/_py/save_options.py new file mode 100644 index 0000000..602a2c8 --- /dev/null +++ b/nmreval/gui_qt/_py/save_options.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/save_options.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(400, 58) + self.verticalLayout = QtWidgets.QVBoxLayout(Form) + self.verticalLayout.setObjectName("verticalLayout") + self.label = QtWidgets.QLabel(Form) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.checkBox = QtWidgets.QCheckBox(Form) + self.checkBox.setObjectName("checkBox") + self.verticalLayout.addWidget(self.checkBox) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.label.setText(_translate("Form", "

Use <label> as placeholder in filename for data label.

")) + self.checkBox.setText(_translate("Form", "Replace spaces with underscore")) diff --git a/nmreval/gui_qt/_py/saveoptions.py b/nmreval/gui_qt/_py/saveoptions.py new file mode 100644 index 0000000..c210a7e --- /dev/null +++ b/nmreval/gui_qt/_py/saveoptions.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/saveoptions.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Frame(object): + def setupUi(self, Frame): + Frame.setObjectName("Frame") + Frame.resize(464, 62) + Frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + Frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.verticalLayout = QtWidgets.QVBoxLayout(Frame) + self.verticalLayout.setObjectName("verticalLayout") + self.label = QtWidgets.QLabel(Frame) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.line = QtWidgets.QFrame(Frame) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.verticalLayout.addWidget(self.line) + self.checkBox = QtWidgets.QCheckBox(Frame) + self.checkBox.setChecked(True) + self.checkBox.setObjectName("checkBox") + self.verticalLayout.addWidget(self.checkBox) + + self.retranslateUi(Frame) + QtCore.QMetaObject.connectSlotsByName(Frame) + + def retranslateUi(self, Frame): + _translate = QtCore.QCoreApplication.translate + Frame.setWindowTitle(_translate("Frame", "Frame")) + self.label.setText(_translate("Frame", "

Use <label> as placeholder in filename. (e.g. t1_<label>.dat)

")) + self.checkBox.setText(_translate("Frame", "Replace spaces with underscore")) diff --git a/nmreval/gui_qt/_py/sdmodelwidget.py b/nmreval/gui_qt/_py/sdmodelwidget.py new file mode 100644 index 0000000..4f3a9a0 --- /dev/null +++ b/nmreval/gui_qt/_py/sdmodelwidget.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/sdmodelwidget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_SDParameter(object): + def setupUi(self, SDParameter): + SDParameter.setObjectName("SDParameter") + SDParameter.setWindowModality(QtCore.Qt.WindowModal) + SDParameter.resize(290, 37) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(SDParameter.sizePolicy().hasHeightForWidth()) + SDParameter.setSizePolicy(sizePolicy) + SDParameter.setAutoFillBackground(True) + self.verticalLayout = QtWidgets.QVBoxLayout(SDParameter) + self.verticalLayout.setContentsMargins(1, 0, 0, 0) + self.verticalLayout.setSpacing(0) + self.verticalLayout.setObjectName("verticalLayout") + self.gridLayout = QtWidgets.QGridLayout() + self.gridLayout.setContentsMargins(6, -1, 0, -1) + self.gridLayout.setSpacing(0) + self.gridLayout.setObjectName("gridLayout") + self.parameter_line = LineEdit(SDParameter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.parameter_line.sizePolicy().hasHeightForWidth()) + self.parameter_line.setSizePolicy(sizePolicy) + self.parameter_line.setObjectName("parameter_line") + self.gridLayout.addWidget(self.parameter_line, 0, 2, 1, 1) + self.parametername = QtWidgets.QLabel(SDParameter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(10) + sizePolicy.setHeightForWidth(self.parametername.sizePolicy().hasHeightForWidth()) + self.parametername.setSizePolicy(sizePolicy) + self.parametername.setFrameShape(QtWidgets.QFrame.NoFrame) + self.parametername.setObjectName("parametername") + self.gridLayout.addWidget(self.parametername, 0, 0, 1, 1) + self.checkBox = QtWidgets.QCheckBox(SDParameter) + self.checkBox.setObjectName("checkBox") + self.gridLayout.addWidget(self.checkBox, 0, 3, 1, 1) + self.line_2 = QtWidgets.QFrame(SDParameter) + self.line_2.setFrameShape(QtWidgets.QFrame.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.gridLayout.addWidget(self.line_2, 1, 0, 1, 4) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem, 0, 1, 1, 1) + self.verticalLayout.addLayout(self.gridLayout) + + self.retranslateUi(SDParameter) + QtCore.QMetaObject.connectSlotsByName(SDParameter) + + def retranslateUi(self, SDParameter): + _translate = QtCore.QCoreApplication.translate + SDParameter.setWindowTitle(_translate("SDParameter", "Form")) + self.parameter_line.setText(_translate("SDParameter", "1")) + self.parametername.setText(_translate("SDParameter", "Fitparameter")) + self.checkBox.setText(_translate("SDParameter", "Fix?")) +from nmrevalgui.lib.forms import LineEdit diff --git a/nmreval/gui_qt/_py/selection_widget.py b/nmreval/gui_qt/_py/selection_widget.py new file mode 100644 index 0000000..45614d4 --- /dev/null +++ b/nmreval/gui_qt/_py/selection_widget.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/selection_widget.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_SelectionWidget(object): + def setupUi(self, SelectionWidget): + SelectionWidget.setObjectName("SelectionWidget") + SelectionWidget.resize(367, 43) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(SelectionWidget.sizePolicy().hasHeightForWidth()) + SelectionWidget.setSizePolicy(sizePolicy) + self.horizontalLayout = QtWidgets.QHBoxLayout(SelectionWidget) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setSpacing(0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(SelectionWidget) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.comboBox = QtWidgets.QComboBox(SelectionWidget) + self.comboBox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToMinimumContentsLength) + self.comboBox.setFrame(True) + self.comboBox.setObjectName("comboBox") + self.horizontalLayout.addWidget(self.comboBox) + + self.retranslateUi(SelectionWidget) + QtCore.QMetaObject.connectSlotsByName(SelectionWidget) + + def retranslateUi(self, SelectionWidget): + _translate = QtCore.QCoreApplication.translate + SelectionWidget.setWindowTitle(_translate("SelectionWidget", "Form")) + self.label.setText(_translate("SelectionWidget", "TextLabel")) diff --git a/nmreval/gui_qt/_py/setbyfunction_dialog.py b/nmreval/gui_qt/_py/setbyfunction_dialog.py new file mode 100644 index 0000000..ecd065d --- /dev/null +++ b/nmreval/gui_qt/_py/setbyfunction_dialog.py @@ -0,0 +1,225 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/setbyfunction_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_NewCurveDialog(object): + def setupUi(self, NewCurveDialog): + NewCurveDialog.setObjectName("NewCurveDialog") + NewCurveDialog.resize(648, 578) + self.gridLayout_4 = QtWidgets.QGridLayout(NewCurveDialog) + self.gridLayout_4.setObjectName("gridLayout_4") + self.groupBox_2 = QtWidgets.QGroupBox(NewCurveDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox_2.sizePolicy().hasHeightForWidth()) + self.groupBox_2.setSizePolicy(sizePolicy) + self.groupBox_2.setObjectName("groupBox_2") + self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox_2) + self.gridLayout_2.setContentsMargins(2, 2, 2, 2) + self.gridLayout_2.setSpacing(2) + self.gridLayout_2.setObjectName("gridLayout_2") + self.lineEdit_3 = QtWidgets.QLineEdit(self.groupBox_2) + self.lineEdit_3.setPlaceholderText("") + self.lineEdit_3.setObjectName("lineEdit_3") + self.gridLayout_2.addWidget(self.lineEdit_3, 0, 1, 1, 1) + self.lineEdit_5 = QtWidgets.QLineEdit(self.groupBox_2) + self.lineEdit_5.setObjectName("lineEdit_5") + self.gridLayout_2.addWidget(self.lineEdit_5, 0, 6, 1, 1) + self.label_5 = QtWidgets.QLabel(self.groupBox_2) + self.label_5.setObjectName("label_5") + self.gridLayout_2.addWidget(self.label_5, 0, 3, 1, 1) + self.lineEdit_4 = QtWidgets.QLineEdit(self.groupBox_2) + self.lineEdit_4.setObjectName("lineEdit_4") + self.gridLayout_2.addWidget(self.lineEdit_4, 0, 4, 1, 1) + self.label_4 = QtWidgets.QLabel(self.groupBox_2) + self.label_4.setObjectName("label_4") + self.gridLayout_2.addWidget(self.label_4, 0, 0, 1, 1) + self.label_6 = QtWidgets.QLabel(self.groupBox_2) + self.label_6.setObjectName("label_6") + self.gridLayout_2.addWidget(self.label_6, 0, 5, 1, 1) + self.checkBox = QtWidgets.QCheckBox(self.groupBox_2) + self.checkBox.setLayoutDirection(QtCore.Qt.RightToLeft) + self.checkBox.setObjectName("checkBox") + self.gridLayout_2.addWidget(self.checkBox, 0, 7, 1, 1) + self.gridLayout_4.addWidget(self.groupBox_2, 0, 0, 1, 1) + self.groupBox = QtWidgets.QGroupBox(NewCurveDialog) + self.groupBox.setObjectName("groupBox") + self.gridLayout_3 = QtWidgets.QGridLayout(self.groupBox) + self.gridLayout_3.setContentsMargins(3, 3, 3, 3) + self.gridLayout_3.setSpacing(2) + self.gridLayout_3.setObjectName("gridLayout_3") + self.lineEdit_2 = QtWidgets.QLineEdit(self.groupBox) + self.lineEdit_2.setObjectName("lineEdit_2") + self.gridLayout_3.addWidget(self.lineEdit_2, 1, 2, 1, 1) + self.comboBox_6 = QtWidgets.QComboBox(self.groupBox) + self.comboBox_6.setObjectName("comboBox_6") + self.gridLayout_3.addWidget(self.comboBox_6, 2, 0, 1, 1) + self.pushButton = QtWidgets.QPushButton(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth()) + self.pushButton.setSizePolicy(sizePolicy) + self.pushButton.setObjectName("pushButton") + self.gridLayout_3.addWidget(self.pushButton, 4, 0, 1, 1) + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.gridLayout_3.addLayout(self.verticalLayout, 3, 0, 1, 1) + self.comboBox_7 = QtWidgets.QComboBox(self.groupBox) + self.comboBox_7.setObjectName("comboBox_7") + self.gridLayout_3.addWidget(self.comboBox_7, 2, 2, 1, 1) + self.lineEdit = QtWidgets.QLineEdit(self.groupBox) + self.lineEdit.setObjectName("lineEdit") + self.gridLayout_3.addWidget(self.lineEdit, 1, 0, 1, 1) + self.label = QtWidgets.QLabel(self.groupBox) + self.label.setObjectName("label") + self.gridLayout_3.addWidget(self.label, 0, 0, 1, 1) + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.gridLayout_3.addLayout(self.verticalLayout_2, 3, 2, 1, 1) + self.label_2 = QtWidgets.QLabel(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth()) + self.label_2.setSizePolicy(sizePolicy) + self.label_2.setObjectName("label_2") + self.gridLayout_3.addWidget(self.label_2, 0, 2, 1, 1) + self.line_2 = QtWidgets.QFrame(self.groupBox) + self.line_2.setFrameShape(QtWidgets.QFrame.VLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.gridLayout_3.addWidget(self.line_2, 0, 1, 4, 1) + self.gridLayout_4.addWidget(self.groupBox, 1, 0, 1, 1) + self.groupBox_3 = QtWidgets.QGroupBox(NewCurveDialog) + self.groupBox_3.setObjectName("groupBox_3") + self.gridLayout = QtWidgets.QGridLayout(self.groupBox_3) + self.gridLayout.setContentsMargins(3, 3, 3, 3) + self.gridLayout.setSpacing(2) + self.gridLayout.setObjectName("gridLayout") + self.doubleSpinBox = QtWidgets.QDoubleSpinBox(self.groupBox_3) + self.doubleSpinBox.setDecimals(1) + self.doubleSpinBox.setMaximum(20.0) + self.doubleSpinBox.setSingleStep(0.5) + self.doubleSpinBox.setProperty("value", 1.0) + self.doubleSpinBox.setObjectName("doubleSpinBox") + self.gridLayout.addWidget(self.doubleSpinBox, 3, 4, 1, 1) + self.line = QtWidgets.QFrame(self.groupBox_3) + self.line.setFrameShape(QtWidgets.QFrame.VLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.gridLayout.addWidget(self.line, 0, 2, 4, 1) + self.spinBox = QtWidgets.QSpinBox(self.groupBox_3) + self.spinBox.setMaximum(100) + self.spinBox.setProperty("value", 10) + self.spinBox.setObjectName("spinBox") + self.gridLayout.addWidget(self.spinBox, 3, 1, 1, 1) + self.label_8 = QtWidgets.QLabel(self.groupBox_3) + self.label_8.setObjectName("label_8") + self.gridLayout.addWidget(self.label_8, 0, 4, 1, 1) + self.comboBox = SymbolStyleEditor(self.groupBox_3) + self.comboBox.setObjectName("comboBox") + self.gridLayout.addWidget(self.comboBox, 1, 1, 1, 1) + self.comboBox_2 = LineStyleEditor(self.groupBox_3) + self.comboBox_2.setObjectName("comboBox_2") + self.gridLayout.addWidget(self.comboBox_2, 1, 4, 1, 1) + self.label_7 = QtWidgets.QLabel(self.groupBox_3) + self.label_7.setObjectName("label_7") + self.gridLayout.addWidget(self.label_7, 0, 1, 1, 1) + self.comboBox_4 = ColorListEditor(self.groupBox_3) + self.comboBox_4.setObjectName("comboBox_4") + self.gridLayout.addWidget(self.comboBox_4, 2, 4, 1, 1) + self.comboBox_5 = ColorListEditor(self.groupBox_3) + self.comboBox_5.setObjectName("comboBox_5") + self.gridLayout.addWidget(self.comboBox_5, 2, 1, 1, 1) + self.gridLayout_4.addWidget(self.groupBox_3, 2, 0, 1, 1) + self.groupBox_21 = QtWidgets.QGroupBox(NewCurveDialog) + self.groupBox_21.setObjectName("groupBox_21") + self.gridLayout_5 = QtWidgets.QGridLayout(self.groupBox_21) + self.gridLayout_5.setObjectName("gridLayout_5") + self.label_3 = QtWidgets.QLabel(self.groupBox_21) + self.label_3.setObjectName("label_3") + self.gridLayout_5.addWidget(self.label_3, 0, 0, 1, 1) + self.lineEdit_6 = QtWidgets.QLineEdit(self.groupBox_21) + self.lineEdit_6.setObjectName("lineEdit_6") + self.gridLayout_5.addWidget(self.lineEdit_6, 0, 1, 1, 1) + self.label_10 = QtWidgets.QLabel(self.groupBox_21) + self.label_10.setObjectName("label_10") + self.gridLayout_5.addWidget(self.label_10, 0, 2, 1, 1) + self.comboBox_3 = QtWidgets.QComboBox(self.groupBox_21) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.comboBox_3.sizePolicy().hasHeightForWidth()) + self.comboBox_3.setSizePolicy(sizePolicy) + self.comboBox_3.setObjectName("comboBox_3") + self.gridLayout_5.addWidget(self.comboBox_3, 0, 3, 1, 1) + self.gridLayout_4.addWidget(self.groupBox_21, 3, 0, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(NewCurveDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout_4.addWidget(self.buttonBox, 5, 0, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_4.addItem(spacerItem, 4, 0, 1, 1) + self.label_5.setBuddy(self.lineEdit_4) + self.label_4.setBuddy(self.lineEdit_3) + self.label_6.setBuddy(self.lineEdit_5) + self.label.setBuddy(self.lineEdit) + self.label_2.setBuddy(self.lineEdit_2) + self.label_8.setBuddy(self.comboBox_2) + self.label_7.setBuddy(self.comboBox) + self.label_3.setBuddy(self.lineEdit_6) + self.label_10.setBuddy(self.comboBox_3) + + self.retranslateUi(NewCurveDialog) + self.comboBox.setCurrentIndex(-1) + self.comboBox_2.setCurrentIndex(-1) + self.buttonBox.accepted.connect(NewCurveDialog.accept) + self.buttonBox.rejected.connect(NewCurveDialog.reject) + QtCore.QMetaObject.connectSlotsByName(NewCurveDialog) + NewCurveDialog.setTabOrder(self.lineEdit_3, self.lineEdit_4) + NewCurveDialog.setTabOrder(self.lineEdit_4, self.lineEdit_5) + NewCurveDialog.setTabOrder(self.lineEdit_5, self.checkBox) + NewCurveDialog.setTabOrder(self.checkBox, self.lineEdit) + NewCurveDialog.setTabOrder(self.lineEdit, self.comboBox) + NewCurveDialog.setTabOrder(self.comboBox, self.spinBox) + NewCurveDialog.setTabOrder(self.spinBox, self.comboBox_2) + NewCurveDialog.setTabOrder(self.comboBox_2, self.doubleSpinBox) + NewCurveDialog.setTabOrder(self.doubleSpinBox, self.lineEdit_6) + NewCurveDialog.setTabOrder(self.lineEdit_6, self.comboBox_3) + NewCurveDialog.setTabOrder(self.comboBox_3, self.buttonBox) + + def retranslateUi(self, NewCurveDialog): + _translate = QtCore.QCoreApplication.translate + NewCurveDialog.setWindowTitle(_translate("NewCurveDialog", "Create new data by function")) + self.groupBox_2.setTitle(_translate("NewCurveDialog", "Control variable i")) + self.lineEdit_3.setText(_translate("NewCurveDialog", "0")) + self.lineEdit_5.setText(_translate("NewCurveDialog", "10")) + self.label_5.setText(_translate("NewCurveDialog", "Stop at")) + self.lineEdit_4.setText(_translate("NewCurveDialog", "1")) + self.label_4.setText(_translate("NewCurveDialog", "Start at")) + self.label_6.setText(_translate("NewCurveDialog", "# points")) + self.checkBox.setText(_translate("NewCurveDialog", "Logarithmic?")) + self.groupBox.setTitle(_translate("NewCurveDialog", "Expressions")) + self.lineEdit_2.setText(_translate("NewCurveDialog", "x**2")) + self.pushButton.setText(_translate("NewCurveDialog", "Check")) + self.lineEdit.setText(_translate("NewCurveDialog", "i")) + self.label.setText(_translate("NewCurveDialog", " x = ")) + self.label_2.setText(_translate("NewCurveDialog", " y = ")) + self.groupBox_3.setTitle(_translate("NewCurveDialog", "Look")) + self.label_8.setText(_translate("NewCurveDialog", "Line")) + self.label_7.setText(_translate("NewCurveDialog", "Symbol")) + self.groupBox_21.setTitle(_translate("NewCurveDialog", "Designation")) + self.label_3.setText(_translate("NewCurveDialog", "Name")) + self.label_10.setText(_translate("NewCurveDialog", "Graph")) +from ..lib.delegates import ColorListEditor, LineStyleEditor, SymbolStyleEditor diff --git a/nmreval/gui_qt/_py/shift_scale_dialog.py b/nmreval/gui_qt/_py/shift_scale_dialog.py new file mode 100644 index 0000000..b8605e5 --- /dev/null +++ b/nmreval/gui_qt/_py/shift_scale_dialog.py @@ -0,0 +1,314 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/shift_scale_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_shift_dialog(object): + def setupUi(self, shift_dialog): + shift_dialog.setObjectName("shift_dialog") + shift_dialog.resize(959, 639) + self.verticalLayout = QtWidgets.QVBoxLayout(shift_dialog) + self.verticalLayout.setObjectName("verticalLayout") + self.splitter = QtWidgets.QSplitter(shift_dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.splitter.sizePolicy().hasHeightForWidth()) + self.splitter.setSizePolicy(sizePolicy) + self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setObjectName("splitter") + self.tabWidget = QtWidgets.QTabWidget(self.splitter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.tabWidget.sizePolicy().hasHeightForWidth()) + self.tabWidget.setSizePolicy(sizePolicy) + self.tabWidget.setObjectName("tabWidget") + self.shift_page = QtWidgets.QWidget() + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.shift_page.sizePolicy().hasHeightForWidth()) + self.shift_page.setSizePolicy(sizePolicy) + self.shift_page.setObjectName("shift_page") + self.gridLayout_2 = QtWidgets.QGridLayout(self.shift_page) + self.gridLayout_2.setContentsMargins(3, 3, 3, 3) + self.gridLayout_2.setObjectName("gridLayout_2") + self.label_7 = QtWidgets.QLabel(self.shift_page) + self.label_7.setObjectName("label_7") + self.gridLayout_2.addWidget(self.label_7, 2, 0, 1, 1) + self.label = QtWidgets.QLabel(self.shift_page) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label.setObjectName("label") + self.gridLayout_2.addWidget(self.label, 2, 1, 1, 1) + self.x_shift_spinbox = SciSpinBox(self.shift_page) + self.x_shift_spinbox.setMinimumSize(QtCore.QSize(150, 0)) + self.x_shift_spinbox.setDecimals(3) + self.x_shift_spinbox.setProperty("value", 0.0) + self.x_shift_spinbox.setObjectName("x_shift_spinbox") + self.gridLayout_2.addWidget(self.x_shift_spinbox, 2, 2, 1, 1) + self.label_5 = QtWidgets.QLabel(self.shift_page) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_5.sizePolicy().hasHeightForWidth()) + self.label_5.setSizePolicy(sizePolicy) + self.label_5.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_5.setObjectName("label_5") + self.gridLayout_2.addWidget(self.label_5, 3, 1, 1, 1) + self.y_shift_spinbox = SciSpinBox(self.shift_page) + self.y_shift_spinbox.setMinimumSize(QtCore.QSize(150, 0)) + self.y_shift_spinbox.setDecimals(3) + self.y_shift_spinbox.setProperty("value", 0.0) + self.y_shift_spinbox.setObjectName("y_shift_spinbox") + self.gridLayout_2.addWidget(self.y_shift_spinbox, 3, 2, 1, 1) + self.shift_table = QtWidgets.QTableWidget(self.shift_page) + self.shift_table.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.shift_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.shift_table.setColumnCount(3) + self.shift_table.setObjectName("shift_table") + self.shift_table.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + self.shift_table.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.shift_table.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + self.shift_table.setHorizontalHeaderItem(2, item) + self.shift_table.verticalHeader().setVisible(False) + self.gridLayout_2.addWidget(self.shift_table, 0, 0, 1, 3) + self.tabWidget.addTab(self.shift_page, "") + self.scale_page = QtWidgets.QWidget() + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.scale_page.sizePolicy().hasHeightForWidth()) + self.scale_page.setSizePolicy(sizePolicy) + self.scale_page.setObjectName("scale_page") + self.gridLayout = QtWidgets.QGridLayout(self.scale_page) + self.gridLayout.setContentsMargins(3, 3, 3, 3) + self.gridLayout.setObjectName("gridLayout") + self.label_3 = QtWidgets.QLabel(self.scale_page) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth()) + self.label_3.setSizePolicy(sizePolicy) + self.label_3.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_3.setObjectName("label_3") + self.gridLayout.addWidget(self.label_3, 1, 1, 1, 1) + self.x_scale_spinbox = SciSpinBox(self.scale_page) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.x_scale_spinbox.sizePolicy().hasHeightForWidth()) + self.x_scale_spinbox.setSizePolicy(sizePolicy) + self.x_scale_spinbox.setMinimumSize(QtCore.QSize(150, 0)) + self.x_scale_spinbox.setDecimals(3) + self.x_scale_spinbox.setProperty("value", 1.0) + self.x_scale_spinbox.setObjectName("x_scale_spinbox") + self.gridLayout.addWidget(self.x_scale_spinbox, 1, 2, 1, 1) + self.label_6 = QtWidgets.QLabel(self.scale_page) + self.label_6.setObjectName("label_6") + self.gridLayout.addWidget(self.label_6, 1, 0, 1, 1) + self.label_2 = QtWidgets.QLabel(self.scale_page) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth()) + self.label_2.setSizePolicy(sizePolicy) + self.label_2.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 2, 1, 1, 1) + self.y_scale_spinbox = SciSpinBox(self.scale_page) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.y_scale_spinbox.sizePolicy().hasHeightForWidth()) + self.y_scale_spinbox.setSizePolicy(sizePolicy) + self.y_scale_spinbox.setMinimumSize(QtCore.QSize(150, 0)) + self.y_scale_spinbox.setDecimals(3) + self.y_scale_spinbox.setProperty("value", 1.0) + self.y_scale_spinbox.setObjectName("y_scale_spinbox") + self.gridLayout.addWidget(self.y_scale_spinbox, 2, 2, 1, 1) + self.scale_table = QtWidgets.QTableWidget(self.scale_page) + self.scale_table.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.scale_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.scale_table.setObjectName("scale_table") + self.scale_table.setColumnCount(3) + self.scale_table.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + self.scale_table.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.scale_table.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + self.scale_table.setHorizontalHeaderItem(2, item) + self.scale_table.verticalHeader().setVisible(False) + self.gridLayout.addWidget(self.scale_table, 0, 0, 1, 3) + self.tabWidget.addTab(self.scale_page, "") + self.verticalFrame_2 = QtWidgets.QFrame(self.splitter) + self.verticalFrame_2.setObjectName("verticalFrame_2") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.verticalFrame_2) + self.verticalLayout_2.setSpacing(3) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.graphicsView = PlotWidget(self.verticalFrame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.graphicsView.sizePolicy().hasHeightForWidth()) + self.graphicsView.setSizePolicy(sizePolicy) + self.graphicsView.setObjectName("graphicsView") + self.verticalLayout_2.addWidget(self.graphicsView) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.label_4 = QtWidgets.QLabel(self.verticalFrame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4.setSizePolicy(sizePolicy) + self.label_4.setObjectName("label_4") + self.horizontalLayout.addWidget(self.label_4) + self.xlog_checkbox = QtWidgets.QCheckBox(self.verticalFrame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.xlog_checkbox.sizePolicy().hasHeightForWidth()) + self.xlog_checkbox.setSizePolicy(sizePolicy) + self.xlog_checkbox.setObjectName("xlog_checkbox") + self.horizontalLayout.addWidget(self.xlog_checkbox) + self.ylog_checkbox = QtWidgets.QCheckBox(self.verticalFrame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.ylog_checkbox.sizePolicy().hasHeightForWidth()) + self.ylog_checkbox.setSizePolicy(sizePolicy) + self.ylog_checkbox.setObjectName("ylog_checkbox") + self.horizontalLayout.addWidget(self.ylog_checkbox) + self.verticalLayout_2.addLayout(self.horizontalLayout) + self.verticalLayout.addWidget(self.splitter) + self.line = QtWidgets.QFrame(shift_dialog) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.verticalLayout.addWidget(self.line) + self.frame = QtWidgets.QFrame(shift_dialog) + self.frame.setObjectName("frame") + self.gridLayout_4 = QtWidgets.QGridLayout(self.frame) + self.gridLayout_4.setContentsMargins(3, 3, 3, 3) + self.gridLayout_4.setSpacing(3) + self.gridLayout_4.setObjectName("gridLayout_4") + self.value_checkbox = QtWidgets.QCheckBox(self.frame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.value_checkbox.sizePolicy().hasHeightForWidth()) + self.value_checkbox.setSizePolicy(sizePolicy) + self.value_checkbox.setChecked(True) + self.value_checkbox.setObjectName("value_checkbox") + self.gridLayout_4.addWidget(self.value_checkbox, 0, 1, 1, 1) + self.overwrite_checkbox = QtWidgets.QCheckBox(self.frame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.overwrite_checkbox.sizePolicy().hasHeightForWidth()) + self.overwrite_checkbox.setSizePolicy(sizePolicy) + self.overwrite_checkbox.setObjectName("overwrite_checkbox") + self.gridLayout_4.addWidget(self.overwrite_checkbox, 0, 0, 1, 1) + self.data_newgraph = QtWidgets.QCheckBox(self.frame) + self.data_newgraph.setChecked(True) + self.data_newgraph.setObjectName("data_newgraph") + self.gridLayout_4.addWidget(self.data_newgraph, 1, 0, 1, 1) + self.data_combobox = QtWidgets.QComboBox(self.frame) + self.data_combobox.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.data_combobox.sizePolicy().hasHeightForWidth()) + self.data_combobox.setSizePolicy(sizePolicy) + self.data_combobox.setObjectName("data_combobox") + self.gridLayout_4.addWidget(self.data_combobox, 2, 0, 1, 1) + self.values_newgraph = QtWidgets.QCheckBox(self.frame) + self.values_newgraph.setChecked(True) + self.values_newgraph.setObjectName("values_newgraph") + self.gridLayout_4.addWidget(self.values_newgraph, 1, 1, 1, 1) + self.values_combobox = QtWidgets.QComboBox(self.frame) + self.values_combobox.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.values_combobox.sizePolicy().hasHeightForWidth()) + self.values_combobox.setSizePolicy(sizePolicy) + self.values_combobox.setObjectName("values_combobox") + self.gridLayout_4.addWidget(self.values_combobox, 2, 1, 1, 1) + self.verticalLayout.addWidget(self.frame) + self.buttonBox = QtWidgets.QDialogButtonBox(shift_dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + self.label.setBuddy(self.x_shift_spinbox) + self.label_5.setBuddy(self.y_shift_spinbox) + self.label_3.setBuddy(self.x_scale_spinbox) + self.label_2.setBuddy(self.y_scale_spinbox) + + self.retranslateUi(shift_dialog) + self.tabWidget.setCurrentIndex(0) + self.buttonBox.accepted.connect(shift_dialog.accept) + self.buttonBox.rejected.connect(shift_dialog.reject) + QtCore.QMetaObject.connectSlotsByName(shift_dialog) + shift_dialog.setTabOrder(self.tabWidget, self.shift_table) + shift_dialog.setTabOrder(self.shift_table, self.x_shift_spinbox) + shift_dialog.setTabOrder(self.x_shift_spinbox, self.y_shift_spinbox) + shift_dialog.setTabOrder(self.y_shift_spinbox, self.scale_table) + shift_dialog.setTabOrder(self.scale_table, self.x_scale_spinbox) + shift_dialog.setTabOrder(self.x_scale_spinbox, self.y_scale_spinbox) + shift_dialog.setTabOrder(self.y_scale_spinbox, self.xlog_checkbox) + shift_dialog.setTabOrder(self.xlog_checkbox, self.ylog_checkbox) + shift_dialog.setTabOrder(self.ylog_checkbox, self.graphicsView) + + def retranslateUi(self, shift_dialog): + _translate = QtCore.QCoreApplication.translate + shift_dialog.setWindowTitle(_translate("shift_dialog", "Shift + Scale")) + self.label_7.setText(_translate("shift_dialog", "Global")) + self.label.setText(_translate("shift_dialog", "

x

")) + self.label_5.setText(_translate("shift_dialog", "

y

")) + item = self.shift_table.horizontalHeaderItem(0) + item.setText(_translate("shift_dialog", "Data")) + item = self.shift_table.horizontalHeaderItem(1) + item.setText(_translate("shift_dialog", "x")) + item = self.shift_table.horizontalHeaderItem(2) + item.setText(_translate("shift_dialog", "y")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.shift_page), _translate("shift_dialog", "Shift")) + self.label_3.setText(_translate("shift_dialog", "

x

")) + self.label_6.setText(_translate("shift_dialog", "Global:")) + self.label_2.setText(_translate("shift_dialog", "

y

")) + item = self.scale_table.horizontalHeaderItem(0) + item.setText(_translate("shift_dialog", "Data")) + item = self.scale_table.horizontalHeaderItem(1) + item.setText(_translate("shift_dialog", "x")) + item = self.scale_table.horizontalHeaderItem(2) + item.setText(_translate("shift_dialog", "y")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.scale_page), _translate("shift_dialog", "Scale")) + self.label_4.setText(_translate("shift_dialog", "Axes:")) + self.xlog_checkbox.setText(_translate("shift_dialog", "log x")) + self.ylog_checkbox.setText(_translate("shift_dialog", "log y")) + self.value_checkbox.setText(_translate("shift_dialog", "Export shift/scale values")) + self.overwrite_checkbox.setText(_translate("shift_dialog", "Overwrite data")) + self.data_newgraph.setText(_translate("shift_dialog", "New graph")) + self.values_newgraph.setText(_translate("shift_dialog", "New graph")) +from ..lib.utils import SciSpinBox +from pyqtgraph import PlotWidget diff --git a/nmreval/gui_qt/_py/skipdialog.py b/nmreval/gui_qt/_py/skipdialog.py new file mode 100644 index 0000000..f541dc2 --- /dev/null +++ b/nmreval/gui_qt/_py/skipdialog.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/skipdialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_SkipDialog(object): + def setupUi(self, SkipDialog): + SkipDialog.setObjectName("SkipDialog") + SkipDialog.resize(448, 208) + SkipDialog.setWindowTitle("") + self.gridLayout = QtWidgets.QGridLayout(SkipDialog) + self.gridLayout.setObjectName("gridLayout") + self.label_2 = QtWidgets.QLabel(SkipDialog) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem, 3, 0, 1, 1) + self.label_4 = QtWidgets.QLabel(SkipDialog) + self.label_4.setObjectName("label_4") + self.gridLayout.addWidget(self.label_4, 0, 0, 1, 4) + self.offset_spinbox = QtWidgets.QSpinBox(SkipDialog) + self.offset_spinbox.setMinimum(0) + self.offset_spinbox.setMaximum(1) + self.offset_spinbox.setProperty("value", 0) + self.offset_spinbox.setObjectName("offset_spinbox") + self.gridLayout.addWidget(self.offset_spinbox, 1, 3, 1, 1) + self.label = QtWidgets.QLabel(SkipDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 1, 2, 1, 1) + self.step_spinbox = QtWidgets.QSpinBox(SkipDialog) + self.step_spinbox.setMinimum(2) + self.step_spinbox.setObjectName("step_spinbox") + self.gridLayout.addWidget(self.step_spinbox, 1, 1, 1, 1) + self.invert_check = QtWidgets.QCheckBox(SkipDialog) + self.invert_check.setLayoutDirection(QtCore.Qt.LeftToRight) + self.invert_check.setObjectName("invert_check") + self.gridLayout.addWidget(self.invert_check, 1, 4, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(SkipDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 4, 0, 1, 5) + self.hide_button = QtWidgets.QRadioButton(SkipDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.hide_button.sizePolicy().hasHeightForWidth()) + self.hide_button.setSizePolicy(sizePolicy) + self.hide_button.setChecked(True) + self.hide_button.setObjectName("hide_button") + self.buttonGroup = QtWidgets.QButtonGroup(SkipDialog) + self.buttonGroup.setObjectName("buttonGroup") + self.buttonGroup.addButton(self.hide_button) + self.gridLayout.addWidget(self.hide_button, 2, 0, 1, 2) + self.delete_button = QtWidgets.QRadioButton(SkipDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.delete_button.sizePolicy().hasHeightForWidth()) + self.delete_button.setSizePolicy(sizePolicy) + self.delete_button.setObjectName("delete_button") + self.buttonGroup.addButton(self.delete_button) + self.gridLayout.addWidget(self.delete_button, 2, 2, 1, 3) + self.label_2.setBuddy(self.step_spinbox) + self.label.setBuddy(self.offset_spinbox) + + self.retranslateUi(SkipDialog) + self.buttonBox.accepted.connect(SkipDialog.accept) + self.buttonBox.rejected.connect(SkipDialog.reject) + QtCore.QMetaObject.connectSlotsByName(SkipDialog) + SkipDialog.setTabOrder(self.step_spinbox, self.offset_spinbox) + SkipDialog.setTabOrder(self.offset_spinbox, self.invert_check) + SkipDialog.setTabOrder(self.invert_check, self.hide_button) + SkipDialog.setTabOrder(self.hide_button, self.delete_button) + + def retranslateUi(self, SkipDialog): + _translate = QtCore.QCoreApplication.translate + self.label_2.setText(_translate("SkipDialog", "Step")) + self.label_4.setText(_translate("SkipDialog", "

Show every step point, beginning with offset (<step).
Use Invert to hide every step point.

")) + self.label.setText(_translate("SkipDialog", "Offset")) + self.invert_check.setText(_translate("SkipDialog", "Invert")) + self.hide_button.setText(_translate("SkipDialog", "Hide skipped pts.")) + self.delete_button.setText(_translate("SkipDialog", "Copy without any hidden pts.")) diff --git a/nmreval/gui_qt/_py/smoothdialog.py b/nmreval/gui_qt/_py/smoothdialog.py new file mode 100644 index 0000000..634fde5 --- /dev/null +++ b/nmreval/gui_qt/_py/smoothdialog.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/smoothdialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_SmoothDialog(object): + def setupUi(self, SmoothDialog): + SmoothDialog.setObjectName("SmoothDialog") + SmoothDialog.resize(451, 220) + self.gridLayout = QtWidgets.QGridLayout(SmoothDialog) + self.gridLayout.setSpacing(3) + self.gridLayout.setObjectName("gridLayout") + self.frac_label = QtWidgets.QLabel(SmoothDialog) + self.frac_label.setObjectName("frac_label") + self.gridLayout.addWidget(self.frac_label, 1, 0, 1, 1) + self.widget_2 = QtWidgets.QWidget(SmoothDialog) + self.widget_2.setObjectName("widget_2") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.widget_2) + self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_3.setSpacing(3) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.label_3 = QtWidgets.QLabel(self.widget_2) + self.label_3.setObjectName("label_3") + self.horizontalLayout_3.addWidget(self.label_3) + self.iter_spinBox = QtWidgets.QSpinBox(self.widget_2) + self.iter_spinBox.setMaximum(3) + self.iter_spinBox.setSingleStep(1) + self.iter_spinBox.setProperty("value", 1) + self.iter_spinBox.setObjectName("iter_spinBox") + self.horizontalLayout_3.addWidget(self.iter_spinBox) + self.gridLayout.addWidget(self.widget_2, 3, 0, 1, 2) + self.line = QtWidgets.QFrame(SmoothDialog) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.gridLayout.addWidget(self.line, 4, 0, 1, 2) + self.buttonBox = QtWidgets.QDialogButtonBox(SmoothDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 7, 0, 1, 2) + self.widget = QtWidgets.QWidget(SmoothDialog) + self.widget.setObjectName("widget") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widget) + self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_2.setSpacing(3) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label = QtWidgets.QLabel(self.widget) + self.label.setObjectName("label") + self.horizontalLayout_2.addWidget(self.label) + self.polynom_spinBox = QtWidgets.QSpinBox(self.widget) + self.polynom_spinBox.setMinimum(1) + self.polynom_spinBox.setMaximum(3) + self.polynom_spinBox.setObjectName("polynom_spinBox") + self.horizontalLayout_2.addWidget(self.polynom_spinBox) + self.gridLayout.addWidget(self.widget, 2, 0, 1, 2) + self.frac_spinBox = QtWidgets.QSpinBox(SmoothDialog) + self.frac_spinBox.setMinimum(1) + self.frac_spinBox.setMaximum(999) + self.frac_spinBox.setObjectName("frac_spinBox") + self.gridLayout.addWidget(self.frac_spinBox, 1, 1, 1, 1) + self.comboBox = QtWidgets.QComboBox(SmoothDialog) + self.comboBox.setObjectName("comboBox") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.gridLayout.addWidget(self.comboBox, 0, 0, 1, 2) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem, 6, 0, 1, 1) + self.y_checkBox = QtWidgets.QCheckBox(SmoothDialog) + self.y_checkBox.setObjectName("y_checkBox") + self.gridLayout.addWidget(self.y_checkBox, 5, 1, 1, 1) + self.x_checkBox = QtWidgets.QCheckBox(SmoothDialog) + self.x_checkBox.setObjectName("x_checkBox") + self.gridLayout.addWidget(self.x_checkBox, 5, 0, 1, 1) + self.frac_label.setBuddy(self.frac_spinBox) + self.label_3.setBuddy(self.iter_spinBox) + self.label.setBuddy(self.polynom_spinBox) + + self.retranslateUi(SmoothDialog) + self.buttonBox.accepted.connect(SmoothDialog.accept) + self.buttonBox.rejected.connect(SmoothDialog.reject) + QtCore.QMetaObject.connectSlotsByName(SmoothDialog) + SmoothDialog.setTabOrder(self.comboBox, self.frac_spinBox) + SmoothDialog.setTabOrder(self.frac_spinBox, self.polynom_spinBox) + SmoothDialog.setTabOrder(self.polynom_spinBox, self.iter_spinBox) + SmoothDialog.setTabOrder(self.iter_spinBox, self.x_checkBox) + SmoothDialog.setTabOrder(self.x_checkBox, self.y_checkBox) + + def retranslateUi(self, SmoothDialog): + _translate = QtCore.QCoreApplication.translate + SmoothDialog.setWindowTitle(_translate("SmoothDialog", "1D smoothing filter")) + self.frac_label.setText(_translate("SmoothDialog", "Window length")) + self.label_3.setText(_translate("SmoothDialog", "Iterations")) + self.label.setText(_translate("SmoothDialog", "Polynomial degree")) + self.polynom_spinBox.setToolTip(_translate("SmoothDialog", "Deg")) + self.frac_spinBox.setToolTip(_translate("SmoothDialog", "

Number of data points used as smoothing window.

")) + self.comboBox.setItemText(0, _translate("SmoothDialog", "Moving mean")) + self.comboBox.setItemText(1, _translate("SmoothDialog", "Savitzky-Golay")) + self.comboBox.setItemText(2, _translate("SmoothDialog", "Loess (slow, use for < 10000 pts)")) + self.comboBox.setItemText(3, _translate("SmoothDialog", "Moving median")) + self.comboBox.setItemText(4, _translate("SmoothDialog", "Moving standard deviation")) + self.comboBox.setItemText(5, _translate("SmoothDialog", "Moving variance")) + self.comboBox.setItemText(6, _translate("SmoothDialog", "Moving maximum")) + self.comboBox.setItemText(7, _translate("SmoothDialog", "Moving minimum")) + self.comboBox.setItemText(8, _translate("SmoothDialog", "Moving sum")) + self.y_checkBox.setText(_translate("SmoothDialog", "y log-spaced?")) + self.x_checkBox.setText(_translate("SmoothDialog", "x log-spaced?")) diff --git a/nmreval/gui_qt/_py/t1_calc_dialog.py b/nmreval/gui_qt/_py/t1_calc_dialog.py new file mode 100644 index 0000000..b560eba --- /dev/null +++ b/nmreval/gui_qt/_py/t1_calc_dialog.py @@ -0,0 +1,318 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/t1_calc_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(582, 698) + self.gridLayout_2 = QtWidgets.QGridLayout(Dialog) + self.gridLayout_2.setObjectName("gridLayout_2") + self.groupBox_2 = QtWidgets.QGroupBox(Dialog) + self.groupBox_2.setObjectName("groupBox_2") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox_2) + self.verticalLayout_2.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_2.setSpacing(0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.specdens_combobox = QtWidgets.QComboBox(self.groupBox_2) + self.specdens_combobox.setObjectName("specdens_combobox") + self.verticalLayout_2.addWidget(self.specdens_combobox) + self.specdens_frame = QtWidgets.QFrame(self.groupBox_2) + self.specdens_frame.setObjectName("specdens_frame") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.specdens_frame) + self.verticalLayout_3.setSpacing(0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.verticalLayout_2.addWidget(self.specdens_frame) + self.coupling_combobox = QtWidgets.QComboBox(self.groupBox_2) + self.coupling_combobox.setObjectName("coupling_combobox") + self.verticalLayout_2.addWidget(self.coupling_combobox) + self.coupling_frame = QtWidgets.QFrame(self.groupBox_2) + self.coupling_frame.setObjectName("coupling_frame") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.coupling_frame) + self.verticalLayout_4.setContentsMargins(-1, -1, 1, 1) + self.verticalLayout_4.setSpacing(0) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.verticalLayout_2.addWidget(self.coupling_frame) + self.gridLayout_2.addWidget(self.groupBox_2, 1, 0, 1, 1) + self.groupBox_3 = QtWidgets.QGroupBox(Dialog) + self.groupBox_3.setObjectName("groupBox_3") + self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBox_3) + self.gridLayout_4.setContentsMargins(3, 3, 3, 3) + self.gridLayout_4.setSpacing(3) + self.gridLayout_4.setObjectName("gridLayout_4") + self.graph_combobox = QtWidgets.QComboBox(self.groupBox_3) + self.graph_combobox.setEnabled(False) + self.graph_combobox.setObjectName("graph_combobox") + self.gridLayout_4.addWidget(self.graph_combobox, 1, 1, 1, 1) + self.graph_checkbox = QtWidgets.QCheckBox(self.groupBox_3) + self.graph_checkbox.setChecked(True) + self.graph_checkbox.setObjectName("graph_checkbox") + self.gridLayout_4.addWidget(self.graph_checkbox, 1, 0, 1, 1) + self.relax_combox = QtWidgets.QComboBox(self.groupBox_3) + self.relax_combox.setObjectName("relax_combox") + self.relax_combox.addItem("") + self.relax_combox.addItem("") + self.gridLayout_4.addWidget(self.relax_combox, 0, 0, 1, 2) + self.gridLayout_2.addWidget(self.groupBox_3, 2, 0, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_2.addItem(spacerItem, 3, 0, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout_2.addWidget(self.buttonBox, 4, 0, 1, 1) + self.groupBox = QtWidgets.QGroupBox(Dialog) + self.groupBox.setObjectName("groupBox") + self.gridLayout_3 = QtWidgets.QGridLayout(self.groupBox) + self.gridLayout_3.setContentsMargins(3, 3, 3, 3) + self.gridLayout_3.setSpacing(2) + self.gridLayout_3.setObjectName("gridLayout_3") + self.second_x_lineEdit = QtWidgets.QLineEdit(self.groupBox) + self.second_x_lineEdit.setObjectName("second_x_lineEdit") + self.gridLayout_3.addWidget(self.second_x_lineEdit, 10, 1, 1, 1) + self.x_input_combobox = QtWidgets.QComboBox(self.groupBox) + self.x_input_combobox.setObjectName("x_input_combobox") + self.x_input_combobox.addItem("") + self.x_input_combobox.addItem("") + self.gridLayout_3.addWidget(self.x_input_combobox, 1, 1, 1, 1) + self.horizontalLayout_4 = QtWidgets.QHBoxLayout() + self.horizontalLayout_4.setSpacing(2) + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.radioButton = QtWidgets.QRadioButton(self.groupBox) + self.radioButton.setChecked(True) + self.radioButton.setObjectName("radioButton") + self.buttonGroup = QtWidgets.QButtonGroup(Dialog) + self.buttonGroup.setObjectName("buttonGroup") + self.buttonGroup.addButton(self.radioButton) + self.horizontalLayout_4.addWidget(self.radioButton) + self.radioButton_2 = QtWidgets.QRadioButton(self.groupBox) + self.radioButton_2.setObjectName("radioButton_2") + self.buttonGroup.addButton(self.radioButton_2) + self.horizontalLayout_4.addWidget(self.radioButton_2) + self.radioButton_4 = QtWidgets.QRadioButton(self.groupBox) + self.radioButton_4.setObjectName("radioButton_4") + self.buttonGroup.addButton(self.radioButton_4) + self.horizontalLayout_4.addWidget(self.radioButton_4) + self.radioButton_3 = QtWidgets.QRadioButton(self.groupBox) + self.radioButton_3.setObjectName("radioButton_3") + self.buttonGroup.addButton(self.radioButton_3) + self.horizontalLayout_4.addWidget(self.radioButton_3) + self.gridLayout_3.addLayout(self.horizontalLayout_4, 0, 0, 1, 2) + self.label_7 = QtWidgets.QLabel(self.groupBox) + self.label_7.setObjectName("label_7") + self.gridLayout_3.addWidget(self.label_7, 10, 0, 1, 1) + self.line = QtWidgets.QFrame(self.groupBox) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") + self.gridLayout_3.addWidget(self.line, 9, 0, 1, 2) + self.line_2 = QtWidgets.QFrame(self.groupBox) + self.line_2.setFrameShape(QtWidgets.QFrame.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.gridLayout_3.addWidget(self.line_2, 7, 0, 1, 2) + self.range_widget = QtWidgets.QWidget(self.groupBox) + self.range_widget.setObjectName("range_widget") + self.gridLayout = QtWidgets.QGridLayout(self.range_widget) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setObjectName("gridLayout") + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem1, 0, 0, 1, 1) + self.stop_lineEdit = QtWidgets.QLineEdit(self.range_widget) + self.stop_lineEdit.setObjectName("stop_lineEdit") + self.gridLayout.addWidget(self.stop_lineEdit, 0, 3, 1, 1) + self.label_4 = QtWidgets.QLabel(self.range_widget) + self.label_4.setObjectName("label_4") + self.gridLayout.addWidget(self.label_4, 0, 2, 1, 1) + self.spinBox = QtWidgets.QSpinBox(self.range_widget) + self.spinBox.setProperty("value", 50) + self.spinBox.setObjectName("spinBox") + self.gridLayout.addWidget(self.spinBox, 0, 5, 1, 1) + self.start_lineEdit = QtWidgets.QLineEdit(self.range_widget) + self.start_lineEdit.setObjectName("start_lineEdit") + self.gridLayout.addWidget(self.start_lineEdit, 0, 1, 1, 1) + self.checkBox = QtWidgets.QCheckBox(self.range_widget) + self.checkBox.setObjectName("checkBox") + self.gridLayout.addWidget(self.checkBox, 0, 6, 1, 1) + self.gridLayout_3.addWidget(self.range_widget, 2, 0, 1, 2) + self.data_widget = QtWidgets.QWidget(self.groupBox) + self.data_widget.setObjectName("data_widget") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.data_widget) + self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_2.setSpacing(2) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.tau_graph_combobox = QtWidgets.QComboBox(self.data_widget) + self.tau_graph_combobox.setObjectName("tau_graph_combobox") + self.horizontalLayout_2.addWidget(self.tau_graph_combobox) + self.tau_set_combobox = QtWidgets.QComboBox(self.data_widget) + self.tau_set_combobox.setObjectName("tau_set_combobox") + self.horizontalLayout_2.addWidget(self.tau_set_combobox) + self.label_10 = QtWidgets.QLabel(self.data_widget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_10.sizePolicy().hasHeightForWidth()) + self.label_10.setSizePolicy(sizePolicy) + self.label_10.setObjectName("label_10") + self.horizontalLayout_2.addWidget(self.label_10) + self.x_radioButton = QtWidgets.QRadioButton(self.data_widget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.x_radioButton.sizePolicy().hasHeightForWidth()) + self.x_radioButton.setSizePolicy(sizePolicy) + self.x_radioButton.setObjectName("x_radioButton") + self.buttonGroup_2 = QtWidgets.QButtonGroup(Dialog) + self.buttonGroup_2.setObjectName("buttonGroup_2") + self.buttonGroup_2.addButton(self.x_radioButton) + self.horizontalLayout_2.addWidget(self.x_radioButton) + self.y_radioButton = QtWidgets.QRadioButton(self.data_widget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.y_radioButton.sizePolicy().hasHeightForWidth()) + self.y_radioButton.setSizePolicy(sizePolicy) + self.y_radioButton.setChecked(True) + self.y_radioButton.setObjectName("y_radioButton") + self.buttonGroup_2.addButton(self.y_radioButton) + self.horizontalLayout_2.addWidget(self.y_radioButton) + self.gridLayout_3.addWidget(self.data_widget, 3, 0, 1, 2) + self.temp_widget = QtWidgets.QWidget(self.groupBox) + self.temp_widget.setObjectName("temp_widget") + self.gridLayout_5 = QtWidgets.QGridLayout(self.temp_widget) + self.gridLayout_5.setContentsMargins(0, 0, 0, 0) + self.gridLayout_5.setHorizontalSpacing(6) + self.gridLayout_5.setVerticalSpacing(0) + self.gridLayout_5.setObjectName("gridLayout_5") + self.arr_widget = QtWidgets.QWidget(self.temp_widget) + self.arr_widget.setObjectName("arr_widget") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.arr_widget) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setSpacing(2) + self.horizontalLayout.setObjectName("horizontalLayout") + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem2) + self.label = QtWidgets.QLabel(self.arr_widget) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.tau0_lineEdit = QtWidgets.QLineEdit(self.arr_widget) + self.tau0_lineEdit.setObjectName("tau0_lineEdit") + self.horizontalLayout.addWidget(self.tau0_lineEdit) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem3) + self.label_2 = QtWidgets.QLabel(self.arr_widget) + self.label_2.setObjectName("label_2") + self.horizontalLayout.addWidget(self.label_2) + self.ea_lineEdit = QtWidgets.QLineEdit(self.arr_widget) + self.ea_lineEdit.setObjectName("ea_lineEdit") + self.horizontalLayout.addWidget(self.ea_lineEdit) + self.gridLayout_5.addWidget(self.arr_widget, 0, 1, 1, 1) + self.vft_widget = QtWidgets.QWidget(self.temp_widget) + self.vft_widget.setObjectName("vft_widget") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.vft_widget) + self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_3.setSpacing(2) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.label_3 = QtWidgets.QLabel(self.vft_widget) + self.label_3.setObjectName("label_3") + self.horizontalLayout_3.addWidget(self.label_3) + self.tau0_vft_lineEdit = QtWidgets.QLineEdit(self.vft_widget) + self.tau0_vft_lineEdit.setObjectName("tau0_vft_lineEdit") + self.horizontalLayout_3.addWidget(self.tau0_vft_lineEdit) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_3.addItem(spacerItem4) + self.label_5 = QtWidgets.QLabel(self.vft_widget) + self.label_5.setObjectName("label_5") + self.horizontalLayout_3.addWidget(self.label_5) + self.b_vft_lineEdit = QtWidgets.QLineEdit(self.vft_widget) + self.b_vft_lineEdit.setObjectName("b_vft_lineEdit") + self.horizontalLayout_3.addWidget(self.b_vft_lineEdit) + spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_3.addItem(spacerItem5) + self.label_6 = QtWidgets.QLabel(self.vft_widget) + self.label_6.setObjectName("label_6") + self.horizontalLayout_3.addWidget(self.label_6) + self.t0_vft_lineEdit = QtWidgets.QLineEdit(self.vft_widget) + self.t0_vft_lineEdit.setObjectName("t0_vft_lineEdit") + self.horizontalLayout_3.addWidget(self.t0_vft_lineEdit) + self.gridLayout_5.addWidget(self.vft_widget, 1, 1, 1, 1) + self.temp_combobox = QtWidgets.QComboBox(self.temp_widget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.temp_combobox.sizePolicy().hasHeightForWidth()) + self.temp_combobox.setSizePolicy(sizePolicy) + self.temp_combobox.setObjectName("temp_combobox") + self.temp_combobox.addItem("") + self.temp_combobox.addItem("") + self.gridLayout_5.addWidget(self.temp_combobox, 0, 0, 2, 1) + self.gridLayout_3.addWidget(self.temp_widget, 4, 0, 1, 2) + self.xtype_combobox = QtWidgets.QComboBox(self.groupBox) + self.xtype_combobox.setObjectName("xtype_combobox") + self.xtype_combobox.addItem("") + self.xtype_combobox.addItem("") + self.xtype_combobox.addItem("") + self.xtype_combobox.addItem("") + self.gridLayout_3.addWidget(self.xtype_combobox, 8, 1, 1, 1) + self.label_8 = QtWidgets.QLabel(self.groupBox) + self.label_8.setObjectName("label_8") + self.gridLayout_3.addWidget(self.label_8, 8, 0, 1, 1) + self.label_9 = QtWidgets.QLabel(self.groupBox) + self.label_9.setObjectName("label_9") + self.gridLayout_3.addWidget(self.label_9, 1, 0, 1, 1) + self.gridLayout_2.addWidget(self.groupBox, 0, 0, 1, 1) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Calculate relaxation")) + self.groupBox_2.setTitle(_translate("Dialog", "Model")) + self.groupBox_3.setTitle(_translate("Dialog", "Result")) + self.graph_checkbox.setText(_translate("Dialog", "New graph?")) + self.relax_combox.setStatusTip(_translate("Dialog", "NOTE: Mean values are not available for all spectral densities. For more information ask someone.")) + self.relax_combox.setItemText(0, _translate("Dialog", "Spin-Lattice Relaxation T1")) + self.relax_combox.setItemText(1, _translate("Dialog", "Spin-Spin Relaxation T2")) + self.groupBox.setTitle(_translate("Dialog", "Axis")) + self.x_input_combobox.setItemText(0, _translate("Dialog", "Range")) + self.x_input_combobox.setItemText(1, _translate("Dialog", "Data")) + self.radioButton.setText(_translate("Dialog", "τ / s")) + self.radioButton_2.setText(_translate("Dialog", "ω / Hz")) + self.radioButton_4.setText(_translate("Dialog", "1000 K / T")) + self.radioButton_3.setText(_translate("Dialog", "T / K")) + self.label_7.setText(_translate("Dialog", "2nd axis")) + self.label_4.setText(_translate("Dialog", "–")) + self.spinBox.setSuffix(_translate("Dialog", " pts.")) + self.checkBox.setText(_translate("Dialog", "Log?")) + self.label_10.setText(_translate("Dialog", " Use")) + self.x_radioButton.setText(_translate("Dialog", "x")) + self.y_radioButton.setText(_translate("Dialog", "y")) + self.label.setText(_translate("Dialog", "τ0 / s ")) + self.tau0_lineEdit.setText(_translate("Dialog", "1")) + self.label_2.setText(_translate("Dialog", "E_A / eV ")) + self.ea_lineEdit.setText(_translate("Dialog", "1")) + self.label_3.setText(_translate("Dialog", "τ0 / s ")) + self.tau0_vft_lineEdit.setText(_translate("Dialog", "1")) + self.label_5.setText(_translate("Dialog", "B / K ")) + self.b_vft_lineEdit.setText(_translate("Dialog", "1")) + self.label_6.setText(_translate("Dialog", "T_0 / K ")) + self.t0_vft_lineEdit.setText(_translate("Dialog", "1")) + self.temp_combobox.setItemText(0, _translate("Dialog", "Arrhenius")) + self.temp_combobox.setItemText(1, _translate("Dialog", "VFT")) + self.xtype_combobox.setItemText(0, _translate("Dialog", "Function parameter: τ")) + self.xtype_combobox.setItemText(1, _translate("Dialog", "Peak time: τₚ")) + self.xtype_combobox.setItemText(2, _translate("Dialog", "Arithmetic mean: ⟨τ⟩")) + self.xtype_combobox.setItemText(3, _translate("Dialog", "Geometric mean: exp(⟨ln τ⟩)")) + self.label_8.setText(_translate("Dialog", "Interpretation as:")) + self.label_9.setText(_translate("Dialog", "Input from: ")) diff --git a/nmreval/gui_qt/_py/t1_dock.py b/nmreval/gui_qt/_py/t1_dock.py new file mode 100644 index 0000000..cc1bdf0 --- /dev/null +++ b/nmreval/gui_qt/_py/t1_dock.py @@ -0,0 +1,258 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/t1_dock.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_t1dialog(object): + def setupUi(self, t1dialog): + t1dialog.setObjectName("t1dialog") + t1dialog.resize(295, 771) + self.dockWidgetContents = QtWidgets.QWidget() + self.dockWidgetContents.setObjectName("dockWidgetContents") + self.verticalLayout = QtWidgets.QVBoxLayout(self.dockWidgetContents) + self.verticalLayout.setObjectName("verticalLayout") + self.scrollArea = QtWidgets.QScrollArea(self.dockWidgetContents) + self.scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame) + self.scrollArea.setWidgetResizable(True) + self.scrollArea.setObjectName("scrollArea") + self.scrollAreaWidgetContents = QtWidgets.QWidget() + self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 279, 727)) + self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") + self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents) + self.verticalLayout_7.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_7.setSpacing(0) + self.verticalLayout_7.setObjectName("verticalLayout_7") + self.groupBox_1 = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) + self.groupBox_1.setObjectName("groupBox_1") + self.gridLayout_3 = QtWidgets.QGridLayout(self.groupBox_1) + self.gridLayout_3.setVerticalSpacing(0) + self.gridLayout_3.setObjectName("gridLayout_3") + self.comboBox_3 = QtWidgets.QComboBox(self.groupBox_1) + self.comboBox_3.setObjectName("comboBox_3") + self.comboBox_3.addItem("") + self.comboBox_3.addItem("") + self.comboBox_3.addItem("") + self.comboBox_3.addItem("") + self.gridLayout_3.addWidget(self.comboBox_3, 0, 1, 1, 1) + self.label_6 = QtWidgets.QLabel(self.groupBox_1) + self.label_6.setObjectName("label_6") + self.gridLayout_3.addWidget(self.label_6, 0, 0, 1, 1) + self.comboBox_2 = QtWidgets.QComboBox(self.groupBox_1) + self.comboBox_2.setObjectName("comboBox_2") + self.comboBox_2.addItem("") + self.comboBox_2.addItem("") + self.comboBox_2.addItem("") + self.gridLayout_3.addWidget(self.comboBox_2, 1, 1, 1, 1) + self.label_5 = QtWidgets.QLabel(self.groupBox_1) + self.label_5.setObjectName("label_5") + self.gridLayout_3.addWidget(self.label_5, 1, 0, 1, 1) + self.verticalLayout_7.addWidget(self.groupBox_1) + self.groupBox_5 = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) + self.groupBox_5.setObjectName("groupBox_5") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.groupBox_5) + self.verticalLayout_6.setSpacing(0) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.comboBox_6 = QtWidgets.QComboBox(self.groupBox_5) + self.comboBox_6.setObjectName("comboBox_6") + self.comboBox_6.addItem("") + self.comboBox_6.addItem("") + self.comboBox_6.addItem("") + self.comboBox_6.addItem("") + self.verticalLayout_6.addWidget(self.comboBox_6) + self.frame = QtWidgets.QFrame(self.groupBox_5) + self.frame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame.setFrameShadow(QtWidgets.QFrame.Plain) + self.frame.setObjectName("frame") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame) + self.horizontalLayout.setContentsMargins(0, 6, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label_9 = QtWidgets.QLabel(self.frame) + self.label_9.setObjectName("label_9") + self.horizontalLayout.addWidget(self.label_9) + self.lineEdit_2 = QtWidgets.QLineEdit(self.frame) + self.lineEdit_2.setObjectName("lineEdit_2") + self.horizontalLayout.addWidget(self.lineEdit_2) + self.label_10 = QtWidgets.QLabel(self.frame) + self.label_10.setObjectName("label_10") + self.horizontalLayout.addWidget(self.label_10) + self.lineEdit_3 = QtWidgets.QLineEdit(self.frame) + self.lineEdit_3.setObjectName("lineEdit_3") + self.horizontalLayout.addWidget(self.lineEdit_3) + self.checkBox = QtWidgets.QCheckBox(self.frame) + self.checkBox.setObjectName("checkBox") + self.horizontalLayout.addWidget(self.checkBox) + self.verticalLayout_6.addWidget(self.frame) + self.frame_2 = QtWidgets.QFrame(self.groupBox_5) + self.frame_2.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame_2.setFrameShadow(QtWidgets.QFrame.Plain) + self.frame_2.setObjectName("frame_2") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame_2) + self.horizontalLayout_2.setContentsMargins(0, 6, 0, 0) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label_11 = QtWidgets.QLabel(self.frame_2) + self.label_11.setObjectName("label_11") + self.horizontalLayout_2.addWidget(self.label_11) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem) + self.label_13 = QtWidgets.QLabel(self.frame_2) + self.label_13.setObjectName("label_13") + self.horizontalLayout_2.addWidget(self.label_13) + self.label_12 = QtWidgets.QLabel(self.frame_2) + self.label_12.setObjectName("label_12") + self.horizontalLayout_2.addWidget(self.label_12) + self.pushButton_2 = QtWidgets.QPushButton(self.frame_2) + self.pushButton_2.setObjectName("pushButton_2") + self.horizontalLayout_2.addWidget(self.pushButton_2) + self.verticalLayout_6.addWidget(self.frame_2) + self.verticalLayout_7.addWidget(self.groupBox_5) + self.groupBox_2 = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) + self.groupBox_2.setObjectName("groupBox_2") + self.gridLayout = QtWidgets.QGridLayout(self.groupBox_2) + self.gridLayout.setVerticalSpacing(0) + self.gridLayout.setObjectName("gridLayout") + self.label_3 = QtWidgets.QLabel(self.groupBox_2) + self.label_3.setObjectName("label_3") + self.gridLayout.addWidget(self.label_3, 0, 0, 1, 1) + self.label_2 = QtWidgets.QLabel(self.groupBox_2) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 0, 3, 1, 1) + self.t1_min_edit = QtWidgets.QLineEdit(self.groupBox_2) + self.t1_min_edit.setObjectName("t1_min_edit") + self.gridLayout.addWidget(self.t1_min_edit, 0, 4, 1, 1) + self.label_7 = QtWidgets.QLabel(self.groupBox_2) + self.label_7.setObjectName("label_7") + self.gridLayout.addWidget(self.label_7, 0, 5, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem1, 0, 1, 1, 1) + self.t1_pos_edit = QtWidgets.QLineEdit(self.groupBox_2) + self.t1_pos_edit.setObjectName("t1_pos_edit") + self.gridLayout.addWidget(self.t1_pos_edit, 0, 2, 1, 1) + self.label = QtWidgets.QLabel(self.groupBox_2) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 1, 0, 1, 1) + self.label_8 = QtWidgets.QLabel(self.groupBox_2) + self.label_8.setObjectName("label_8") + self.gridLayout.addWidget(self.label_8, 1, 5, 1, 1) + self.lineEdit = QtWidgets.QLineEdit(self.groupBox_2) + self.lineEdit.setInputMethodHints(QtCore.Qt.ImhDigitsOnly|QtCore.Qt.ImhFormattedNumbersOnly|QtCore.Qt.ImhPreferNumbers) + self.lineEdit.setObjectName("lineEdit") + self.gridLayout.addWidget(self.lineEdit, 1, 4, 1, 1) + self.verticalLayout_7.addWidget(self.groupBox_2) + self.groupBox = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) + self.groupBox.setObjectName("groupBox") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox) + self.verticalLayout_2.setSpacing(0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.comboBox_4 = QtWidgets.QComboBox(self.groupBox) + self.comboBox_4.setObjectName("comboBox_4") + self.verticalLayout_2.addWidget(self.comboBox_4) + self.verticalLayout_3 = QtWidgets.QVBoxLayout() + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.verticalLayout_2.addLayout(self.verticalLayout_3) + self.label_14 = QtWidgets.QLabel(self.groupBox) + self.label_14.setObjectName("label_14") + self.verticalLayout_2.addWidget(self.label_14) + self.verticalLayout_7.addWidget(self.groupBox) + self.groupBox_4 = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) + self.groupBox_4.setObjectName("groupBox_4") + self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.groupBox_4) + self.verticalLayout_5.setSpacing(0) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.comboBox_5 = QtWidgets.QComboBox(self.groupBox_4) + self.comboBox_5.setObjectName("comboBox_5") + self.verticalLayout_5.addWidget(self.comboBox_5) + self.verticalLayout_4 = QtWidgets.QVBoxLayout() + self.verticalLayout_4.setContentsMargins(-1, -1, 0, 0) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.verticalLayout_5.addLayout(self.verticalLayout_4) + self.verticalLayout_7.addWidget(self.groupBox_4) + self.groupBox_3 = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) + self.groupBox_3.setObjectName("groupBox_3") + self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox_3) + self.gridLayout_2.setContentsMargins(-1, 1, -1, -1) + self.gridLayout_2.setObjectName("gridLayout_2") + self.comboBox = QtWidgets.QComboBox(self.groupBox_3) + self.comboBox.setObjectName("comboBox") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.gridLayout_2.addWidget(self.comboBox, 0, 1, 1, 1) + self.label_4 = QtWidgets.QLabel(self.groupBox_3) + self.label_4.setObjectName("label_4") + self.gridLayout_2.addWidget(self.label_4, 0, 0, 1, 1) + self.checkBox_interpol = QtWidgets.QCheckBox(self.groupBox_3) + self.checkBox_interpol.setObjectName("checkBox_interpol") + self.gridLayout_2.addWidget(self.checkBox_interpol, 1, 1, 1, 1) + self.verticalLayout_7.addWidget(self.groupBox_3) + self.pushButton = QtWidgets.QPushButton(self.scrollAreaWidgetContents) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.pushButton.setFont(font) + self.pushButton.setObjectName("pushButton") + self.verticalLayout_7.addWidget(self.pushButton) + spacerItem2 = QtWidgets.QSpacerItem(17, 423, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_7.addItem(spacerItem2) + self.scrollArea.setWidget(self.scrollAreaWidgetContents) + self.verticalLayout.addWidget(self.scrollArea) + t1dialog.setWidget(self.dockWidgetContents) + + self.retranslateUi(t1dialog) + QtCore.QMetaObject.connectSlotsByName(t1dialog) + + def retranslateUi(self, t1dialog): + _translate = QtCore.QCoreApplication.translate + t1dialog.setWindowTitle(_translate("t1dialog", "Evaluate T1 (temperature)")) + self.groupBox_1.setTitle(_translate("t1dialog", "Axes")) + self.comboBox_3.setItemText(0, _translate("t1dialog", "T1")) + self.comboBox_3.setItemText(1, _translate("t1dialog", "1/T1")) + self.comboBox_3.setItemText(2, _translate("t1dialog", "log10(T1)")) + self.comboBox_3.setItemText(3, _translate("t1dialog", "log10(1/T1)")) + self.label_6.setText(_translate("t1dialog", "Relaxation in")) + self.comboBox_2.setItemText(0, _translate("t1dialog", "T")) + self.comboBox_2.setItemText(1, _translate("t1dialog", "1000/T")) + self.comboBox_2.setItemText(2, _translate("t1dialog", "1/T")) + self.label_5.setText(_translate("t1dialog", "Temperature in")) + self.groupBox_5.setTitle(_translate("t1dialog", "T1 minimon")) + self.comboBox_6.setItemText(0, _translate("t1dialog", "Data minimum")) + self.comboBox_6.setItemText(1, _translate("t1dialog", "Parabola")) + self.comboBox_6.setItemText(2, _translate("t1dialog", "Cubic spline")) + self.comboBox_6.setItemText(3, _translate("t1dialog", "Pchip")) + self.label_9.setText(_translate("t1dialog", "start (K)")) + self.lineEdit_2.setPlaceholderText(_translate("t1dialog", "1")) + self.label_10.setText(_translate("t1dialog", " end (K)")) + self.lineEdit_3.setPlaceholderText(_translate("t1dialog", "2")) + self.checkBox.setText(_translate("t1dialog", "Show?")) + self.label_11.setText(_translate("t1dialog", "Minimon")) + self.label_13.setText(_translate("t1dialog", "x value")) + self.label_12.setText(_translate("t1dialog", "y value")) + self.pushButton_2.setText(_translate("t1dialog", "Use")) + self.groupBox_2.setTitle(_translate("t1dialog", "Parameter")) + self.label_3.setText(_translate("t1dialog", "

T1 minimum

")) + self.label_2.setText(_translate("t1dialog", "K")) + self.t1_min_edit.setPlaceholderText(_translate("t1dialog", "1e-3")) + self.label_7.setText(_translate("t1dialog", "s")) + self.t1_pos_edit.setPlaceholderText(_translate("t1dialog", "100")) + self.label.setText(_translate("t1dialog", "frequency")) + self.label_8.setText(_translate("t1dialog", "Hz")) + self.lineEdit.setPlaceholderText(_translate("t1dialog", "100e6")) + self.groupBox.setTitle(_translate("t1dialog", "Spectral density")) + self.label_14.setText(_translate("t1dialog", "Calculated minimum:")) + self.groupBox_4.setTitle(_translate("t1dialog", "Coupling")) + self.groupBox_3.setTitle(_translate("t1dialog", "Result")) + self.comboBox.setStatusTip(_translate("t1dialog", "NOTE: Mean values are not available for all spectral densities. For more information ask someone.")) + self.comboBox.setItemText(0, _translate("t1dialog", "Fit parameter: τ")) + self.comboBox.setItemText(1, _translate("t1dialog", "Peak time: τₚ")) + self.comboBox.setItemText(2, _translate("t1dialog", "Arithmetic mean: ⟨τ⟩")) + self.comboBox.setItemText(3, _translate("t1dialog", "Geometric mean: exp(⟨ln τ⟩)")) + self.label_4.setText(_translate("t1dialog", "Result as")) + self.checkBox_interpol.setText(_translate("t1dialog", "Use interpolation")) + self.pushButton.setText(_translate("t1dialog", "Calculate")) diff --git a/nmreval/gui_qt/_py/t1_tau_calculation.py b/nmreval/gui_qt/_py/t1_tau_calculation.py new file mode 100644 index 0000000..d61945a --- /dev/null +++ b/nmreval/gui_qt/_py/t1_tau_calculation.py @@ -0,0 +1,215 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/t1_tau_calculation.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(400, 799) + self.verticalLayout = QtWidgets.QVBoxLayout(Form) + self.verticalLayout.setObjectName("verticalLayout") + self.groupBox_2 = QtWidgets.QGroupBox(Form) + self.groupBox_2.setObjectName("groupBox_2") + self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox_2) + self.gridLayout_2.setContentsMargins(3, 3, 3, 3) + self.gridLayout_2.setHorizontalSpacing(3) + self.gridLayout_2.setVerticalSpacing(1) + self.gridLayout_2.setObjectName("gridLayout_2") + self.freq_spinbox = QtWidgets.QDoubleSpinBox(self.groupBox_2) + self.freq_spinbox.setMaximum(999.99) + self.freq_spinbox.setProperty("value", 100.0) + self.freq_spinbox.setObjectName("freq_spinbox") + self.gridLayout_2.addWidget(self.freq_spinbox, 0, 0, 1, 1) + self.freq_combox = QtWidgets.QComboBox(self.groupBox_2) + self.freq_combox.setObjectName("freq_combox") + self.freq_combox.addItem("") + self.freq_combox.addItem("") + self.freq_combox.addItem("") + self.gridLayout_2.addWidget(self.freq_combox, 0, 1, 1, 1) + self.verticalLayout.addWidget(self.groupBox_2) + self.scrollArea = QtWidgets.QScrollArea(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.scrollArea.sizePolicy().hasHeightForWidth()) + self.scrollArea.setSizePolicy(sizePolicy) + self.scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame) + self.scrollArea.setFrameShadow(QtWidgets.QFrame.Plain) + self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.scrollArea.setWidgetResizable(True) + self.scrollArea.setObjectName("scrollArea") + self.scrollAreaWidgetContents = QtWidgets.QWidget() + self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 388, 713)) + self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") + self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents) + self.verticalLayout_5.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_5.setSpacing(3) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.groupBox_6 = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) + self.groupBox_6.setObjectName("groupBox_6") + self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.groupBox_6) + self.verticalLayout_7.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_7.setSpacing(1) + self.verticalLayout_7.setObjectName("verticalLayout_7") + self.comboBox_7 = QtWidgets.QComboBox(self.groupBox_6) + self.comboBox_7.setObjectName("comboBox_7") + self.comboBox_7.addItem("") + self.comboBox_7.addItem("") + self.comboBox_7.addItem("") + self.verticalLayout_7.addWidget(self.comboBox_7) + self.arr_frame = QtWidgets.QFrame(self.groupBox_6) + self.arr_frame.setObjectName("arr_frame") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.arr_frame) + self.verticalLayout_6.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_6.setSpacing(1) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.verticalLayout_7.addWidget(self.arr_frame) + self.temp_frame = QtWidgets.QFrame(self.groupBox_6) + self.temp_frame.setObjectName("temp_frame") + self.gridLayout = QtWidgets.QGridLayout(self.temp_frame) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setObjectName("gridLayout") + self.lineEdit_3 = QtWidgets.QLineEdit(self.temp_frame) + self.lineEdit_3.setObjectName("lineEdit_3") + self.gridLayout.addWidget(self.lineEdit_3, 0, 1, 1, 1) + self.checkBox = QtWidgets.QCheckBox(self.temp_frame) + self.checkBox.setObjectName("checkBox") + self.gridLayout.addWidget(self.checkBox, 0, 7, 1, 1) + self.label_4 = QtWidgets.QLabel(self.temp_frame) + self.label_4.setObjectName("label_4") + self.gridLayout.addWidget(self.label_4, 0, 2, 1, 1) + self.lineEdit_4 = QtWidgets.QLineEdit(self.temp_frame) + self.lineEdit_4.setObjectName("lineEdit_4") + self.gridLayout.addWidget(self.lineEdit_4, 0, 3, 1, 1) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem, 0, 4, 1, 1) + self.spinBox = QtWidgets.QSpinBox(self.temp_frame) + self.spinBox.setProperty("value", 50) + self.spinBox.setObjectName("spinBox") + self.gridLayout.addWidget(self.spinBox, 0, 5, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem1, 0, 6, 1, 1) + self.verticalLayout_7.addWidget(self.temp_frame) + self.data_frame = QtWidgets.QFrame(self.groupBox_6) + self.data_frame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.data_frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.data_frame.setObjectName("data_frame") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.data_frame) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setSpacing(1) + self.horizontalLayout.setObjectName("horizontalLayout") + self.tau_graph_combobox = QtWidgets.QComboBox(self.data_frame) + self.tau_graph_combobox.setObjectName("tau_graph_combobox") + self.horizontalLayout.addWidget(self.tau_graph_combobox) + self.tau_set_combobox = QtWidgets.QComboBox(self.data_frame) + self.tau_set_combobox.setObjectName("tau_set_combobox") + self.horizontalLayout.addWidget(self.tau_set_combobox) + self.verticalLayout_7.addWidget(self.data_frame) + self.comboBox = QtWidgets.QComboBox(self.groupBox_6) + self.comboBox.setObjectName("comboBox") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.verticalLayout_7.addWidget(self.comboBox) + self.verticalLayout_5.addWidget(self.groupBox_6) + self.groupBox = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) + self.groupBox.setObjectName("groupBox") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox) + self.verticalLayout_2.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_2.setSpacing(0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.specdens_combobox = QtWidgets.QComboBox(self.groupBox) + self.specdens_combobox.setObjectName("specdens_combobox") + self.verticalLayout_2.addWidget(self.specdens_combobox) + self.specdens_frame = QtWidgets.QFrame(self.groupBox) + self.specdens_frame.setObjectName("specdens_frame") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.specdens_frame) + self.verticalLayout_3.setSpacing(0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.verticalLayout_2.addWidget(self.specdens_frame) + self.coupling_combobox = QtWidgets.QComboBox(self.groupBox) + self.coupling_combobox.setObjectName("coupling_combobox") + self.verticalLayout_2.addWidget(self.coupling_combobox) + self.coupling_frame = QtWidgets.QFrame(self.groupBox) + self.coupling_frame.setObjectName("coupling_frame") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.coupling_frame) + self.verticalLayout_4.setContentsMargins(-1, -1, 1, 1) + self.verticalLayout_4.setSpacing(0) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.verticalLayout_2.addWidget(self.coupling_frame) + self.verticalLayout_5.addWidget(self.groupBox) + self.groupBox_3 = QtWidgets.QGroupBox(self.scrollAreaWidgetContents) + self.groupBox_3.setObjectName("groupBox_3") + self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBox_3) + self.gridLayout_4.setContentsMargins(3, 3, 3, 3) + self.gridLayout_4.setSpacing(3) + self.gridLayout_4.setObjectName("gridLayout_4") + self.tau_combox = QtWidgets.QComboBox(self.groupBox_3) + self.tau_combox.setObjectName("tau_combox") + self.tau_combox.addItem("") + self.tau_combox.addItem("") + self.tau_combox.addItem("") + self.tau_combox.addItem("") + self.gridLayout_4.addWidget(self.tau_combox, 0, 0, 1, 2) + self.graph_checkbox = QtWidgets.QCheckBox(self.groupBox_3) + self.graph_checkbox.setChecked(True) + self.graph_checkbox.setObjectName("graph_checkbox") + self.gridLayout_4.addWidget(self.graph_checkbox, 1, 0, 1, 1) + self.graph_combobox = QtWidgets.QComboBox(self.groupBox_3) + self.graph_combobox.setEnabled(True) + self.graph_combobox.setObjectName("graph_combobox") + self.gridLayout_4.addWidget(self.graph_combobox, 1, 1, 1, 1) + self.verticalLayout_5.addWidget(self.groupBox_3) + self.pushButton = QtWidgets.QPushButton(self.scrollAreaWidgetContents) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.pushButton.setFont(font) + self.pushButton.setObjectName("pushButton") + self.verticalLayout_5.addWidget(self.pushButton) + spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_5.addItem(spacerItem2) + self.scrollArea.setWidget(self.scrollAreaWidgetContents) + self.verticalLayout.addWidget(self.scrollArea) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.groupBox_2.setTitle(_translate("Form", "Frequency")) + self.freq_combox.setItemText(0, _translate("Form", "MHz")) + self.freq_combox.setItemText(1, _translate("Form", "kHz")) + self.freq_combox.setItemText(2, _translate("Form", "Hz")) + self.groupBox_6.setTitle(_translate("Form", "Correlation times")) + self.comboBox_7.setItemText(0, _translate("Form", "Arrhenius")) + self.comboBox_7.setItemText(1, _translate("Form", "VFT")) + self.comboBox_7.setItemText(2, _translate("Form", "Data")) + self.lineEdit_3.setPlaceholderText(_translate("Form", "1 K")) + self.checkBox.setText(_translate("Form", "1000/T")) + self.label_4.setText(_translate("Form", "–")) + self.lineEdit_4.setPlaceholderText(_translate("Form", "100 K")) + self.spinBox.setSuffix(_translate("Form", " pts.")) + self.comboBox.setItemText(0, _translate("Form", "Fit parameter: τ")) + self.comboBox.setItemText(1, _translate("Form", "Peak time: τₚ")) + self.comboBox.setItemText(2, _translate("Form", "Arithmetic mean: ⟨τ⟩")) + self.comboBox.setItemText(3, _translate("Form", "Geometric mean: exp(⟨ln τ⟩)")) + self.groupBox.setTitle(_translate("Form", "Model")) + self.groupBox_3.setTitle(_translate("Form", "Result")) + self.tau_combox.setStatusTip(_translate("Form", "NOTE: Mean values are not available for all spectral densities. For more information ask someone.")) + self.tau_combox.setItemText(0, _translate("Form", "Fit parameter: τ")) + self.tau_combox.setItemText(1, _translate("Form", "Peak time: τₚ")) + self.tau_combox.setItemText(2, _translate("Form", "Arithmetic mean: ⟨τ⟩")) + self.tau_combox.setItemText(3, _translate("Form", "Geometric mean: exp(⟨ln τ⟩)")) + self.graph_checkbox.setText(_translate("Form", "New graph?")) + self.pushButton.setText(_translate("Form", "Calculate")) diff --git a/nmreval/gui_qt/_py/t1dialog.py b/nmreval/gui_qt/_py/t1dialog.py new file mode 100644 index 0000000..7f6c421 --- /dev/null +++ b/nmreval/gui_qt/_py/t1dialog.py @@ -0,0 +1,228 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/t1dialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_t1dialog(object): + def setupUi(self, t1dialog): + t1dialog.setObjectName("t1dialog") + t1dialog.resize(316, 741) + self.gridLayout_2 = QtWidgets.QGridLayout(t1dialog) + self.gridLayout_2.setContentsMargins(3, 3, 3, 3) + self.gridLayout_2.setObjectName("gridLayout_2") + self.groupBox_1 = QtWidgets.QGroupBox(t1dialog) + self.groupBox_1.setObjectName("groupBox_1") + self.gridLayout_3 = QtWidgets.QGridLayout(self.groupBox_1) + self.gridLayout_3.setContentsMargins(3, 3, 3, 3) + self.gridLayout_3.setHorizontalSpacing(3) + self.gridLayout_3.setVerticalSpacing(0) + self.gridLayout_3.setObjectName("gridLayout_3") + self.t1_combobox = QtWidgets.QComboBox(self.groupBox_1) + self.t1_combobox.setObjectName("t1_combobox") + self.t1_combobox.addItem("") + self.t1_combobox.addItem("") + self.gridLayout_3.addWidget(self.t1_combobox, 1, 1, 1, 1) + self.temp_combobox = QtWidgets.QComboBox(self.groupBox_1) + self.temp_combobox.setObjectName("temp_combobox") + self.temp_combobox.addItem("") + self.temp_combobox.addItem("") + self.temp_combobox.addItem("") + self.gridLayout_3.addWidget(self.temp_combobox, 1, 0, 1, 1) + self.gridLayout_2.addWidget(self.groupBox_1, 0, 0, 1, 1) + self.groupBox_2 = QtWidgets.QGroupBox(t1dialog) + self.groupBox_2.setObjectName("groupBox_2") + self.gridLayout = QtWidgets.QGridLayout(self.groupBox_2) + self.gridLayout.setContentsMargins(3, 3, 3, 3) + self.gridLayout.setHorizontalSpacing(3) + self.gridLayout.setVerticalSpacing(1) + self.gridLayout.setObjectName("gridLayout") + self.freq_combox = QtWidgets.QComboBox(self.groupBox_2) + self.freq_combox.setObjectName("freq_combox") + self.freq_combox.addItem("") + self.freq_combox.addItem("") + self.freq_combox.addItem("") + self.gridLayout.addWidget(self.freq_combox, 0, 1, 1, 1) + self.freq_spinbox = QtWidgets.QDoubleSpinBox(self.groupBox_2) + self.freq_spinbox.setMaximum(999.99) + self.freq_spinbox.setProperty("value", 100.0) + self.freq_spinbox.setObjectName("freq_spinbox") + self.gridLayout.addWidget(self.freq_spinbox, 0, 0, 1, 1) + self.gridLayout_2.addWidget(self.groupBox_2, 1, 0, 1, 1) + self.groupBox = QtWidgets.QGroupBox(t1dialog) + self.groupBox.setObjectName("groupBox") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox) + self.verticalLayout_2.setContentsMargins(3, 3, 3, -1) + self.verticalLayout_2.setSpacing(2) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.specdens_combobox = QtWidgets.QComboBox(self.groupBox) + self.specdens_combobox.setObjectName("specdens_combobox") + self.verticalLayout_2.addWidget(self.specdens_combobox) + self.sd_frame = QtWidgets.QFrame(self.groupBox) + self.sd_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.sd_frame.setFrameShadow(QtWidgets.QFrame.Sunken) + self.sd_frame.setObjectName("sd_frame") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.sd_frame) + self.verticalLayout_3.setContentsMargins(1, 1, 1, 1) + self.verticalLayout_3.setSpacing(0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.verticalLayout_2.addWidget(self.sd_frame) + self.coupling_combobox = QtWidgets.QComboBox(self.groupBox) + self.coupling_combobox.setObjectName("coupling_combobox") + self.verticalLayout_2.addWidget(self.coupling_combobox) + self.cp_frame = QtWidgets.QFrame(self.groupBox) + self.cp_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.cp_frame.setFrameShadow(QtWidgets.QFrame.Sunken) + self.cp_frame.setObjectName("cp_frame") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.cp_frame) + self.verticalLayout_4.setContentsMargins(1, 1, 1, 1) + self.verticalLayout_4.setSpacing(0) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.verticalLayout_2.addWidget(self.cp_frame) + self.gridLayout_2.addWidget(self.groupBox, 3, 0, 1, 1) + self.groupBox_5 = QtWidgets.QGroupBox(t1dialog) + self.groupBox_5.setObjectName("groupBox_5") + self.gridLayout_5 = QtWidgets.QGridLayout(self.groupBox_5) + self.gridLayout_5.setContentsMargins(3, 3, 3, 3) + self.gridLayout_5.setHorizontalSpacing(2) + self.gridLayout_5.setObjectName("gridLayout_5") + self.interpol_combobox = QtWidgets.QComboBox(self.groupBox_5) + self.interpol_combobox.setObjectName("interpol_combobox") + self.interpol_combobox.addItem("") + self.interpol_combobox.addItem("") + self.interpol_combobox.addItem("") + self.interpol_combobox.addItem("") + self.gridLayout_5.addWidget(self.interpol_combobox, 0, 0, 1, 1) + self.frame = QtWidgets.QFrame(self.groupBox_5) + self.frame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame.setFrameShadow(QtWidgets.QFrame.Plain) + self.frame.setObjectName("frame") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label_9 = QtWidgets.QLabel(self.frame) + self.label_9.setObjectName("label_9") + self.horizontalLayout.addWidget(self.label_9) + self.lineEdit_2 = QtWidgets.QLineEdit(self.frame) + self.lineEdit_2.setObjectName("lineEdit_2") + self.horizontalLayout.addWidget(self.lineEdit_2) + self.label_10 = QtWidgets.QLabel(self.frame) + self.label_10.setObjectName("label_10") + self.horizontalLayout.addWidget(self.label_10) + self.lineEdit_3 = QtWidgets.QLineEdit(self.frame) + self.lineEdit_3.setObjectName("lineEdit_3") + self.horizontalLayout.addWidget(self.lineEdit_3) + self.gridLayout_5.addWidget(self.frame, 1, 0, 1, 2) + self.frame_2 = QtWidgets.QFrame(self.groupBox_5) + self.frame_2.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame_2.setFrameShadow(QtWidgets.QFrame.Plain) + self.frame_2.setObjectName("frame_2") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame_2) + self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label_11 = QtWidgets.QLabel(self.frame_2) + self.label_11.setObjectName("label_11") + self.horizontalLayout_2.addWidget(self.label_11) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem) + self.label_13 = QtWidgets.QLabel(self.frame_2) + self.label_13.setObjectName("label_13") + self.horizontalLayout_2.addWidget(self.label_13) + self.label_12 = QtWidgets.QLabel(self.frame_2) + self.label_12.setObjectName("label_12") + self.horizontalLayout_2.addWidget(self.label_12) + self.gridLayout_5.addWidget(self.frame_2, 2, 0, 1, 2) + self.t1min_toolButton = QtWidgets.QToolButton(self.groupBox_5) + self.t1min_toolButton.setObjectName("t1min_toolButton") + self.gridLayout_5.addWidget(self.t1min_toolButton, 0, 1, 1, 1) + self.gridLayout_2.addWidget(self.groupBox_5, 2, 0, 1, 1) + self.groupBox_3 = QtWidgets.QGroupBox(t1dialog) + self.groupBox_3.setObjectName("groupBox_3") + self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBox_3) + self.gridLayout_4.setContentsMargins(3, 3, 3, 3) + self.gridLayout_4.setSpacing(3) + self.gridLayout_4.setObjectName("gridLayout_4") + self.graph_combobox = QtWidgets.QComboBox(self.groupBox_3) + self.graph_combobox.setEnabled(False) + self.graph_combobox.setObjectName("graph_combobox") + self.gridLayout_4.addWidget(self.graph_combobox, 3, 1, 1, 1) + self.tau_combox = QtWidgets.QComboBox(self.groupBox_3) + self.tau_combox.setObjectName("tau_combox") + self.tau_combox.addItem("") + self.tau_combox.addItem("") + self.tau_combox.addItem("") + self.tau_combox.addItem("") + self.gridLayout_4.addWidget(self.tau_combox, 1, 0, 1, 2) + self.checkBox_interpol = QtWidgets.QCheckBox(self.groupBox_3) + self.checkBox_interpol.setObjectName("checkBox_interpol") + self.gridLayout_4.addWidget(self.checkBox_interpol, 2, 0, 1, 2) + self.graph_checkbox = QtWidgets.QCheckBox(self.groupBox_3) + self.graph_checkbox.setChecked(True) + self.graph_checkbox.setObjectName("graph_checkbox") + self.gridLayout_4.addWidget(self.graph_checkbox, 3, 0, 1, 1) + self.label = QtWidgets.QLabel(self.groupBox_3) + self.label.setObjectName("label") + self.gridLayout_4.addWidget(self.label, 0, 0, 1, 1) + self.label_t1min = QtWidgets.QLabel(self.groupBox_3) + self.label_t1min.setText("") + self.label_t1min.setObjectName("label_t1min") + self.gridLayout_4.addWidget(self.label_t1min, 0, 1, 1, 1) + self.gridLayout_2.addWidget(self.groupBox_3, 4, 0, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(17, 19, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_2.addItem(spacerItem1, 6, 0, 1, 1) + self.calc_pushButton = QtWidgets.QPushButton(t1dialog) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.calc_pushButton.setFont(font) + self.calc_pushButton.setObjectName("calc_pushButton") + self.gridLayout_2.addWidget(self.calc_pushButton, 5, 0, 1, 1) + self.label_9.setBuddy(self.lineEdit_2) + self.label_10.setBuddy(self.lineEdit_3) + + self.retranslateUi(t1dialog) + QtCore.QMetaObject.connectSlotsByName(t1dialog) + + def retranslateUi(self, t1dialog): + _translate = QtCore.QCoreApplication.translate + t1dialog.setWindowTitle(_translate("t1dialog", "Form")) + self.groupBox_1.setTitle(_translate("t1dialog", "Axes")) + self.t1_combobox.setItemText(0, _translate("t1dialog", "T1")) + self.t1_combobox.setItemText(1, _translate("t1dialog", "1/T1")) + self.temp_combobox.setItemText(0, _translate("t1dialog", "1000/T")) + self.temp_combobox.setItemText(1, _translate("t1dialog", "T")) + self.temp_combobox.setItemText(2, _translate("t1dialog", "1/T")) + self.groupBox_2.setTitle(_translate("t1dialog", "Frequency")) + self.freq_combox.setItemText(0, _translate("t1dialog", "MHz")) + self.freq_combox.setItemText(1, _translate("t1dialog", "kHz")) + self.freq_combox.setItemText(2, _translate("t1dialog", "Hz")) + self.groupBox.setTitle(_translate("t1dialog", "Model")) + self.groupBox_5.setTitle(_translate("t1dialog", "Pick T1 minimon")) + self.interpol_combobox.setItemText(0, _translate("t1dialog", "Data minimum")) + self.interpol_combobox.setItemText(1, _translate("t1dialog", "Parabola")) + self.interpol_combobox.setItemText(2, _translate("t1dialog", "Cubic spline")) + self.interpol_combobox.setItemText(3, _translate("t1dialog", "Akima spline")) + self.label_9.setText(_translate("t1dialog", "Interpolate")) + self.lineEdit_2.setPlaceholderText(_translate("t1dialog", "1 K")) + self.label_10.setText(_translate("t1dialog", "--")) + self.lineEdit_3.setPlaceholderText(_translate("t1dialog", "2000 K")) + self.label_11.setText(_translate("t1dialog", "Minimon")) + self.label_13.setText(_translate("t1dialog", "x value")) + self.label_12.setText(_translate("t1dialog", "y value")) + self.t1min_toolButton.setText(_translate("t1dialog", "Set")) + self.groupBox_3.setTitle(_translate("t1dialog", "Result")) + self.tau_combox.setStatusTip(_translate("t1dialog", "NOTE: Mean values are not available for all spectral densities. For more information ask someone.")) + self.tau_combox.setItemText(0, _translate("t1dialog", "Fit parameter: τ")) + self.tau_combox.setItemText(1, _translate("t1dialog", "Peak time: τₚ")) + self.tau_combox.setItemText(2, _translate("t1dialog", "Arithmetic mean: ⟨τ⟩")) + self.tau_combox.setItemText(3, _translate("t1dialog", "Geometric mean: exp(⟨ln τ⟩)")) + self.checkBox_interpol.setText(_translate("t1dialog", "Use minimon interpolation")) + self.graph_checkbox.setText(_translate("t1dialog", "New graph?")) + self.label.setText(_translate("t1dialog", "Calculated minimon")) + self.calc_pushButton.setText(_translate("t1dialog", "Calculate")) diff --git a/nmreval/gui_qt/_py/tntdialog.py b/nmreval/gui_qt/_py/tntdialog.py new file mode 100644 index 0000000..d3754ec --- /dev/null +++ b/nmreval/gui_qt/_py/tntdialog.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/tntdialog.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_tntdialog(object): + def setupUi(self, tntdialog): + tntdialog.setObjectName("tntdialog") + tntdialog.resize(373, 482) + self.gridLayout = QtWidgets.QGridLayout(tntdialog) + self.gridLayout.setObjectName("gridLayout") + self.widget_3 = QDelayWidget(tntdialog) + self.widget_3.setObjectName("widget_3") + self.gridLayout.addWidget(self.widget_3, 3, 1, 1, 2) + self.label_3 = QtWidgets.QLabel(tntdialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth()) + self.label_3.setSizePolicy(sizePolicy) + self.label_3.setObjectName("label_3") + self.gridLayout.addWidget(self.label_3, 0, 2, 1, 1) + self.widget = QDelayWidget(tntdialog) + self.widget.setObjectName("widget") + self.gridLayout.addWidget(self.widget, 1, 1, 1, 2) + self.label_2 = QtWidgets.QLabel(tntdialog) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 0, 1, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem, 6, 1, 1, 1) + self.widget_2 = QDelayWidget(tntdialog) + self.widget_2.setObjectName("widget_2") + self.gridLayout.addWidget(self.widget_2, 2, 1, 1, 2) + self.buttonBox = QtWidgets.QDialogButtonBox(tntdialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 9, 1, 1, 2) + self.frame = QtWidgets.QFrame(tntdialog) + self.frame.setObjectName("frame") + self.gridLayout_2 = QtWidgets.QGridLayout(self.frame) + self.gridLayout_2.setContentsMargins(0, 0, 0, 0) + self.gridLayout_2.setSpacing(0) + self.gridLayout_2.setObjectName("gridLayout_2") + self.checkBox_2 = QtWidgets.QCheckBox(self.frame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.checkBox_2.sizePolicy().hasHeightForWidth()) + self.checkBox_2.setSizePolicy(sizePolicy) + self.checkBox_2.setObjectName("checkBox_2") + self.gridLayout_2.addWidget(self.checkBox_2, 3, 0, 1, 1) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label_5 = QtWidgets.QLabel(self.frame) + self.label_5.setObjectName("label_5") + self.horizontalLayout_2.addWidget(self.label_5) + self.start_lineedit = QtWidgets.QLineEdit(self.frame) + self.start_lineedit.setObjectName("start_lineedit") + self.horizontalLayout_2.addWidget(self.start_lineedit) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem1) + self.label_6 = QtWidgets.QLabel(self.frame) + self.label_6.setObjectName("label_6") + self.horizontalLayout_2.addWidget(self.label_6) + self.end_lineedit = QtWidgets.QLineEdit(self.frame) + self.end_lineedit.setFrame(True) + self.end_lineedit.setObjectName("end_lineedit") + self.horizontalLayout_2.addWidget(self.end_lineedit) + self.gridLayout_2.addLayout(self.horizontalLayout_2, 1, 0, 1, 2) + self.label = QtWidgets.QLabel(self.frame) + self.label.setObjectName("label") + self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1) + self.lineEdit = QtWidgets.QLineEdit(self.frame) + self.lineEdit.setObjectName("lineEdit") + self.gridLayout_2.addWidget(self.lineEdit, 0, 1, 1, 1) + self.spinBox = QtWidgets.QSpinBox(self.frame) + self.spinBox.setObjectName("spinBox") + self.gridLayout_2.addWidget(self.spinBox, 3, 1, 1, 1) + self.checkBox = QtWidgets.QCheckBox(self.frame) + self.checkBox.setLayoutDirection(QtCore.Qt.LeftToRight) + self.checkBox.setObjectName("checkBox") + self.gridLayout_2.addWidget(self.checkBox, 4, 0, 1, 1) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setContentsMargins(25, -1, -1, -1) + self.horizontalLayout.setSpacing(0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.pushButton = QtWidgets.QPushButton(self.frame) + self.pushButton.setObjectName("pushButton") + self.horizontalLayout.addWidget(self.pushButton) + self.pushButton_2 = QtWidgets.QPushButton(self.frame) + self.pushButton_2.setObjectName("pushButton_2") + self.horizontalLayout.addWidget(self.pushButton_2) + self.gridLayout_2.addLayout(self.horizontalLayout, 4, 1, 1, 1) + self.gridLayout.addWidget(self.frame, 8, 1, 1, 2) + self.frame_2 = QtWidgets.QFrame(tntdialog) + self.frame_2.setObjectName("frame_2") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.frame_2) + self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.label_4 = QtWidgets.QLabel(self.frame_2) + self.label_4.setObjectName("label_4") + self.horizontalLayout_3.addWidget(self.label_4) + self.unknown_delay_combobox = QtWidgets.QComboBox(self.frame_2) + self.unknown_delay_combobox.setObjectName("unknown_delay_combobox") + self.horizontalLayout_3.addWidget(self.unknown_delay_combobox) + self.gridLayout.addWidget(self.frame_2, 4, 1, 1, 2) + + self.retranslateUi(tntdialog) + self.buttonBox.accepted.connect(tntdialog.accept) + self.buttonBox.rejected.connect(tntdialog.reject) + QtCore.QMetaObject.connectSlotsByName(tntdialog) + + def retranslateUi(self, tntdialog): + _translate = QtCore.QCoreApplication.translate + tntdialog.setWindowTitle(_translate("tntdialog", "Read tnt file")) + self.label_3.setText(_translate("tntdialog", "TextLabel")) + self.label_2.setText(_translate("tntdialog", "Dimensions")) + self.checkBox_2.setText(_translate("tntdialog", "Staggered range")) + self.label_5.setText(_translate("tntdialog", "Start")) + self.start_lineedit.setPlaceholderText(_translate("tntdialog", "0")) + self.label_6.setText(_translate("tntdialog", "End")) + self.end_lineedit.setPlaceholderText(_translate("tntdialog", "1")) + self.label.setText(_translate("tntdialog", "Name")) + self.checkBox.setToolTip(_translate("tntdialog", "NOTE: There is no inspection if start and end are valid values.")) + self.checkBox.setText(_translate("tntdialog", "Logarithmic scale")) + self.pushButton.setText(_translate("tntdialog", "Apply")) + self.pushButton_2.setText(_translate("tntdialog", "Cancel")) + self.label_4.setText(_translate("tntdialog", "Unassigned lists")) +from widgets.subwidgets import QDelayWidget diff --git a/nmreval/gui_qt/_py/typeconversion.py b/nmreval/gui_qt/_py/typeconversion.py new file mode 100644 index 0000000..fcfa751 --- /dev/null +++ b/nmreval/gui_qt/_py/typeconversion.py @@ -0,0 +1,139 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/typeconversion.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(839, 502) + self.verticalLayout_2 = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout_2.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_2.setSpacing(3) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.label_4 = QtWidgets.QLabel(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4.setSizePolicy(sizePolicy) + self.label_4.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.label_4.setObjectName("label_4") + self.verticalLayout_2.addWidget(self.label_4) + self.splitter = QtWidgets.QSplitter(Dialog) + self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setObjectName("splitter") + self.set_list = QtWidgets.QListWidget(self.splitter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.set_list.sizePolicy().hasHeightForWidth()) + self.set_list.setSizePolicy(sizePolicy) + self.set_list.setDragEnabled(True) + self.set_list.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly) + self.set_list.setObjectName("set_list") + self.verticalLayoutWidget = QtWidgets.QWidget(self.splitter) + self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") + self.gridLayout = QtWidgets.QGridLayout(self.verticalLayoutWidget) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setHorizontalSpacing(0) + self.gridLayout.setVerticalSpacing(2) + self.gridLayout.setObjectName("gridLayout") + self.simple_button = QtWidgets.QRadioButton(self.verticalLayoutWidget) + self.simple_button.setChecked(True) + self.simple_button.setObjectName("simple_button") + self.buttonGroup = QtWidgets.QButtonGroup(Dialog) + self.buttonGroup.setObjectName("buttonGroup") + self.buttonGroup.addButton(self.simple_button) + self.gridLayout.addWidget(self.simple_button, 0, 0, 1, 1) + self.merge_button = QtWidgets.QRadioButton(self.verticalLayoutWidget) + self.merge_button.setObjectName("merge_button") + self.buttonGroup.addButton(self.merge_button) + self.gridLayout.addWidget(self.merge_button, 0, 1, 1, 1) + self.stackedWidget = QtWidgets.QStackedWidget(self.verticalLayoutWidget) + self.stackedWidget.setObjectName("stackedWidget") + self.page_1 = QtWidgets.QWidget() + self.page_1.setObjectName("page_1") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.page_1) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_3.setSpacing(0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.simple_table = QtWidgets.QTableWidget(self.page_1) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.simple_table.sizePolicy().hasHeightForWidth()) + self.simple_table.setSizePolicy(sizePolicy) + self.simple_table.setDragDropMode(QtWidgets.QAbstractItemView.DropOnly) + self.simple_table.setObjectName("simple_table") + self.simple_table.setColumnCount(2) + self.simple_table.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + self.simple_table.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.simple_table.setHorizontalHeaderItem(1, item) + self.simple_table.horizontalHeader().setStretchLastSection(True) + self.verticalLayout_3.addWidget(self.simple_table) + self.stackedWidget.addWidget(self.page_1) + self.page_2 = QtWidgets.QWidget() + self.page_2.setObjectName("page_2") + self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.page_2) + self.verticalLayout_5.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_5.setSpacing(0) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.merge_table = QtWidgets.QTableWidget(self.page_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.merge_table.sizePolicy().hasHeightForWidth()) + self.merge_table.setSizePolicy(sizePolicy) + self.merge_table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.merge_table.setDragDropMode(QtWidgets.QAbstractItemView.DropOnly) + self.merge_table.setDefaultDropAction(QtCore.Qt.CopyAction) + self.merge_table.setObjectName("merge_table") + self.merge_table.setColumnCount(3) + self.merge_table.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + self.merge_table.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.merge_table.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + self.merge_table.setHorizontalHeaderItem(2, item) + self.merge_table.horizontalHeader().setStretchLastSection(True) + self.verticalLayout_5.addWidget(self.merge_table) + self.stackedWidget.addWidget(self.page_2) + self.gridLayout.addWidget(self.stackedWidget, 1, 0, 1, 2) + self.verticalLayout_2.addWidget(self.splitter) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout_2.addWidget(self.buttonBox) + + self.retranslateUi(Dialog) + self.stackedWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Change type")) + self.label_4.setText(_translate("Dialog", "Drag & drop datasets and select new type.")) + self.simple_button.setText(_translate("Dialog", "Simple conversion")) + self.merge_button.setText(_translate("Dialog", "Merge to complex set")) + item = self.simple_table.horizontalHeaderItem(0) + item.setText(_translate("Dialog", "Set")) + item = self.simple_table.horizontalHeaderItem(1) + item.setText(_translate("Dialog", "Type")) + item = self.merge_table.horizontalHeaderItem(0) + item.setText(_translate("Dialog", "Real")) + item = self.merge_table.horizontalHeaderItem(1) + item.setText(_translate("Dialog", "Imag")) + item = self.merge_table.horizontalHeaderItem(2) + item.setText(_translate("Dialog", "Type")) diff --git a/nmreval/gui_qt/_py/untitled.py b/nmreval/gui_qt/_py/untitled.py new file mode 100644 index 0000000..4b991d4 --- /dev/null +++ b/nmreval/gui_qt/_py/untitled.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/untitled.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(800, 600) + self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.toolButton = QtWidgets.QToolButton(self.centralwidget) + self.toolButton.setGeometry(QtCore.QRect(0, 0, 31, 34)) + self.toolButton.setObjectName("toolButton") + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 30)) + self.menubar.setObjectName("menubar") + self.menuDfgdfg = QtWidgets.QMenu(self.menubar) + self.menuDfgdfg.setObjectName("menuDfgdfg") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.toolBar = QtWidgets.QToolBar(MainWindow) + self.toolBar.setObjectName("toolBar") + MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) + self.actionAsdasd = QtWidgets.QAction(MainWindow) + self.actionAsdasd.setObjectName("actionAsdasd") + self.menuDfgdfg.addAction(self.actionAsdasd) + self.menubar.addAction(self.menuDfgdfg.menuAction()) + self.toolBar.addSeparator() + + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + self.toolButton.setText(_translate("MainWindow", "...")) + self.menuDfgdfg.setTitle(_translate("MainWindow", "dfgdfg")) + self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar")) + self.actionAsdasd.setText(_translate("MainWindow", "asdasd")) diff --git a/nmreval/gui_qt/_py/userfitassist.py b/nmreval/gui_qt/_py/userfitassist.py new file mode 100644 index 0000000..c587927 --- /dev/null +++ b/nmreval/gui_qt/_py/userfitassist.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/userfitassist.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(675, 682) + self.verticalLayout = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout.setObjectName("verticalLayout") + self.label_3 = QtWidgets.QLabel(Dialog) + self.label_3.setIndent(4) + self.label_3.setObjectName("label_3") + self.verticalLayout.addWidget(self.label_3) + self.lineEdit_2 = QtWidgets.QLineEdit(Dialog) + self.lineEdit_2.setObjectName("lineEdit_2") + self.verticalLayout.addWidget(self.lineEdit_2) + self.label_4 = QtWidgets.QLabel(Dialog) + self.label_4.setIndent(4) + self.label_4.setObjectName("label_4") + self.verticalLayout.addWidget(self.label_4) + self.lineEdit_3 = QtWidgets.QLineEdit(Dialog) + self.lineEdit_3.setObjectName("lineEdit_3") + self.verticalLayout.addWidget(self.lineEdit_3) + self.label_2 = QtWidgets.QLabel(Dialog) + self.label_2.setIndent(4) + self.label_2.setObjectName("label_2") + self.verticalLayout.addWidget(self.label_2) + self.lineEdit = QtWidgets.QLineEdit(Dialog) + self.lineEdit.setText("") + self.lineEdit.setObjectName("lineEdit") + self.verticalLayout.addWidget(self.lineEdit) + self.parameterLabel = QtWidgets.QLabel(Dialog) + self.parameterLabel.setIndent(4) + self.parameterLabel.setObjectName("parameterLabel") + self.verticalLayout.addWidget(self.parameterLabel) + self.parameterLineEdit = QtWidgets.QLineEdit(Dialog) + self.parameterLineEdit.setObjectName("parameterLineEdit") + self.verticalLayout.addWidget(self.parameterLineEdit) + self.checkBox = QtWidgets.QCheckBox(Dialog) + self.checkBox.setObjectName("checkBox") + self.verticalLayout.addWidget(self.checkBox) + self.externalParametersLineEdit = QtWidgets.QLineEdit(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.externalParametersLineEdit.sizePolicy().hasHeightForWidth()) + self.externalParametersLineEdit.setSizePolicy(sizePolicy) + self.externalParametersLineEdit.setObjectName("externalParametersLineEdit") + self.verticalLayout.addWidget(self.externalParametersLineEdit) + self.checkBox_2 = QtWidgets.QCheckBox(Dialog) + self.checkBox_2.setObjectName("checkBox_2") + self.verticalLayout.addWidget(self.checkBox_2) + self.tableWidget = QtWidgets.QTableWidget(Dialog) + self.tableWidget.setObjectName("tableWidget") + self.tableWidget.setColumnCount(0) + self.tableWidget.setRowCount(0) + self.verticalLayout.addWidget(self.tableWidget) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Save) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + self.label_3.setBuddy(self.lineEdit_2) + self.label_4.setBuddy(self.lineEdit_3) + self.label_2.setBuddy(self.lineEdit) + self.parameterLabel.setBuddy(self.parameterLineEdit) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Dialog")) + self.label_3.setText(_translate("Dialog", "Name")) + self.lineEdit_2.setPlaceholderText(_translate("Dialog", "Name of function, e.g. Hopperbagger")) + self.label_4.setText(_translate("Dialog", "Group")) + self.lineEdit_3.setPlaceholderText(_translate("Dialog", "Type of function, e.g., Relaxation, Diffusion, Dredge,...")) + self.label_2.setText(_translate("Dialog", "Equation")) + self.lineEdit.setPlaceholderText(_translate("Dialog", "\\alpha + B*exp(x*C_{33}) + D")) + self.parameterLabel.setText(_translate("Dialog", "Parameters")) + self.parameterLineEdit.setPlaceholderText(_translate("Dialog", "\\alpha B C_{33}")) + self.checkBox.setText(_translate("Dialog", "Fixed parameter")) + self.externalParametersLineEdit.setPlaceholderText(_translate("Dialog", "D")) + self.checkBox_2.setText(_translate("Dialog", "Selection")) + self.buttonBox.setToolTip(_translate("Dialog", "Fit model is saved in myfitmodels.py and ready to use without restart.")) diff --git a/nmreval/gui_qt/_py/usermodeleditor.py b/nmreval/gui_qt/_py/usermodeleditor.py new file mode 100644 index 0000000..5858c0b --- /dev/null +++ b/nmreval/gui_qt/_py/usermodeleditor.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/usermodeleditor.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(800, 600) + self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) + self.verticalLayout.setContentsMargins(3, 3, 3, 3) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.edit_field = CodeEditor(self.centralwidget) + font = QtGui.QFont() + font.setPointSize(10) + self.edit_field.setFont(font) + self.edit_field.setObjectName("edit_field") + self.verticalLayout.addWidget(self.edit_field) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 30)) + self.menubar.setObjectName("menubar") + self.menuFile = QtWidgets.QMenu(self.menubar) + self.menuFile.setObjectName("menuFile") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.actionOpen = QtWidgets.QAction(MainWindow) + self.actionOpen.setObjectName("actionOpen") + self.actionSave = QtWidgets.QAction(MainWindow) + self.actionSave.setObjectName("actionSave") + self.actionSave_as = QtWidgets.QAction(MainWindow) + self.actionSave_as.setObjectName("actionSave_as") + self.actionClose = QtWidgets.QAction(MainWindow) + self.actionClose.setObjectName("actionClose") + self.menuFile.addAction(self.actionOpen) + self.menuFile.addAction(self.actionSave) + self.menuFile.addAction(self.actionSave_as) + self.menuFile.addAction(self.actionClose) + self.menubar.addAction(self.menuFile.menuAction()) + + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "Editor")) + self.menuFile.setTitle(_translate("MainWindow", "File")) + self.actionOpen.setText(_translate("MainWindow", "Open...")) + self.actionSave.setText(_translate("MainWindow", "Save")) + self.actionSave_as.setText(_translate("MainWindow", "Save as...")) + self.actionClose.setText(_translate("MainWindow", "Close")) +from ..lib.codeeditor import CodeEditor diff --git a/nmreval/gui_qt/_py/valueeditor.py b/nmreval/gui_qt/_py/valueeditor.py new file mode 100644 index 0000000..bfab40a --- /dev/null +++ b/nmreval/gui_qt/_py/valueeditor.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'resources/_ui/valueeditor.ui' +# +# Created by: PyQt5 UI code generator 5.12.3 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_MaskDialog(object): + def setupUi(self, MaskDialog): + MaskDialog.setObjectName("MaskDialog") + MaskDialog.resize(383, 645) + self.verticalLayout = QtWidgets.QVBoxLayout(MaskDialog) + self.verticalLayout.setContentsMargins(3, 3, 3, 3) + self.verticalLayout.setSpacing(3) + self.verticalLayout.setObjectName("verticalLayout") + self.comboBox = QtWidgets.QComboBox(MaskDialog) + self.comboBox.setObjectName("comboBox") + self.verticalLayout.addWidget(self.comboBox) + self.comboBox_2 = QtWidgets.QComboBox(MaskDialog) + self.comboBox_2.setObjectName("comboBox_2") + self.verticalLayout.addWidget(self.comboBox_2) + self.tableView = QtWidgets.QTableView(MaskDialog) + self.tableView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableView.setObjectName("tableView") + self.verticalLayout.addWidget(self.tableView) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(MaskDialog) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.spinBox = QtWidgets.QSpinBox(MaskDialog) + self.spinBox.setMinimum(1) + self.spinBox.setObjectName("spinBox") + self.horizontalLayout.addWidget(self.spinBox) + self.toolButton = QtWidgets.QToolButton(MaskDialog) + self.toolButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + self.toolButton.setAutoRaise(True) + self.toolButton.setArrowType(QtCore.Qt.RightArrow) + self.toolButton.setObjectName("toolButton") + self.horizontalLayout.addWidget(self.toolButton) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.verticalLayout.addLayout(self.horizontalLayout) + self.gridLayout = QtWidgets.QGridLayout() + self.gridLayout.setContentsMargins(-1, 0, -1, -1) + self.gridLayout.setSpacing(3) + self.gridLayout.setObjectName("gridLayout") + self.unmaskbutton = QtWidgets.QPushButton(MaskDialog) + self.unmaskbutton.setObjectName("unmaskbutton") + self.gridLayout.addWidget(self.unmaskbutton, 1, 0, 1, 1) + self.delete_button = QtWidgets.QPushButton(MaskDialog) + icon = QtGui.QIcon.fromTheme("list-remove") + self.delete_button.setIcon(icon) + self.delete_button.setObjectName("delete_button") + self.gridLayout.addWidget(self.delete_button, 0, 1, 1, 1) + self.add_button = QtWidgets.QPushButton(MaskDialog) + icon = QtGui.QIcon.fromTheme("list-add") + self.add_button.setIcon(icon) + self.add_button.setObjectName("add_button") + self.gridLayout.addWidget(self.add_button, 0, 0, 1, 1) + self.mask_button = QtWidgets.QPushButton(MaskDialog) + self.mask_button.setObjectName("mask_button") + self.gridLayout.addWidget(self.mask_button, 1, 1, 1, 1) + self.verticalLayout.addLayout(self.gridLayout) + self.label.setBuddy(self.spinBox) + + self.retranslateUi(MaskDialog) + QtCore.QMetaObject.connectSlotsByName(MaskDialog) + + def retranslateUi(self, MaskDialog): + _translate = QtCore.QCoreApplication.translate + MaskDialog.setWindowTitle(_translate("MaskDialog", "Form")) + self.label.setText(_translate("MaskDialog", "Go to line:")) + self.toolButton.setText(_translate("MaskDialog", "Go Go Power Rangers!")) + self.unmaskbutton.setText(_translate("MaskDialog", "Show all")) + self.delete_button.setText(_translate("MaskDialog", "Delete rows")) + self.add_button.setText(_translate("MaskDialog", "Add row")) + self.mask_button.setToolTip(_translate("MaskDialog", "

Masked rows are shown in green

")) + self.mask_button.setText(_translate("MaskDialog", "Hide/Show selected")) diff --git a/nmreval/gui_qt/data/__init__.py b/nmreval/gui_qt/data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nmreval/gui_qt/data/container.py b/nmreval/gui_qt/data/container.py new file mode 100644 index 0000000..7027698 --- /dev/null +++ b/nmreval/gui_qt/data/container.py @@ -0,0 +1,651 @@ +from collections import OrderedDict +from itertools import cycle +from typing import Any + +import numpy as np +from pyqtgraph import mkPen + +from ...data.points import Points +from ...data.signals import Signal +from ...utils.text import convert +from ...data.bds import BDS +from ...lib.colors import Colors +from ...lib.lines import LineStyle +from ...lib.symbols import SymbolStyle, symbolcycle +from ...data.nmr import Spectrum, FID + +from ..Qt import QtCore +from ..io.exporters import pgitem_to_dic +from ..lib.decorators import plot_update +from ..lib.pg_objects import ErrorBars, PlotItem + + +class ExperimentContainer(QtCore.QObject): + dataChanged = QtCore.pyqtSignal(str) + labelChanged = QtCore.pyqtSignal(str, str) + groupChanged = QtCore.pyqtSignal(str, str) + colors = cycle(Colors) + + def __init__(self, identifier, data, **kwargs): + super().__init__() + self.id = str(identifier) + + self._fits = [] + self._data = data + self._manager = kwargs.get('manager') + + self.mode = 'point' + self.plot_real = None + self.plot_imag = None + self.plot_error = None + + self.actions = {} + self._update_actions() + + def _init_plot(self): + raise NotImplementedError + + def __getitem__(self, item): + try: + return self._data[item] + except KeyError: + raise KeyError('Unknown key %s' % str(item)) + + def __del__(self): + del self._data + del self.plot_real + del self.plot_imag + del self.plot_error + + def __repr__(self): + return 'name:' + self.name + + def __len__(self): + return len(self._data) + + def copy(self, full: bool = False): + if full: + new_data = type(self)(str(self.id), self._data.copy(), manager=self._manager) + new_data.mode = self.mode + + for src, dest in [(self.plot_real, new_data.plot_real), (self.plot_imag, new_data.plot_imag)]: + if src is not None: + dest.set_symbol(symbol=src.symbol, size=src.symbolsize, color=src.symbolcolor) + dest.set_line(style=src.linestyle, width=src.linewidth, color=src.linecolor) + + return new_data + + else: + return self._data.copy() + + def change_type(self, data): + if isinstance(data, (FID, Spectrum, BDS)): + new_type = SignalContainer + elif isinstance(data, Points): + new_type = PointContainer + else: + raise TypeError('Unknown data type') + + new_data = new_type(str(self.id), data, manager=self._manager) + + for src, dest in [(self.plot_real, new_data.plot_real), (self.plot_imag, new_data.plot_imag)]: + if dest is not None: + if src is not None: + dest.set_symbol(symbol=src.symbol, size=src.symbolsize, color=src.symbolcolor) + dest.set_line(style=src.linestyle, width=src.linewidth, color=src.linecolor) + else: + dest.set_symbol(symbol=self.plot_real.symbol, size=self.plot_real.symbolsize, color=self.plot_real.symbolcolor) + dest.set_line(style=self.plot_real.linestyle, width=self.plot_real.linewidth, color=self.plot_real.linecolor) + + return new_data + + @property + def x(self): + return self._data.x[self._data.mask] + + @x.setter + @plot_update + def x(self, value): + if len(self._data.x) == len(value): + self._data.x = value + elif len(self._data.x[self._data.mask]) == len(value): + self._data.x = value + self._data.y = self._data.y[self._data.mask] + self._data.mask = np.ma.array(np.ones_like(self._data.x, dtype=bool)) + else: + raise ValueError('x and y have different dimensions!') + + @property + def y(self): + return self._data.y[self._data.mask] + + @y.setter + @plot_update + def y(self, value): + if len(self._data.y) == len(value): + self._data.y = value + elif len(self._data.y[self._data.mask]) == len(value): + self._data.y = value + self._data.x = self._data.x[self._data.mask] + self._data.mask = np.ma.array(np.ones_like(self._data.y, dtype=bool)) + else: + raise ValueError('x and y have different dimensions!') + + @property + def y_err(self): + return self._data.y_err[self._data.mask] + + @y_err.setter + @plot_update + def y_err(self, value): + if len(self._data.y_err) == len(value): + self._data.y_err = value + elif len(self._data.y[self._data.mask]) == len(value): + self._data.y_err[self._data.mask] = value + else: + raise ValueError('y_err has not correct length') + + @property + def name(self): + return self._data.name + + @name.setter + @plot_update + def name(self, value: str): + self._data.name = value + self.plot_real.opts['name'] = value + try: + self.plot_imag.opts['name'] = value + except AttributeError: + pass + try: + num_val = float(value) + self._data.value = num_val + except ValueError: + pass + + @property + def value(self): + return self._data.value + + @value.setter + def value(self, val): + self._data.value = float(val) + + @property + def group(self): + return str(self._data['group']) + + @group.setter + def group(self, valium): + self._data['group'] = str(valium) + self.groupChanged.emit(self.id, str(valium)) + + @property + def data(self): + return self._data + + @data.setter + @plot_update + def data(self, new_data): + self._data = new_data + self._update_actions() + + @property + def opts(self): + return self._data.meta + + @property + def plots(self): + return self.plot_real, self.plot_imag, self.plot_error + + def get_state(self): + ret_dic = { + 'id': self.id, + 'data': self._data.get_state(), + 'mode': self.mode, + 'fits': self._fits, + 'real': ({'symbol': self.plot_real.symbol.value, + 'size': self.plot_real.symbolsize, + 'color': self.plot_real.symbolcolor.value}, + {'style': self.plot_real.linestyle.value, + 'width': self.plot_real.linewidth, + 'color': self.plot_real.linecolor.value}) + } + + if self.plot_imag is not None: + ret_dic['imag'] = ({'symbol': self.plot_imag.symbol.value, + 'size': self.plot_imag.symbolsize, + 'color': self.plot_imag.symbolcolor.value}, + {'style': self.plot_imag.linestyle.value, + 'width': self.plot_imag.linewidth, + 'color': self.plot_imag.linecolor.value}) + + return ret_dic + + def get_fits(self): + return [self._manager[idx] for idx in self._fits] + + def has_fits(self): + return len(self._fits) != 0 + + def set_fits(self, value: str or list, replace: bool = False): + if isinstance(value, str): + value = [value] + + if replace: + if isinstance(value, list): + self._fits = value + else: + raise TypeError() + else: + self._fits.extend(value) + + def _update_actions(self): + self.actions.update({'sort': self._data.sort, + 'cut': self._data.cut, + 'norm': self._data.normalize, + 'center': self.center}) + + @plot_update + def update(self, opts: dict): + self._data.update(opts) + + def get_properties(self) -> dict: + props = OrderedDict() + props['General'] = OrderedDict([('Name', self.name), ('Value', str(self.value)), ('Group', str(self.group))]) + props['Symbol'] = OrderedDict() + props['Line'] = OrderedDict() + + props['Symbol']['Symbol'] = self.plot_real.symbol + props['Symbol']['Size'] = self.plot_real.symbolsize + props['Symbol']['Color'] = self.plot_real.symbolcolor + + props['Line']['Style'] = self.plot_real.linestyle + props['Line']['Width'] = self.plot_real.linewidth + props['Line']['Color'] = self.plot_real.linecolor + + if self.plot_imag is not None: + props['Symbol']['Symbol (imag)'] = self.plot_imag.symbol + props['Symbol']['Size (imag)'] = self.plot_imag.symbolsize + props['Symbol']['Color (imag)'] = self.plot_imag.symbolcolor + + props['Line']['Style (imag)'] = self.plot_imag.linestyle + props['Line']['Width (imag)'] = self.plot_imag.linewidth + props['Line']['Color (imag)'] = self.plot_imag.linecolor + + return props + + def setColor(self, color, symbol=False, line=False, mode='real'): + if mode == 'real': + self.plot_real.set_color(color, symbol=symbol, line=line) + if self.plot_real.symbol != SymbolStyle.No and symbol: + err_pen = self.plot_error.pen + err_pen.setColor(self.plot_real.symbolcolor.rbg()) + self.plot_error.setData(pen=err_pen) + elif line: + err_pen = self.plot_error.pen + err_pen.setColor(self.plot_real.linecolor.rbg()) + self.plot_error.setData(pen=err_pen) + + elif mode == 'imag' and self.plot_imag is not None: + self.plot_imag.set_color(color, symbol=symbol, line=line) + else: + print('Updating color failed for ' + str(self.id)) + + def setSymbol(self, symbol=None, color=None, size=None, mode='real'): + if mode == 'real': + self.plot_real.set_symbol(symbol=symbol, size=size, color=color) + elif mode == 'imag' and self.plot_imag is not None: + self.plot_imag.set_symbol(symbol=symbol, size=size, color=color) + else: + print('Updating symbol failed for ' + str(self.id)) + + def setLine(self, width=None, style=None, color=None, mode='real'): + if mode == 'real': + self.plot_real.set_line(width=width, style=style, color=color) + elif mode == 'imag' and self.plot_imag is not None: + self.plot_imag.set_line(width=width, style=style, color=color) + else: + print('Updating line failed for ' + str(self.id)) + + def update_property(self, key1: str, key2: str, value: Any): + keykey = key2.split() + if len(keykey) == 1: + if key1 == 'Symbol': + self.setSymbol(mode='real', **{key2.lower(): value}) + + elif key1 == 'Line': + self.setLine(mode='real', **{key2.lower(): value}) + + elif key1 == 'General': + setattr(self, key2.lower(), value) + + else: + if key1 == 'Symbol': + self.setSymbol(mode='imag', **{keykey[0].lower(): value}) + + elif key1 == 'Line': + self.setLine(mode='imag', **{keykey[0].lower(): value}) + + def points(self, params: dict): + return self._data.points(**params) + + @plot_update + def apply(self, func: str, args: tuple): + if func in self.actions: + f = self.actions[func] + f(*args) + + return self + + @plot_update + def unsort(self, order: np.ndarray): + # this exists only to update plots after an undo action + self._data.x = self._data.x[order] + self._data.y = self._data.y[order] + self._data.y_err = self._data.y_err[order] + self._data.mask = self._data.mask[order] + + def save(self, fname): + ext = fname.suffix + if ext == '.agr': + real_dic = pgitem_to_dic(self.plot_real) + from ..io.exporters import GraceExporter + + GraceExporter(real_dic).export(fname) + + elif ext in ['.dat', '.txt']: + self._data.savetxt(fname, err=True) + + else: + raise ValueError('Unknown extension ' + ext) + + @plot_update + def setvalues(self, pos, valium): + xy, position = pos + if xy == 0: + self._data.x[position] = valium + elif xy == 1: + self._data.y[position] = valium + else: + self._data.y_err[position] = valium + + @property + def mask(self): + return self._data.mask + + @mask.setter + @plot_update + def mask(self, m): + self._data.mask = np.asarray(m, dtype=bool) + + @plot_update + def add(self, m): + if isinstance(m, (np.ndarray, list, tuple)): + self._data.append(m[0], m[1], y_err=m[2]) + elif isinstance(m, (Points, ExperimentContainer)): + self._data.append(m.x, m.y, y_err=m.y_err) + else: + raise TypeError('Unknown type ' + type(m)) + + @plot_update + def remove(self, m): + self._data.remove(m) + + @plot_update + def center(self) -> float: + offset = self.x[np.argmax(self.y.real)] + self._data._x -= offset + + return offset + + def get_namespace(self, i: int = None, j: int = None) -> dict: + if (i is None) and (j is None): + prefix = '' + else: + prefix = 'g[%i].s[%i].' % (i, j) + + namespace = {prefix + 'x': (self.x, 'x values'), + prefix + 'y': [self.y, 'y values'], + prefix + 'y_err': (self.y_err, 'y error values'), + prefix + 'value': (self.value, str(self.value))} + + if len(self._fits) == 1: + namespace.update({ + "%sfit['%s']" % (prefix, convert(pname, old='tex', new='str')): (pvalue.value, str(pvalue.value)) + for (pname, pvalue) in self._manager[self._fits[0]].parameter.items() + }) + else: + for k, f in enumerate(self._fits): + namespace.update({ + "%sfit['%s_%d']" % (prefix, convert(pname, old='tex', new='str'), k): (pvalue.value, str(pvalue.value)) + for (pname, pvalue) in self._manager[f].parameter.items() + }) + + return namespace + + def eval_expression(self, cmds, namespace): + namespace.update({'x': self.x, 'y': self.y, 'y_err': self.y_err, 'value': self.value}) + + if len(self._fits) == 1: + namespace.update({"fit['%s']" % (convert(pname, old='tex', new='str')): pvalue.value + for (pname, pvalue) in self._manager[self._fits[0]].parameter.items()}) + else: + for k, f in enumerate(self._fits): + namespace.update({"fit['%s_%i']" % (convert(pname, old='tex', new='str'), k): pvalue.value + for (pname, pvalue) in self._manager[f].parameter.items()}) + + new_data = self.copy() + for c in cmds: + if c: + exec(c, globals(), namespace) + + new_data.set_data(x=namespace['x'], y=namespace['y'], y_err=namespace['y_err']) + new_data.value = namespace['value'] + + return new_data + + +class PointContainer(ExperimentContainer): + symbols = symbolcycle() + + def __init__(self, identifier, data, **kwargs): + super().__init__(identifier, data, **kwargs) + + self.mode = 'pts' + self._init_plot(**kwargs) + + def _init_plot(self, **kwargs): + self.plot_imag = None + + color = kwargs.get('color', None) + symcolor = kwargs.get('symbolcolor', color) + linecolor = kwargs.get('linecolor', color) + + if symcolor is None and linecolor is None: + color = next(self.colors) + symcolor = color + linecolor = color + elif symcolor is None: + symcolor = linecolor + elif linecolor is None: + linecolor = symcolor + + sym_kwargs = { + 'symbol': kwargs.get('symbol', None), + 'size': kwargs.get('symbolsize', 10), + 'color': symcolor + } + + line_kwargs = { + 'style': kwargs.get('linestyle', None), + 'width': kwargs.get('linewidth', 1), + 'color': linecolor + } + + if sym_kwargs['symbol'] is None and line_kwargs['style'] is None: + if len(self._data) > 1000: + line_kwargs['style'] = LineStyle.Solid + sym_kwargs['symbol'] = SymbolStyle.No + else: + line_kwargs['style'] = LineStyle.No + sym_kwargs['symbol'] = next(PointContainer.symbols) + + self.plot_real = PlotItem(x=self._data.x, y=self._data.y, name=self.name, + symbol=None, pen=None, connect='finite') + + self.setSymbol(mode='real', **sym_kwargs) + self.setLine(mode='real', **line_kwargs) + + if sym_kwargs['symbol'] != SymbolStyle.No: + self.plot_error = ErrorBars(x=self._data.x, y=self._data.y, top=self._data.y_err, bottom=self._data.y_err, + pen=mkPen({'color': self.plot_real.symbolcolor.rgb()})) + else: + self.plot_error = ErrorBars(x=self._data.x, y=self._data.y, top=self._data.y_err, bottom=self._data.y_err, + pen=mkPen({'color': self.plot_real.linecolor.rgb()})) + + def update_property(self, key1: str, key2: str, value: Any): + # update default color + if key1 == 'Symbol' and key2 == 'Color': + self.plot_real.set_color(value, symbol=True, line=False) + super().update_property(key1, key2, value) + + +class FitContainer(ExperimentContainer): + def __init__(self, identifier, data, **kwargs): + super().__init__(identifier, data, **kwargs) + self.fitted_key = kwargs.get('src', '') + self.mode = 'fit' + self.parent_set = kwargs.get('src', '') + + self._init_plot(**kwargs) + + for n in ['statistics', 'nobs', 'nvar', 'parameter', 'model_name']: + setattr(self, n, getattr(data, n)) + + def _init_plot(self, **kwargs): + color = kwargs.get('color', (0, 0, 0)) + if isinstance(color, Colors): + color = color.rgb() + + self.plot_real = PlotItem(x=self._data.x, y=self._data.y.real, name=self.name, + pen=mkPen({'color': color}), + connect='finite', symbol=None) + + if np.iscomplexobj(self._data.y): + self.plot_imag = PlotItem(x=self._data.x, y=self._data.y.imag, name=self.name, + pen=mkPen({'color': color}), + connect='finite', symbol=None) + + @property + def fitted_key(self): + return self._data.idx + + @fitted_key.setter + def fitted_key(self, val): + self._data.idx = val + + def get_namespace(self, i: int = None, j: int = None): + namespace = super().get_namespace(i, j) + + namespace.update({ + "g[%i].s[%i].fit['%s']" % (i, j, convert(pname, old='latex', new='plain')): (pvalue.value, str(pvalue.value)) + for (pname, pvalue) in self._data.parameter.items() + }) + + return namespace + + +class SignalContainer(ExperimentContainer): + symbols = symbolcycle() + + def __init__(self, identifier, data, symbol=None, **kwargs): + super().__init__(identifier, data, **kwargs) + + self.mode = 'signal' + self._init_plot(symbol=symbol, **kwargs) + + def _init_plot(self, **kwargs): + self.plot_real = PlotItem(x=self._data.x, y=self._data.y.real, name=self.name, + symbol=None, pen=None, connect='finite') + self.plot_imag = PlotItem(x=self._data.x, y=self._data.y.imag, name=self.name, + symbol=None, pen=None, connect='finite') + + color = kwargs.get('color', None) + symcolor = kwargs.get('symbolcolor', color) + linecolor = kwargs.get('linecolor', color) + + if symcolor is None and linecolor is None: + color = next(self.colors) + symcolor = color + linecolor = color + elif symcolor is None: + symcolor = linecolor + elif linecolor is None: + linecolor = symcolor + + sym_kwargs = { + 'symbol': kwargs.get('symbol', None), + 'size': kwargs.get('symbolsize', 10), + 'color': symcolor + } + + line_kwargs = { + 'style': kwargs.get('linestyle', None), + 'width': kwargs.get('linewidth', 1), + 'color': linecolor + } + + if isinstance(self._data, BDS): + self.mode = 'bds' + + if sym_kwargs['symbol'] is None and line_kwargs['style'] is None: + sym_kwargs['symbol'] = next(PointContainer.symbols) + line_kwargs['style'] = LineStyle.No + + elif isinstance(self._data, Signal): + if line_kwargs['style'] is None and sym_kwargs['symbol'] is None: + line_kwargs['style'] = LineStyle.Solid + sym_kwargs['symbol'] = SymbolStyle.No + + if isinstance(self._data, FID): + self.mode = 'fid' + else: + self.mode = 'spectrum' + else: + raise TypeError('Unknown class %s, should be FID, Spectrum, or BDS.' % type(self._data)) + + for mode in ['real', 'imag']: + if mode == 'imag': + line_kwargs['style'] = LineStyle.Dashed + self.setSymbol(mode=mode, **sym_kwargs) + self.setLine(mode=mode, **line_kwargs) + + def _update_actions(self): + super()._update_actions() + + self.actions.update({'ph': self._data.manual_phase, 'bls': self._data.baseline_spline}) + if isinstance(self._data, Spectrum): + self.actions.update({'bl': self._data.baseline, 'ls': self._data.shift, + 'divide': self._data.divide, 'ft': self.fourier}) + self.mode = 'spectrum' + + elif isinstance(self._data, FID): + self.actions.update({'bl': self._data.baseline, 'ls': self._data.shift, + 'zf': self._data.zerofill, 'divide': self._data.divide, + 'ap': self._data.apod, 'ft': self.fourier}) + self.mode = 'fid' + + @plot_update + def fourier(self, mode='normal'): + if mode == 'normal': + self._data = self._data.fourier() + elif mode == 'depake': + try: + self._data = self._data.fft_depake() + except AttributeError: + return + self._update_actions() + + return self diff --git a/nmreval/gui_qt/data/conversion.py b/nmreval/gui_qt/data/conversion.py new file mode 100644 index 0000000..dbcb0b8 --- /dev/null +++ b/nmreval/gui_qt/data/conversion.py @@ -0,0 +1,171 @@ +from nmreval.gui_qt.Qt import QtWidgets, QtCore, QtGui +from nmreval.gui_qt._py.typeconversion import Ui_Dialog + + +class ConversionDialog(QtWidgets.QDialog, Ui_Dialog): + convertSets = QtCore.pyqtSignal(list) + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.simple_table.installEventFilter(self) + self.merge_table.installEventFilter(self) + + self._simple_table_dropevent = self.simple_table.dropEvent + self.simple_table.dropEvent = self._drop_on_simple_table + + self._merge_table_dropevent = self.merge_table.dropEvent + self.merge_table.dropEvent = self._drop_on_simple_table + + self.buttonGroup.buttonClicked.connect(self.change_table) + + def set_graphs(self, graphs: dict): + self.set_list.clear() + self.simple_table.clear() + self.simple_table.setHorizontalHeaderLabels(['Simple', 'Type']) + self.merge_table.clear() + self.merge_table.setHorizontalHeaderLabels(['Real', 'Imag', 'Type']) + + for graph, datasets in graphs.items(): + for set_id, set_name in datasets: + item_name = set_name + ' (' + graph[1] + ')' + + item1 = QtWidgets.QListWidgetItem(item_name) + item1.setData(QtCore.Qt.UserRole, set_id) + item1.setData(QtCore.Qt.UserRole+1, graph[0]) + self.set_list.addItem(item1) + + def eventFilter(self, src: QtCore.QObject, evt: QtCore.QEvent): + if evt.type() in [QtCore.QEvent.DragEnter, QtCore.QEvent.DragMove]: + evt.accept() + return True + + if evt.type() == QtCore.QEvent.KeyPress and evt.key() == QtCore.Qt.Key_Delete: + if src == self.simple_table: + type_idx = 1 + else: + type_idx = 2 + + if len(src.selectedIndexes()) > 0: + idx = src.selectedIndexes()[0] + row, col = idx.row(), idx.column() + + if col != type_idx: + src.takeItem(row, col) + is_empty = all(src.item(row, i) is None for i in range(type_idx)) + if is_empty: + src.removeRow(row) + + return True + + return super().eventFilter(src, evt) + + def _drop_on_simple_table(self, evt: QtGui.QDropEvent): + """ + event filter does not receive dropevents? + """ + if self.stackedWidget.currentIndex() == 0: + table = self.simple_table + type_column = 1 + default_drop = self._simple_table_dropevent + type_name = ['Points', 'FID', 'Spectrum', 'BDS'] + else: + table = self.merge_table + type_column = 2 + default_drop = self._merge_table_dropevent + type_name = ['FID', 'Spectrum', 'BDS'] + + pos = evt.pos() + drop_col = table.columnAt(pos.x()) + if drop_col == type_column: + evt.ignore() + else: + drop_row = table.rowAt(pos.y()) + default_drop(evt) + + if drop_row == -1: + w = QtWidgets.QComboBox() + w.addItems(type_name) + item = QtWidgets.QTableWidgetItem('') + drop_row = table.rowAt(pos.y()) + table.setItem(drop_row, type_column, item) + table.setCellWidget(drop_row, type_column, w) + + item = table.item(drop_row, drop_col) + idx = table.indexFromItem(item) + + if idx.row() == -1 and idx.column() == -1: + item = table.takeItem(drop_row, 0) + table.setItem(drop_row, drop_col, item) + + if item is not None: + item.setToolTip(item.text()) + + table.resizeColumnsToContents() + + @QtCore.pyqtSlot(QtWidgets.QAbstractButton) + def change_table(self, button: QtWidgets.QAbstractButton): + idx = [self.simple_button, self.merge_button].index(button) + self.stackedWidget.setCurrentIndex(idx) + + def collect_args(self) -> list: + src_sets = [] + for row in range(self.simple_table.rowCount()): + item = self.simple_table.item(row, 0) + set_id = item.data(QtCore.Qt.UserRole) + graph_id = item.data(QtCore.Qt.UserRole+1) + type_idx = self.simple_table.cellWidget(row, 1).currentIndex() + + src_sets.append((set_id, graph_id, type_idx)) + + for row in range(self.merge_table.rowCount()): + item = self.merge_table.item(row, 0) + graph_id = '' + if item is not None: + set_id_real = item.data(QtCore.Qt.UserRole) + graph_id = item.data(QtCore.Qt.UserRole+1) + else: + set_id_real = '' + + item = self.merge_table.item(row, 1) + if item is not None: + set_id_imag = item.data(QtCore.Qt.UserRole) + graph_id = item.data(QtCore.Qt.UserRole+1) if graph_id == '' else graph_id + else: + set_id_imag = '' + type_idx = self.merge_table.cellWidget(row, 2).currentIndex() + 1 + + src_sets.append((set_id_real, set_id_imag, graph_id, type_idx)) + + print(src_sets) + + self.convertSets.emit(src_sets) + + return src_sets + + @QtCore.pyqtSlot(QtWidgets.QAbstractButton, name='on_buttonBox_clicked') + def button_clicked(self, button): + role = self.buttonBox.buttonRole(button) + if role == self.buttonBox.RejectRole: + self.close() + else: + self.collect_args() + self.accept() + + +if __name__ == '__main__': + import sys + from collections import OrderedDict + + app = QtWidgets.QApplication(sys.argv) + d = ConversionDialog() + + data = OrderedDict([ + (('1', 'Graph 0'), [('a', 'Das Sein und das Nichts'), ('b', 'b'), ('c', 'c'), ('d', 'd')]), + (('2', 'Graph 2'), [('e', 'e'), ('f', 'f'), ('g', 'g'), ('h', 'h')])]) + + d.set_graphs(data) + d.show() + + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/data/datawidget/__init__.py b/nmreval/gui_qt/data/datawidget/__init__.py new file mode 100644 index 0000000..009a5fb --- /dev/null +++ b/nmreval/gui_qt/data/datawidget/__init__.py @@ -0,0 +1 @@ +from .datawidget import * diff --git a/nmreval/gui_qt/data/datawidget/datawidget.py b/nmreval/gui_qt/data/datawidget/datawidget.py new file mode 100644 index 0000000..61311bf --- /dev/null +++ b/nmreval/gui_qt/data/datawidget/datawidget.py @@ -0,0 +1,483 @@ +from typing import List, Union + +from .properties import PropWidget +from ...Qt import QtWidgets, QtGui, QtCore +from ..._py.datawidget import Ui_DataWidget +from ...lib import make_action_icons +from ...lib.delegates import HeaderDelegate + + +class DataTree(QtWidgets.QTreeWidget): + stateChanged = QtCore.pyqtSignal(list, list) # selected, deselected + keyChanged = QtCore.pyqtSignal(str, str) # id, text + positionChanged = QtCore.pyqtSignal(QtWidgets.QTreeWidgetItem) + deleteItem = QtCore.pyqtSignal(list) + moveItem = QtCore.pyqtSignal(list, str, str, int) # items, from, to, new row + copyItem = QtCore.pyqtSignal(list, str) + saveFits = QtCore.pyqtSignal(list) + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.setColumnCount(1) + self.invisibleRootItem().setFlags(self.invisibleRootItem().flags() ^ QtCore.Qt.ItemIsDropEnabled) + + self.itemChanged.connect(self.data_change) + + self.setColumnCount(2) + + self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding) + self.setDragDropMode(QtWidgets.QTreeView.InternalMove) + self.setDefaultDropAction(QtCore.Qt.IgnoreAction) + self.setSelectionMode(QtWidgets.QTreeView.ExtendedSelection) + self.setSelectionBehavior(QtWidgets.QTreeView.SelectRows) + + self._checked_graphs = set() + self._checked_sets = set() + self.management = None + + header = QtWidgets.QHeaderView(QtCore.Qt.Horizontal, self) + self.setHeader(header) + header.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch) + header.setVisible(False) + header.moveSection(1, 0) + self.setColumnWidth(1, 16) + self.setItemDelegateForColumn(1, HeaderDelegate()) + + def add_graph(self, idd: str, name: str): + item = QtWidgets.QTreeWidgetItem() + item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDropEnabled | QtCore.Qt.ItemIsEditable | + QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsUserCheckable) + item.setText(0, name) + item.setData(0, QtCore.Qt.UserRole, idd) + item.setCheckState(0, QtCore.Qt.Checked) + + self.addTopLevelItem(item) + self._checked_graphs.add(idd) + item.setExpanded(True) + + def add_item(self, items: Union[tuple, List[tuple]], gid: str): + if isinstance(items, tuple): + items = [items] + + for row in range(self.invisibleRootItem().childCount()): + graph = self.invisibleRootItem().child(row) + if graph.data(0, QtCore.Qt.UserRole) == gid: + for (idd, name) in items: + item = QtWidgets.QTreeWidgetItem([name]) + item.setData(0, QtCore.Qt.UserRole, idd) + item.setCheckState(0, QtCore.Qt.Checked) + item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsEditable | + QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsUserCheckable) + graph.addChild(item) + self._checked_sets.add(idd) + + self.resizeColumnToContents(0) + break + + @QtCore.pyqtSlot(QtWidgets.QTreeWidgetItem) + def data_change(self, item: QtWidgets.QTreeWidgetItem) -> (list, list): + idd = item.data(0, QtCore.Qt.UserRole) + is_selected = item.checkState(0) == QtCore.Qt.Checked + to_be_hidden = set() + to_be_shown = set() + + # item is top-level item / graph + if item.parent() is None: + was_selected = idd in self._checked_graphs + + # check state changed to selected + if is_selected != was_selected: + # check state changed to checked + if is_selected: + self._checked_graphs.add(idd) + iterator = QtWidgets.QTreeWidgetItemIterator(item) + iterator += 1 + self.blockSignals(True) + for i in range(item.childCount()): + child = item.child(i) + child.setCheckState(0, QtCore.Qt.Checked) + to_be_shown.add(child.data(0, QtCore.Qt.UserRole)) + self.blockSignals(False) + + # check state change to unchecked + else: + self._checked_graphs.remove(idd) + self.blockSignals(True) + for i in range(item.childCount()): + child = item.child(i) + child.setCheckState(0, QtCore.Qt.Unchecked) + to_be_hidden.add(child.data(0, QtCore.Qt.UserRole)) + try: + self._checked_sets.remove(child.data(0, QtCore.Qt.UserRole)) + except KeyError: + pass + self.blockSignals(False) + + else: + self.keyChanged.emit(idd, item.text(0)) + + # item is a set + else: + was_selected = idd in self._checked_sets + if is_selected != was_selected: + if is_selected: + to_be_shown.add(idd) + self._checked_sets.add(idd) + + else: + to_be_hidden.add(idd) + try: + self._checked_sets.remove(idd) + except KeyError: + pass + + else: + self.keyChanged.emit(idd, item.text(0)) + + if to_be_shown or to_be_hidden: + self.stateChanged.emit(list(to_be_shown), list(to_be_hidden)) + + return to_be_shown, to_be_hidden + + def dropEvent(self, evt: QtGui.QDropEvent): + dropped_index = self.indexAt(evt.pos()) + if not dropped_index.isValid(): + return + + to_parent = self.itemFromIndex(dropped_index).parent() + append = False + if not to_parent: + # dropped on graph item -> append items + to_parent = self.itemFromIndex(dropped_index) + append = True + + # index may change + persistent_drop = QtCore.QPersistentModelIndex(dropped_index) + + tobemoved = [] + take_from = [] + for it in self.selectedItems(): + from_parent = it.parent() + if from_parent is None: + continue + + from_parent.removeChild(it) + tobemoved.append(it) + take_from.append(from_parent.data(0, QtCore.Qt.UserRole)) + + pos = QtCore.QModelIndex(persistent_drop) + if self.dropIndicatorPosition() == QtWidgets.QAbstractItemView.BelowItem: + pos = pos.sibling(pos.row()+1, 0) + + row = pos.row() + if (row == -1) or append: + to_parent.addChildren(tobemoved) + else: + to_parent.insertChildren(row, tobemoved) + + self.management.move_sets([it.data(0, QtCore.Qt.UserRole) for it in tobemoved], + to_parent.data(0, QtCore.Qt.UserRole), take_from, + pos=-1 if append else row) + + def move_sets(self, sid: str, gid_in: str, gid_out: str): + self.blockSignals(True) + to_parent = None + from_parent = None + it = None + + iterator = QtWidgets.QTreeWidgetItemIterator(self) + while iterator.value(): + item = iterator.value() + if item is not None: + data = item.data(0, QtCore.Qt.UserRole) + if data == gid_out: + from_parent = item + + elif data == gid_in: + to_parent = item + + elif data == sid: + it = item + + iterator += 1 + + if (from_parent is None) or (to_parent is None) or (it is None): + print('Komisch') + return + + from_parent.removeChild(it) + to_parent.addChild(it) + + self.blockSignals(False) + + def set_name(self, sid, name): + iterator = QtWidgets.QTreeWidgetItemIterator(self) + while iterator.value(): + item = iterator.value() + if item is not None: + data = item.data(0, QtCore.Qt.UserRole) + if data == sid: + if name != item.text(0): + item.setText(0, name) + break + + iterator += 1 + + def keyPressEvent(self, evt: QtGui.QKeyEvent): + if evt.key() == QtCore.Qt.Key_Delete: + rm_sets = [] + rm_graphs = [] + for idx in self.selectedIndexes(): + if idx.column() == 1: + continue + item = self.itemFromIndex(idx) + if item.parent() is None: + for c_i in range(item.childCount()): + rm_sets.append(item.child(c_i).data(0, QtCore.Qt.UserRole)) + rm_graphs.append(item.data(0, QtCore.Qt.UserRole)) + else: + rm_sets.append(item.data(0, QtCore.Qt.UserRole)) + + # self.deleteItem.emit(rm_sets+rm_graphs) + self.management.delete_sets(rm_sets+rm_graphs) + + elif evt.key() == QtCore.Qt.Key_Space: + sets = [] + from_parent = [] + + for idx in self.selectedIndexes(): + if idx.column() != 0: + continue + item = self.itemFromIndex(idx) + + if item.parent() is None: + is_selected = item.checkState(0) + self.blockSignals(True) + for i in range(item.childCount()): + child = item.child(i) + from_parent.append(child) + self.blockSignals(False) + if is_selected == QtCore.Qt.Checked: + item.setCheckState(0, QtCore.Qt.Unchecked) + else: + item.setCheckState(0, QtCore.Qt.Checked) + + else: + sets.append(item) + + for it in sets: + if it in from_parent: + continue + it.setCheckState(0, QtCore.Qt.Unchecked if it.checkState(0) == QtCore.Qt.Checked else QtCore.Qt.Checked) + else: + super().keyPressEvent(evt) + + def mousePressEvent(self, evt: QtGui.QMouseEvent): + # disable drag-and-drop when column 1 ('header') is clicked + idx = self.indexAt(evt.pos()) + self.setDragEnabled(idx.column() == 0) + super().mousePressEvent(evt) + + def remove_item(self, ids: list): + iterator = QtWidgets.QTreeWidgetItemIterator(self) + while iterator.value(): + item = iterator.value() + _id = item.data(0, QtCore.Qt.UserRole) + if _id in ids: + try: + idx = item.parent().indexOfChild(item) + item.parent().takeChild(idx) + if _id in self._checked_sets: + self._checked_sets.remove(_id) + except AttributeError: + idx = self.invisibleRootItem().indexOfChild(item) + self.invisibleRootItem().takeChild(idx) + self._checked_graphs.remove(_id) + + iterator += 1 + + def contextMenuEvent(self, evt): + menu = QtWidgets.QMenu() + d = menu.addAction('Hello') + d.setEnabled(False) + menu.addSeparator() + + idx = self.selectedIndexes() + + if self.invisibleRootItem().childCount() == 0 and len(idx) == 0: + rdn_action = menu.addAction('Randomness') + + action = menu.exec(evt.globalPos()) + + if action == rdn_action: + import webbrowser + webbrowser.open('https://en.wikipedia.org/wiki/Special:Random') + + else: + del_action = menu.addAction('Exterminate') + cp_action = menu.addAction('Replicate') + cat_action = menu.addAction('Join us!') + plt_action = None + save_action = None + + idx = {} + has_fits = False + for i in self.selectedIndexes(): + item = self.itemFromIndex(i) + parent = item.parent() + if parent is None: + continue + + else: + graph_id = parent.data(0, QtCore.Qt.UserRole) + if graph_id not in idx: + idx[graph_id] = [] + # collect sets in their graph + idx[graph_id].append(item.data(0, QtCore.Qt.UserRole)) + data = self.management[item.data(0, QtCore.Qt.UserRole)] + if data.mode == 'fit': + has_fits = True + + if has_fits: + menu.addSeparator() + plt_action = menu.addAction('Plot fit parameter') + save_action = menu.addAction('Save fit parameter') + + action = menu.exec(evt.globalPos()) + + if action == del_action: + s = [] + for gid, sets in idx.items(): + s.extend(sets) + self.management.delete_sets(s) + + elif action == cp_action: + for gid, sets in idx.items(): + self.management.copy_sets(sets, gid) + + elif action == cat_action: + s = [] + for gid, sets in idx.items(): + s.extend(sets) + self.management.cat(s) + + elif action == plt_action: + s = [] + for gid, sets in idx.items(): + s.extend(sets) + self.management.make_fit_parameter(s) + + elif action == save_action: + s = [] + for gid, sets in idx.items(): + s.extend(sets) + self.saveFits.emit(s) + + evt.accept() + + def highlight(self, gid: str): + iterator = QtWidgets.QTreeWidgetItemIterator(self) + while iterator.value(): + item = iterator.value() + if item is not None: + if item.data(0, QtCore.Qt.UserRole) == gid: + item.setBackground(0, QtGui.QBrush(QtGui.QColor('gray'))) + else: + item.setBackground(0, QtGui.QBrush()) + iterator += 1 + + def uncheck_sets(self, sets: List[str]): + self.blockSignals(True) + iterator = QtWidgets.QTreeWidgetItemIterator(self) + while iterator.value(): + item = iterator.value() + if item is not None: + if item.data(0, QtCore.Qt.UserRole) in sets: + item.setCheckState(0, QtCore.Qt.Unchecked) + iterator += 1 + self.blockSignals(False) + + +class DataWidget(QtWidgets.QWidget, Ui_DataWidget): + keyChanged = QtCore.pyqtSignal(str, str) + deleteItem = QtCore.pyqtSignal(list) + startShowProperty = QtCore.pyqtSignal(list) + propertyChanged = QtCore.pyqtSignal(list, str, str, object) + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.setupUi(self) + self.tree = DataTree(self) + self.verticalLayout.addWidget(self.tree) + self.tree.selectionModel().selectionChanged.connect(lambda x, y: self.show_property(x)) + + self.tree.keyChanged.connect(lambda x, y: self.keyChanged.emit(x, y)) + + self.proptable = PropWidget(self) + self.propwidget.addWidget(self.proptable) + self.propwidget.setText('Properties') + self.propwidget.expansionChanged.connect(self.show_property) + self.proptable.propertyChanged.connect(self.change_property) + + make_action_icons(self) + + def add_graph(self, idd: str, name: str): + self.tree.blockSignals(True) + self.tree.add_graph(idd, name) + self.tree.blockSignals(False) + + def add_item(self, idd: str, name: str, gid: str): + self.tree.blockSignals(True) + self.tree.add_item((idd, name), gid) + self.tree.blockSignals(False) + + def add_item_list(self, loi: list, gid: str): + self.tree.blockSignals(True) + self.tree.add_item(loi, gid) + self.tree.blockSignals(False) + + def remove_item(self, key): + self.tree.remove_item(key) + + def show_property(self, _: QtCore.QModelIndex = None): + if not self.propwidget.isExpanded(): + return + + sid = [] + for i in self.tree.selectedIndexes(): + if i.column() == 0: + sid.append(i.data(role=QtCore.Qt.UserRole)) + + self.startShowProperty.emit(sid) + + @QtCore.pyqtSlot(dict) + def set_properties(self, props: dict): + self.proptable.populate(props) + + def change_property(self, key1, key2, value): + ids = [item.data(0, QtCore.Qt.UserRole) for item in self.tree.selectedItems()] + if key2 == 'Value': + try: + value = float(value) + except ValueError: + QtWidgets.QMessageBox.warning(self, 'Invalid entry', + 'Value %r is not a valid number for `value`.' % value) + return + + self.propertyChanged.emit(ids, key1, key2, value) + + def uncheck_sets(self, sets: List[str]): + self.tree.uncheck_sets(sets) + + def set_name(self, sid, value): + self.tree.set_name(sid, value) + + @property + def management(self): + return self.tree.management + + @management.setter + def management(self, value): + self.tree.management = value diff --git a/nmreval/gui_qt/data/datawidget/properties.py b/nmreval/gui_qt/data/datawidget/properties.py new file mode 100644 index 0000000..dd07087 --- /dev/null +++ b/nmreval/gui_qt/data/datawidget/properties.py @@ -0,0 +1,78 @@ +from ...Qt import QtWidgets, QtCore, QtGui +from ...lib.delegates import PropertyDelegate + + +class PropWidget(QtWidgets.QWidget): + propertyChanged = QtCore.pyqtSignal(str, str, object) + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.layout = QtWidgets.QVBoxLayout(self) + self.layout.setContentsMargins(2, 2, 2, 2) + self.tab = QtWidgets.QTabWidget(self) + self.layout.addWidget(self.tab) + self.pages = [] + + self.tab.currentChanged.connect(self.tab_change) + + self._tab_idx = 0 + + def populate(self, props: dict): + self.pages = [] + self.tab.blockSignals(True) + while self.tab.count(): + self.tab.removeTab(0) + + for k, v in props.items(): + table = PropTable(self) + table.populate(v) + table.itemChanged.connect(self.property_change) + self.tab.addTab(table, k) + self.pages.append(table) + self.tab.blockSignals(False) + + self.tab.setCurrentIndex(self._tab_idx) + + @QtCore.pyqtSlot(QtWidgets.QTableWidgetItem) + def property_change(self, item: QtWidgets.QTableWidgetItem): + tab_idx = self.tab.currentIndex() + table = self.pages[tab_idx] + idx = table.indexFromItem(item) + self.propertyChanged.emit(self.tab.tabText(tab_idx), + table.item(idx.row(), idx.column()-1).text(), + item.data(QtCore.Qt.DisplayRole)) + + @QtCore.pyqtSlot(int) + def tab_change(self, idx: int): + self._tab_idx = idx + + +class PropTable(QtWidgets.QTableWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.setColumnCount(2) + self.setItemDelegateForColumn(1, PropertyDelegate()) + self.horizontalHeader().setStretchLastSection(True) + self.verticalHeader().setVisible(False) + self.horizontalHeader().setVisible(False) + self.setFrameShape(QtWidgets.QFrame.NoFrame) + self.setFrameShadow(QtWidgets.QFrame.Plain) + + def populate(self, prop: dict): + self.clear() + self.setRowCount(0) + self.blockSignals(True) + for k, v in prop.items(): + value_item = QtWidgets.QTableWidgetItem('') + value_item.setData(QtCore.Qt.DisplayRole, v) + + key_item = QtWidgets.QTableWidgetItem(k) + key_item.setFlags(QtCore.Qt.NoItemFlags) + key_item.setForeground(QtGui.QBrush(QtGui.QColor(0, 0, 0))) + + self.setRowCount(self.rowCount()+1) + self.setItem(self.rowCount()-1, 0, key_item) + self.setItem(self.rowCount()-1, 1, value_item) + self.blockSignals(False) diff --git a/nmreval/gui_qt/data/integral_widget.py b/nmreval/gui_qt/data/integral_widget.py new file mode 100644 index 0000000..19272bb --- /dev/null +++ b/nmreval/gui_qt/data/integral_widget.py @@ -0,0 +1,213 @@ +from itertools import cycle + +import pyqtgraph as pg +from numpy import nanmax, nanmin, inf, argsort, where +try: + # numpy > 1.19 renamed some integration functions + from scipy.integrate import cumulative_trapezoid +except ImportError: + from scipy.integrate import cumtrapz as cumulative_trapezoid + +from ..Qt import QtWidgets, QtCore, QtGui +from .._py.integral_widget import Ui_Form + + +class IntegralWidget(QtWidgets.QWidget, Ui_Form): + colors = cycle(['red', 'green', 'blue', 'cyan', 'magenta', + 'darkRed', 'darkGreen', 'darkBlue', 'darkCyan', 'darkMagenta']) + + requestData = QtCore.pyqtSignal(str) + item_deleted = QtCore.pyqtSignal(pg.GraphicsObject) + newData = QtCore.pyqtSignal(str, list) + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.connected_figure = '' + self.graph_shown = None + self.shown_set = None + + self._data = None + self.ranges = [] + self.lines = [] + + self.max_area = 0 + self.max_y = inf + self.min_y = -inf + + def __call__(self, graph_name, items): + self.label_2.setText(f'Connected to {graph_name}') + + self.clear() + + self.set_combobox.blockSignals(True) + self.set_combobox.clear() + + for sid, name in items: + self.set_combobox.addItem(name, userData=sid) + + self.set_combobox.blockSignals(False) + + self.set_combobox.setCurrentIndex(0) + self.set_combobox.currentIndexChanged.emit(0) + + return self + + def keyPressEvent(self, e): + if e.key() == QtCore.Qt.Key_Delete: + self.remove_integral() + else: + super().keyPressEvent(e) + + @QtCore.pyqtSlot(int, name='on_set_combobox_currentIndexChanged') + def change_set(self, idx: int): + key = self.set_combobox.itemData(idx) + self.requestData.emit(key) + + def set_data(self, ptr): + self._data = ptr + self.max_y = nanmax(self._data.y.real) + self.min_y = nanmin(self._data.y.real) + for idx, rnge in enumerate(self.ranges): + self._update_values(idx, rnge) + + def add(self, pos): + x = pos[0] + self.ranges.append((x, x * 1.1)) + + c = next(IntegralWidget.colors) + qc = QtGui.QColor(c) + qc.setAlpha(40) + region = pg.LinearRegionItem(values=[x, x*1.1], brush=QtGui.QBrush(qc), pen=pg.mkPen(QtGui.QColor(c))) + integral_plot = pg.PlotDataItem(x=[], y=[]) + region.sigRegionChanged.connect(self._update_integral) + + self.lines.append((region, integral_plot)) + self.areas.append(0) + self._make_entry(c) + + return region, integral_plot + + def _make_entry(self, c): + item = QtWidgets.QTreeWidgetItem() + item.setText(0, f'Integral {len(self.ranges)}') + + item.setForeground(0, QtGui.QBrush(QtGui.QColor(c))) + + pts_i = self.ranges[-1] + item_list = [] + for text, val in [('Start', pts_i[0]), ('Stop', pts_i[1]), ('Areas', 0), ('Ratio', 1.)]: + child = QtWidgets.QTreeWidgetItem() + child.setFlags(QtCore.Qt.NoItemFlags) + child.setText(0, f'{text}: {val:.5g}') + child.setForeground(0, QtGui.QBrush(QtGui.QColor('black'))) + + item_list.append(child) + + item.addChildren(item_list) + + self.treeWidget.addTopLevelItem(item) + self.treeWidget.expandToDepth(1) + + self._update_values(len(self.ranges) - 1, pts_i) + + def _update_integral(self): + idx = None + sender = self.sender() + for i, (reg, _) in enumerate(self.lines): + if sender == reg: + idx = i + break + + if idx is None: + return + + self._update_values(idx, sender.getRegion()) + + def _update_values(self, idx, new_range): + self.ranges[idx] = new_range + area = self.calc_integral(idx, *new_range) + + item = self.treeWidget.topLevelItem(idx) + item.child(0).setText(0, f'Start: {new_range[0]:.5g}') + item.child(1).setText(0, f'Stop: {new_range[1]:.5g}') + + if area is not None: + self.areas[idx] = area + item.child(2).setText(0, f'Area: {area:.5g}') + if self.max_area > 0: + self._set_ratios(idx, self.max_area) + + curr_max = max(self.areas) + if curr_max != self.max_area: + if curr_max > 0: + root = self.treeWidget.invisibleRootItem() + for i in range(root.childCount()): + self._set_ratios(i, curr_max) + self.max_area = curr_max + + def _set_ratios(self, idx, max_value): + item = self.treeWidget.invisibleRootItem().child(idx) + area_i = self.areas[idx] + item.child(3).setText(0, f'Ratio: {area_i / max_value:.3g}') + + integral_line = self.lines[idx][1] + x_i, y_i = integral_line.getData() + scale = (self.max_y - self.min_y) / y_i[-1] * (area_i / max_value) + integral_line.setData(x=x_i, y=y_i * scale) + + def calc_integral(self, idx, x_min, x_max): + int_range = where((self._data.x >= x_min) & (self._data.x <= x_max))[0] + if len(int_range) > 1: + x_int = self._data.x[int_range] + y_int = self._data.y[int_range].real + order = argsort(x_int) + + integral = cumulative_trapezoid(y=y_int[order], x=x_int[order], initial=0) + scale = (self.max_y-self.min_y) / integral[-1] + self.lines[idx][1].setData(x=x_int[order], y=integral*scale + self.min_y) + + return integral[-1] + + else: + self.lines[idx][1].setData(x=[], y=[]) + return None + + def remove_integral(self): + root = self.treeWidget.invisibleRootItem() + for item in self.treeWidget.selectedItems(): + idx = root.indexOfChild(item) + + self.ranges.pop(idx) + self.item_deleted.emit(self.lines[idx][0]) + self.item_deleted.emit(self.lines[idx][1]) + self.lines.pop(idx) + self.areas.pop(idx) + self.treeWidget.takeTopLevelItem(idx) + + @QtCore.pyqtSlot(name='on_pushButton_clicked') + def convert_to_datasets(self): + set_id = self.set_combobox.currentData() + values = [] + for i in range(len(self.ranges)): + x_i, y_i = self.lines[i][1].getData() + start_i, stop_i = self.ranges[i] + area_i = self.areas[i] + values.append((x_i, y_i, start_i, stop_i, area_i)) + + self.newData.emit(set_id, values) + + def clear(self): + self.connected_figure = '' + self.graph_shown = None + self.shown_set = None + + self._data = None + self.ranges = [] + self.lines = [] + + self.max_area = 0 + self.max_y = inf + self.min_y = -inf + diff --git a/nmreval/gui_qt/data/interpolate_dialog.py b/nmreval/gui_qt/data/interpolate_dialog.py new file mode 100644 index 0000000..e70fc4b --- /dev/null +++ b/nmreval/gui_qt/data/interpolate_dialog.py @@ -0,0 +1,41 @@ +from numpy import linspace, logspace, log10 + +from ..Qt import QtWidgets, QtCore +from .._py.interpol_dialog import Ui_Dialog + + +class QInterpol(QtWidgets.QDialog, Ui_Dialog): + ready = QtCore.pyqtSignal(dict) + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.setupUi(self) + + self.on_comboBox_2_currentIndexChanged(0) + + @QtCore.pyqtSlot(int) + def on_comboBox_2_currentIndexChanged(self, idx: int): + if idx == 0: + self.frame.hide() + self.frame_2.show() + else: + self.frame.show() + self.frame_2.hide() + + def accept(self): + ret_dic = {'kind': self.comboBox.currentIndex(), 'ylog': self.checkBox_2.isChecked()} + if self.comboBox_2.currentIndex() == 0: + ret_dic['xaxis'] = int(self.lineEdit.text()) + else: + if self.checkBox.isChecked(): + ret_dic['xaxis'] = logspace(log10(float(self.lineEdit_2.text())), + log10(float(self.lineEdit_3.text())), + num=int(self.lineEdit_4.text())) + else: + ret_dic['xaxis'] = linspace(float(self.lineEdit_2.text()), + float(self.lineEdit_3.text()), + num=int(self.lineEdit_4.text())) + ret_dic['idx'] = [i.row() for i in self.listWidget.selectedIndexes()] + self.ready.emit(ret_dic) + self.close() diff --git a/nmreval/gui_qt/data/plot_dialog.py b/nmreval/gui_qt/data/plot_dialog.py new file mode 100644 index 0000000..a49102a --- /dev/null +++ b/nmreval/gui_qt/data/plot_dialog.py @@ -0,0 +1,123 @@ +from random import randint + +import numpy as np + +from ... import models +from ...lib.importer import find_models +from ...lib.utils import valid_function + +from ..Qt import QtGui, QtCore, QtWidgets +from .._py.setbyfunction_dialog import Ui_NewCurveDialog + + +class QPlotDialog(QtWidgets.QDialog, Ui_NewCurveDialog): + line_created = QtCore.pyqtSignal(object) + + def __init__(self): + super().__init__() + self.setupUi(self) + + self._function = find_models(models) + + self.lineEdit_3.setValidator(QtGui.QDoubleValidator()) + self.lineEdit_4.setValidator(QtGui.QDoubleValidator()) + self.lineEdit_5.setValidator(QtGui.QIntValidator().setBottom(0)) + + self.buttonBox.accepted.connect(self.make_line) + + for cb in [self.comboBox, self.comboBox_2, self.comboBox_4, self.comboBox_5]: + cb.setCurrentIndex(randint(0, cb.count())) + + for cb in [self.comboBox_6, self.comboBox_7]: + self.load_models(cb) + + def load_models(self, cb: QtWidgets.QComboBox): + for f in self._function: + cb.addItem(f'{f.name} ({f.type})', userData=f) + + @QtCore.pyqtSlot(name='on_pushButton_clicked') + def check_input(self): + err = [] + try: + start = float(self.lineEdit_3.text()) + except ValueError: + err.append(0) + start = 1 + try: + stop = float(self.lineEdit_4.text()) + except ValueError: + err.append(1) + stop = 10 + + try: + nums = int(self.lineEdit_5.text()) + except ValueError: + err.append(2) + nums = 10 + + if self.checkBox.isChecked(): + if start <= 0 or stop <= 0: + err.append(3) + start, stop = abs(start)+1e-12, abs(stop) + grid = np.geomspace(start, stop, num=nums) + else: + grid = np.linspace(start, stop, num=nums) + + x_func = self.lineEdit.text() + x, isok = valid_function(x_func, extra_namespace={'i': grid}) + if not isok: + err.append(4) + x = grid + + y_func = self.lineEdit_2.text() + y, isok = valid_function(y_func, extra_namespace={'i': grid, 'x':x}) + if not isok: + err.append(5) + + msg_err = {0: 'Invalid value for grid start', + 1: 'Invalid value for grid end', + 2: 'Invalid number of grid steps', + 3: 'Negative numbers in logarithmic grid', + 4: 'Invalid expression for x', + 5: 'Invalid expression for y' + } + + if err: + m = '\n'.join([msg_err[e] for e in err]) + QtWidgets.QMessageBox().information(self, 'Error detected', m) + return False + + return True + + def make_line(self): + if not self.check_input(): + return + + start = float(self.lineEdit_3.text()) + stop = float(self.lineEdit_4.text()) + nums = int(self.lineEdit_5.text()) + if self.checkBox.isChecked(): + x = np.geomspace(start, stop, num=nums) + else: + x = np.linspace(start, stop, num=nums) + x_func = self.lineEdit.text() + y_func = self.lineEdit_2.text() + + sym = self.comboBox.currentText() + lin = self.comboBox_2.currentText() + + name = self.lineEdit_6.text() + if not name: + name = 'self done' + + lw = self.doubleSpinBox.value() + sw = self.spinBox.value() + + +if __name__ == '__main__': + import sys + app = QtWidgets.QApplication(sys.argv) + win = QPlotDialog() + win.show() + + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/data/point_select.py b/nmreval/gui_qt/data/point_select.py new file mode 100644 index 0000000..c400249 --- /dev/null +++ b/nmreval/gui_qt/data/point_select.py @@ -0,0 +1,196 @@ +import re + +from ..Qt import QtCore, QtWidgets +from .._py.ptstab import Ui_Form + +__all__ = ['PointSelectWidget'] + +from ..lib.pg_objects import LogInfiniteLine, RegionItem + +REGION_RE = re.compile(r'(?P[+-]*\d+(?:\.\d*)*(?:[eE][+-]*\d+)*)' + r'(?: ?- ?(?P[+-]*\d+(?:\.\d*)*(?:[eE][+-]*\d+)*))*') + + +class PointSelectWidget(QtWidgets.QWidget, Ui_Form): + widget_closed = QtCore.pyqtSignal() + points_selected = QtCore.pyqtSignal(dict, str) + point_removed = QtCore.pyqtSignal(LogInfiniteLine) + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.pts = [] + self.pts_lines = [] + self.nop = 0 + self._prev_pos = '' + self._last_item = None + self.connected_figure = '' + + self.okButton.clicked.connect(self.apply) + self.deleteButton.clicked.connect(self.remove_points) + self.peaktable.itemChanged.connect(self.editing_finished) + self.peaktable.itemDoubleClicked.connect(self.editing_started) + + def keyPressEvent(self, e): + if e.key() == QtCore.Qt.Key_Delete: + self.remove_points() + elif e.key() == QtCore.Qt.Key_F2: + self.editing_started() + else: + super().keyPressEvent(e) + + def clear(self): + self.pts = [] + self.nop = 0 + self.peaktable.clear() + self.pts_lines = [] + + @QtCore.pyqtSlot(tuple, bool) + def add(self, pos: tuple, double: bool): + x = pos[0] + if double: + self.removepoint(-1) + + self.pts.append((x, x*1.1)) + item = RegionItem(values=[x, x*1.1], mode='mid') + item.sigRegionChanged.connect(self._update_region) + else: + self.pts.append(x) + item = LogInfiniteLine(pos=x, movable=True) + item.sigPositionChanged.connect(self._update_line) + + self.pts_lines.append(item) + self.nop += 1 + self._makerow() + + return item + + def remove_points(self): + for i in sorted(self.peaktable.selectedIndexes(), key=lambda x: x.row(), reverse=True): + self.removepoint(pos=i.row()) + + def removepoint(self, pos=0): + if pos == -1: + pos = len(self.pts) - 1 + + try: + self.pts.pop(pos) + self.nop -= 1 + item = self.peaktable.takeItem(pos) + del item + + del_line = self.pts_lines.pop(pos) + self.point_removed.emit(del_line) + del del_line + except IndexError: + pass + + def _makerow(self): + if isinstance(self.pts[-1], tuple): + item = QtWidgets.QListWidgetItem(f'{self.pts[-1][0]:.5g} - {self.pts[-1][1]:.5g}') + else: + item = QtWidgets.QListWidgetItem(f'{self.pts[-1]:.5g}') + item.setFlags(item.flags() ^ QtCore.Qt.ItemIsEditable) + self.peaktable.blockSignals(True) + self.peaktable.addItem(item) + self.peaktable.blockSignals(False) + + def closeEvent(self, evt): + self.widget_closed.emit() + super().closeEvent(evt) + + @QtCore.pyqtSlot() + def apply(self) -> dict: + ret_dic = {'avg_range': [self.left_pt.value(), self.right_pt.value()], + 'avg_mode': {0: 'mean', 1: 'sum', 2: 'integral'}[self.average_combobox.currentIndex()], + 'special': None, 'idx': None, + 'xy': (self.xbutton.isChecked(), self.ybutton.isChecked())} + + if self.groupBox_2.isChecked(): + ret_dic['special'] = {0: 'max', 1: 'absmax', 2: 'min', 3: 'absmin'}[self.special_comboBox.currentIndex()] + + if len(self.pts) != 0: + ret_dic['idx'] = self.pts + + if self.graph_checkbox.isChecked(): + gid = '' + else: + gid = self.graph_combobox.currentData() + + self.points_selected.emit(ret_dic, gid) + + return ret_dic + + def _update_region(self): + try: + idx = self.pts_lines.index(self.sender()) + except ValueError: + return + + self.pts[idx] = self.sender().getRegion() + self.peaktable.blockSignals(True) + self.peaktable.item(idx).setText('{:.5g} - {:.5g}'.format(*self.pts[idx])) + self.peaktable.blockSignals(False) + + def _update_line(self): + try: + idx = self.pts_lines.index(self.sender()) + except ValueError: + return + + self.pts[idx] = self.sender().value() + self.peaktable.blockSignals(True) + self.peaktable.item(idx).setText(f'{self.pts[idx]:.5g}') + self.peaktable.blockSignals(False) + + @QtCore.pyqtSlot(QtWidgets.QListWidgetItem) + def editing_started(self, item=None): + if item is None: + item = self.peaktable.selectedItems()[0] + self._prev_pos = item.text() + self.peaktable.editItem(item) + + @QtCore.pyqtSlot(QtWidgets.QListWidgetItem) + def editing_finished(self, it: QtWidgets.QListWidgetItem): + m = re.match(REGION_RE, it.text()).groupdict() + undo = True + if m: + start, stop = m['first'], m['second'] + row = self.peaktable.row(it) + it_pts = self.pts_lines[row] + if ((stop is None) and isinstance(it_pts, RegionItem)) or \ + ((stop is not None) and isinstance(it_pts, LogInfiniteLine)): + QtWidgets.QMessageBox().information(self, 'Invalid type', + 'Conversion between point and region is not possible.') + else: + if stop is None: + it_pts.blockSignals(True) + it_pts.setValue(float(start)) + it_pts.blockSignals(False) + self.pts[row] = float(start) + else: + start, stop = float(start), float(stop) + pos = (min(start, stop), max(start, stop)) + self.pts[row] = pos + self.peaktable.blockSignals(True) + it.setText(f'{pos[0]:.5g} - {pos[1]:.5g}') + self.peaktable.blockSignals(False) + it_pts.blockSignals(True) + it_pts.setRegion(pos) + it_pts.blockSignals(False) + undo = False + + if undo: + self.peaktable.blockSignals(True) + it.setText(self._prev_pos) + self.peaktable.blockSignals(False) + + def set_graphs(self, graphs: list): + self.graph_combobox.clear() + for g in graphs: + self.graph_combobox.addItem(g[1], userData=g[0]) + + @QtCore.pyqtSlot(int, name='on_graph_checkbox_stateChanged') + def changed_state(self, checked): + self.graph_combobox.setEnabled(checked!=QtCore.Qt.Checked) diff --git a/nmreval/gui_qt/data/shift_graphs.py b/nmreval/gui_qt/data/shift_graphs.py new file mode 100644 index 0000000..0fa7f32 --- /dev/null +++ b/nmreval/gui_qt/data/shift_graphs.py @@ -0,0 +1,190 @@ +import numpy as np +from itertools import cycle + +from pyqtgraph import mkColor, mkPen + +from ...lib.colors import Tab10 +from ..Qt import QtGui, QtCore, QtWidgets +from .._py.shift_scale_dialog import Ui_shift_dialog +from ..lib.pg_objects import PlotItem +from ..lib.utils import SciSpinBox + + +class QShift(QtWidgets.QDialog, Ui_shift_dialog): + valuesChanged = QtCore.pyqtSignal(dict, tuple) + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.graphicsView.setMenuEnabled(False) + self.splitter.setSizes([int(self.width()/4), int(self.width()*2/3)]) + + self.movements = {} + self.data = {} + self._colors = cycle(Tab10) + + delegate = SpinBoxDelegate() + delegate.valueChanged.connect(self.shift) + self.shift_table.setItemDelegate(delegate) + self.x_shift_spinbox.valueChanged.connect(lambda: self.glob_shift('h')) + self.y_shift_spinbox.valueChanged.connect(lambda: self.glob_shift('v')) + + delegate = SpinBoxDelegate() + delegate.valueChanged.connect(self.scale) + self.scale_table.setItemDelegate(delegate) + self.x_scale_spinbox.valueChanged.connect(lambda: self.glob_scale('h')) + self.y_scale_spinbox.valueChanged.connect(lambda: self.glob_scale('v')) + + def add_item(self, idx, name, x, y): + color = mkColor(next(self._colors).rgb()) + if np.iscomplexobj(y): + pl = [PlotItem(x, y.real, name=name, pen=mkPen(color=color)), + PlotItem(x, y.imag, name=name, pen=mkPen(color=color))] + else: + pl = [PlotItem(x, y, name=name, pen=mkPen(color=color))] + + self.data[idx] = (pl, x, y) + + # [[horizontal shift, vertical shift], [horizontal scale, vertical scale]] + self.movements[idx] = [[0, 0], [1, 1]] + + for i, tw in enumerate([self.shift_table, self.scale_table]): + tw.blockSignals(True) + row = tw.rowCount() + tw.insertRow(row) + + item = QtWidgets.QTableWidgetItem(name) + item.setForeground(QtGui.QBrush(color)) + item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled) + item.setCheckState(QtCore.Qt.Checked) + item.setData(QtCore.Qt.UserRole, idx) + tw.setItem(row, 0, item) + + tw.setItem(row, 1, QtWidgets.QTableWidgetItem(str(i))) + tw.setItem(row, 2, QtWidgets.QTableWidgetItem(str(i))) + + tw.blockSignals(False) + for i in pl: + self.graphicsView.addItem(i) + + def set_graphs(self, graphs: list): + for key, name in graphs: + self.data_combobox.addItem(name, userData=key) + self.values_combobox.addItem(name, userData=key) + + def glob_shift_scale(self, widget: QtWidgets.QTableWidget, mode: int, col: int, value: float): + for row in range(widget.rowCount()): + if widget.item(row, 0).checkState() == QtCore.Qt.Checked: + item = widget.item(row, col) + item.setText(str(value)) + self.shift_scale(widget, mode, row, col-1, value) + + def glob_shift(self, direction: str): + if direction == 'h': + val = self.x_shift_spinbox.value() + self.glob_shift_scale(self.shift_table, 0, 1, val) + else: + val = self.y_shift_spinbox.value() + self.glob_shift_scale(self.shift_table, 0, 2, val) + + def glob_scale(self, direction: str): + if direction == 'h': + val = self.x_scale_spinbox.value() + self.glob_shift_scale(self.scale_table, 1, 1, val) + else: + val = self.y_scale_spinbox.value() + self.glob_shift_scale(self.scale_table, 1, 2, val) + + def shift_scale(self, widget: QtWidgets.QTableWidget, mode: int, + row: int, col: int, value: float): + item = widget.item(row, 0) + key = item.data(QtCore.Qt.UserRole) + self.movements[key][mode][col] = value + + (x_off, y_off), (x_scale, y_scale) = self.movements[key] + + pl, x, y = self.data[key] + y_part = [np.real, np.imag] + for i, item in enumerate(pl): + item.setData(x=x*x_scale+x_off, y=y_part[i](y) * y_scale + y_off) + + @QtCore.pyqtSlot(int, int, float) + def shift(self, row: int, column: int, value: float): + self.shift_scale(self.shift_table, 0, row, column-1, value) + + @QtCore.pyqtSlot(int, int, float) + def scale(self, row: int, column: int, value: float): + self.shift_scale(self.scale_table, 1, row, column-1, value) + + @QtCore.pyqtSlot(int, name='on_xlog_checkbox_stateChanged') + @QtCore.pyqtSlot(int, name='on_ylog_checkbox_stateChanged') + def set_log(self, state: int): + if self.sender() == self.xlog_checkbox: + log_state = self.graphicsView.plotItem.ctrl.logXCheck + else: + log_state = self.graphicsView.plotItem.ctrl.logYCheck + log_state.setCheckState(state) + self.graphicsView.plotItem.updateLogMode() + + def on_overwrite_checkbox_stateChanged(self, state: int): + self.data_newgraph.setVisible(state != QtCore.Qt.Checked) + self.data_combobox.setVisible(state != QtCore.Qt.Checked) + + def on_value_checkbox_stateChanged(self, state: int): + self.values_newgraph.setVisible(state == QtCore.Qt.Checked) + self.values_combobox.setVisible(state == QtCore.Qt.Checked) + + def on_data_newgraph_stateChanged(self, state: int): + self.data_combobox.setEnabled(state != QtCore.Qt.Checked) + + def on_values_newgraph_stateChanged(self, state: int): + self.values_combobox.setEnabled(state != QtCore.Qt.Checked) + + def accept(self): + data_saving = None + if not self.overwrite_checkbox.isChecked(): + if self.data_newgraph.isChecked(): + data_saving = '' + else: + data_saving = self.data_combobox.currentData() + + value_saving = None + if self.value_checkbox.isChecked(): + if self.values_newgraph.isChecked(): + value_saving = '' + else: + value_saving = self.values_combobox.currentData() + + self.valuesChanged.emit(self.movements, (data_saving, value_saving)) + self.close() + + +class SpinBoxDelegate(QtWidgets.QStyledItemDelegate): + valueChanged = QtCore.pyqtSignal(int, int, float) + + def createEditor(self, parent: QtWidgets.QWidget, option: QtWidgets.QStyleOptionViewItem, + idx: QtCore.QModelIndex) -> QtWidgets.QWidget: + editor = SciSpinBox(parent) + editor.valueChanged.connect(self.new_value) + + return editor + + def new_value(self, val): + # geht bestimmt besser... + table = self.sender().parent().parent() + self.valueChanged.emit(table.currentRow(), table.currentColumn(), val) + + +if __name__ == '__main__': + import sys + + app = QtWidgets.QApplication(sys.argv) + mplQt = QShift() + xx = np.geomspace(1, 100) + mplQt.add_item('aa', 'a', xx, xx/(1+xx**2)*10) + mplQt.add_item('bb', 'b', xx, xx/(1+(0.1*xx)**2)) + mplQt.add_item('cc', 'c', xx, xx/(1+(0.01*xx)**2)/10) + mplQt.set_graphs([('123', 'zyx'), ('456', 'wvu')]) + mplQt.show() + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/data/signaledit/__init__.py b/nmreval/gui_qt/data/signaledit/__init__.py new file mode 100644 index 0000000..b92851f --- /dev/null +++ b/nmreval/gui_qt/data/signaledit/__init__.py @@ -0,0 +1,2 @@ +from .phase_dialog import QApodDialog, QPhasedialog +from .baseline_dialog import QBaselineDialog diff --git a/nmreval/gui_qt/data/signaledit/baseline_dialog.py b/nmreval/gui_qt/data/signaledit/baseline_dialog.py new file mode 100644 index 0000000..c231cd7 --- /dev/null +++ b/nmreval/gui_qt/data/signaledit/baseline_dialog.py @@ -0,0 +1,92 @@ +import numpy as np +import pyqtgraph as pg + +from scipy.interpolate import splrep, splev + +from ...Qt import QtCore, QtWidgets +from ..._py.baseline_dialog import Ui_SignalEdit + + +class QBaselineDialog(QtWidgets.QDialog, Ui_SignalEdit): + finished = QtCore.pyqtSignal(str, tuple) + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.data = None + + self.graph = pg.PlotDataItem(x=[], y=[], pen=pg.mkPen({'color': 'b'})) + self.graph_corr = pg.PlotDataItem(x=[], y=[], pen=pg.mkPen({'color': 'r'})) + self.baseline = pg.PlotDataItem(x=[], y=[]) + + self.anchors = [] + self.anchor_lines = [] + self.spline = None + + self.graphicsView.scene().sigMouseClicked.connect(self.add_node) + self.graphicsView.addItem(self.graph_corr) + self.graphicsView.addItem(self.graph) + self.graphicsView.addItem(self.baseline) + + def add_data(self, x, y): + if self.data is not None: + QtWidgets.QMessageBox().information(self, 'Invalid number of datasets', + 'Baseline correction is only working on one set at a time.') + self.close() + self.anchors.extend([np.min(x), np.max(x)]) + self.data = (x, y) + self.graph.setData(x=x, y=y.real) + self.graph_corr.setData(x=x, y=y.real) + + def accept(self): + self.finished.emit('bls', (splev(self.data[0], self.spline),)) + self.close() + + def add_node(self, evt): + vb = self.graphicsView.plotItem.vb + + if self.graphicsView.plotItem.sceneBoundingRect().contains(evt.scenePos()) and evt.button() == 1: + pos = vb.mapSceneToView(evt.scenePos()) + x = pos.x() + + self.anchors.append(x) + self.anchors.sort() + row = self.anchors.index(x) + self.listWidget.insertItem(row-1, QtWidgets.QListWidgetItem(str(x))) + + inf_line = pg.InfiniteLine(pos=x) + self.anchor_lines.insert(row-1, inf_line) + self.graphicsView.addItem(inf_line) + + self.change_baseline() + + def change_baseline(self): + if self.data: + x, y = self.data + + def mean(xx): + return np.mean(y[max(0, np.argmin(abs(x-xx))-5):min(len(x), np.argmin(abs(x-xx))+6)].real) + + y_node = [mean(x_node) for x_node in self.anchors] + try: + self.spline = splrep(self.anchors, y_node, per=False) + except TypeError: + self.spline = splrep(self.anchors, y_node, per=False, k=1) + + bl = splev(x, self.spline) + + self.baseline.setData(x=x, y=bl) + self.graph_corr.setData(x=x, y=y.real-bl) + + def keyPressEvent(self, evt): + if self.listWidget.hasFocus() and evt.key() == QtCore.Qt.Key_Delete: + r = self.listWidget.currentRow() + self.anchors.pop(r+1) + listitem = self.listWidget.takeItem(r) + del listitem + self.graphicsView.removeItem(self.anchor_lines.pop(r)) + self.change_baseline() + + else: + super().keyPressEvent(evt) diff --git a/nmreval/gui_qt/data/signaledit/editsignalwidget.py b/nmreval/gui_qt/data/signaledit/editsignalwidget.py new file mode 100644 index 0000000..23bb9cd --- /dev/null +++ b/nmreval/gui_qt/data/signaledit/editsignalwidget.py @@ -0,0 +1,92 @@ +from ....math import apodization +from ....lib.importer import find_models +from ....utils.text import convert + +from ...Qt import QtCore, QtWidgets, QtGui +from ...lib.forms import FormWidget +from ..._py.editsignalwidget import Ui_Form + + +class EditSignalWidget(QtWidgets.QWidget, Ui_Form): + do_something = QtCore.pyqtSignal(str, tuple) + get_values = QtCore.pyqtSignal() + preview_triggered = QtCore.pyqtSignal(str) + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.apodlist = find_models(apodization) + + self.lineEdit.hide() + self.lineEdit.setValidator(QtGui.QDoubleValidator()) + + for ap in self.apodlist: + self.apodcombobox.addItem(str(ap().name)) + self.change_apodization(0) + + self.baselinebutton.clicked.connect(lambda: self.apply_changes('bl')) + self.zfbutton.clicked.connect(lambda: self.apply_changes('zf')) + self.phasebutton.clicked.connect(lambda: self.apply_changes('ph')) + self.apodbutton.clicked.connect(lambda: self.apply_changes('ap')) + self.leftshiftbutton.clicked.connect(lambda: self.apply_changes('ls')) + self.fourierutton.clicked.connect(lambda: self.apply_changes('ft')) + + self.pushButton.clicked.connect(lambda: self.preview_triggered.emit('ap')) + self.pushButton_2.clicked.connect(lambda: self.preview_triggered.emit('ph')) + + @QtCore.pyqtSlot(str) + def apply_changes(self, sender): + if sender in ['bl', 'zf', 'ft']: + self.do_something.emit(sender, tuple()) + + elif sender == 'ls': + if self.comboBox.currentIndex() == 0: + _nop = int(self.lsspinBox.text()) + stype = 'pts' + else: + try: + _nop = float(self.lineEdit.text()) + except ValueError: + _nop = 0.0 + stype = 'time' + self.do_something.emit(sender, (_nop, stype)) + + elif sender == 'ap': + apodmodel = self.apodlist[self.apodcombobox.currentIndex()] + p = [float(x.text()) for x in self.groupBox_3.findChildren(QtWidgets.QLineEdit)] + self.do_something.emit(sender, (p, apodmodel)) + + elif sender == 'ph': + ph0 = float(self.ph0slider.value()) + ph1 = float(self.ph1slider.value()) + pvt = float(self.pivot_lineedit.text()) + self.do_something.emit(sender, (ph0, ph1, pvt)) + + else: + print('You should never reach this by accident.') + + @QtCore.pyqtSlot(int, name='on_apodcombobox_currentIndexChanged') + def change_apodization(self, index): + apod_func = self.apodlist[index] + self.label_2.setText(convert(apod_func.equation)) + + while self.verticalLayout_8.count(): + item = self.verticalLayout_8.takeAt(0) + try: + item.widget().deleteLater() + except AttributeError: + pass + + for k, v in enumerate(apod_func.params): + widgt = FormWidget(name=v) + self.verticalLayout_8.addWidget(widgt) + + @QtCore.pyqtSlot(int, name='on_comboBox_currentIndexChanged') + def change_ls(self, idx): + if idx: + self.lineEdit.show() + self.lsspinBox.hide() + else: + self.lineEdit.hide() + self.lsspinBox.show() diff --git a/nmreval/gui_qt/data/signaledit/phase_dialog.py b/nmreval/gui_qt/data/signaledit/phase_dialog.py new file mode 100644 index 0000000..0f89208 --- /dev/null +++ b/nmreval/gui_qt/data/signaledit/phase_dialog.py @@ -0,0 +1,196 @@ +import numpy as np +import pyqtgraph as pg +from numpy import inf, linspace +from numpy.fft import fft, fftfreq, fftshift + +from ....lib.importer import find_models +from ....math import apodization as apodization +from ....utils.text import convert + +from ...Qt import QtCore, QtWidgets +from ..._py.apod_dialog import Ui_ApodEdit +from ..._py.phase_corr_dialog import Ui_SignalEdit +from ...lib.forms import FormWidget + + +class QPreviewDialogs(QtWidgets.QDialog): + finished = QtCore.pyqtSignal(str, tuple) + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.data = [] + self.graphs = [] + + self.mode = '' + + def add_data(self, x, y): + self.data.append((x, y)) + real_plt = pg.PlotDataItem(x=x, y=y.real, pen=pg.mkColor('b')) + imag_plt = pg.PlotDataItem(x=x, y=y.imag, pen=pg.mkColor('r')) + self.graphs.append((real_plt, imag_plt)) + self.graphicsView.addItem(real_plt) + self.graphicsView.addItem(imag_plt) + + def done(self, val): + self.cleanup() + super().done(val) + + def close(self): + self.cleanup() + super().close() + + def accept(self): + self.finished.emit(self.mode, self.get_value()) + super().accept() + + def get_value(self): + raise NotImplementedError + + def cleanup(self): + self.blockSignals(True) + + for line in self.graphs: + for g in line: + self.graphicsView.removeItem(g) + del g + + self.graphicsView.clear() + + self.data = [] + self.graphs = [] + + self.blockSignals(False) + + +class QPhasedialog(QPreviewDialogs, Ui_SignalEdit): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.mode = 'ph' + + self.pvt_line = pg.InfiniteLine(pos=0, movable=True) + self.graphicsView.addItem(self.pvt_line) + self.pvt_line.sigPositionChanged.connect(self.move_line) + + @QtCore.pyqtSlot(float, name='on_ph1slider_valueChanged') + @QtCore.pyqtSlot(float, name='on_ph0slider_valueChanged') + def _temp_phase(self, *args): + ph0, ph1, pvt = self.get_value() + self.pvt_line.setValue(pvt) + + for i, (x, y) in enumerate(self.data): + phasecorr = np.exp(1j * (ph0 + ph1*(x-pvt)/np.max(x))*np.pi/180.) + _y = y * phasecorr + + self.graphs[i][0].setData(x=x, y=_y.real) + self.graphs[i][1].setData(x=x, y=_y.imag) + + def get_value(self): + return float(self.ph0slider.text()), float(self.ph1slider.text()), float(self.pivot_lineedit.text()) + + def move_line(self, evt): + self.pivot_lineedit.setText(str(int(evt.value()))) + + +class QApodDialog(QPreviewDialogs, Ui_ApodEdit): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self._limits = (-inf, inf), -inf + + self.apods = [] + self.apods = find_models(apodization) + + self.apodcombobox.blockSignals(True) + for ap in self.apods: + self.apodcombobox.addItem(ap().name) + self.apodcombobox.blockSignals(False) + + self.apod_graph = pg.PlotDataItem(x=[], y=[]) + self.graphicsView.addItem(self.apod_graph) + + self.mode = 'ap' + + self.change_apodization(0) + + def add_data(self, x, y): + real_plt = pg.PlotDataItem(x=x, y=y.real, pen=pg.mkPen('b')) + # imag_plt = pg.PlotDataItem(x=x, y=y.imag, pen=pg.mkPen('r')) + self.graphicsView.addItem(real_plt) + # self.graphicsView.addItem(imag_plt) + + y_fft = fftshift(fft(y)) + x_fft = fftshift(fftfreq(len(x), d=x[1]-x[0])) + real_plt_fft = pg.PlotDataItem(x=x_fft, y=y_fft.real, pen=pg.mkPen('b')) + # imag_plt_fft = pg.PlotDataItem(x=x_fft, y=y_fft.imag, pen=pg.mkPen('b')) + self.graphicsView_2.addItem(real_plt_fft) + # self.graphicsView_2.addItem(imag_plt_fft) + + self.graphs.append((real_plt, real_plt_fft)) + self.data.append((x, y, x_fft)) + + xlimits = (max(x.min(), self._limits[0][0]), min(x.max(), self._limits[0][1])) + ylimit = max(self._limits[1], y.real.max()) + self._limits = xlimits, ylimit + + @QtCore.pyqtSlot(int, name='on_apodcombobox_currentIndexChanged') + def change_apodization(self, index): + # delete old widgets + self.eqn_label.setText(convert(self.apods[index].equation)) + while self.widget_layout.count(): + item = self.widget_layout.takeAt(0) + try: + item.widget().deleteLater() + except AttributeError: + pass + + # set up parameter widgets for new model + for k, v in enumerate(self.apods[index]().params): + widgt = FormWidget(name=v) + widgt.valueChanged.connect(self._temp_apod) + self.widget_layout.addWidget(widgt) + + self.widget_layout.addStretch() + self._temp_apod() + + def _temp_apod(self): + apodmodel = self.apods[self.apodcombobox.currentIndex()] + p = self._get_parameter() + + if self.data: + for i, (x, y, x_fft) in enumerate(self.data): + y2 = apodmodel.apod(x, *p) + _y = y2 * y + self.graphs[i][0].setData(x=x, y=_y.real) + # self.graphs[i][1].setData(y=_y.imag) + y_fft = fftshift(fft(_y)) + self.graphs[i][1].setData(x=x_fft, y=y_fft.real) + # self.graphs[i][3].setData(y=y_fft.imag) + + _x_apod = linspace(self._limits[0][0], self._limits[0][1]) + try: + _y_apod = apodmodel.apod(_x_apod, *p) + self.apod_graph.setData(x=_x_apod, y=self._limits[1]*_y_apod) + except IndexError: + pass + + def _get_parameter(self): + p = [] + for i in range(self.widget_layout.count()): + item = self.widget_layout.itemAt(i) + w = item.widget() + try: + p.append(w.value) + except AttributeError: + continue + + return p + + def get_value(self): + apodmodel = self.apods[self.apodcombobox.currentIndex()] + p = self._get_parameter() + + return p, apodmodel diff --git a/nmreval/gui_qt/data/valueeditwidget.py b/nmreval/gui_qt/data/valueeditwidget.py new file mode 100644 index 0000000..f79e32c --- /dev/null +++ b/nmreval/gui_qt/data/valueeditwidget.py @@ -0,0 +1,336 @@ +from typing import Union, List + +import numpy as np + +from ..Qt import QtGui, QtCore, QtWidgets +from .._py.valueeditor import Ui_MaskDialog + + +class ValueEditWidget(QtWidgets.QWidget, Ui_MaskDialog): + requestData = QtCore.pyqtSignal(str) + maskSignal = QtCore.pyqtSignal(str, list) + itemChanged = QtCore.pyqtSignal(str, tuple, object) + itemDeleted = QtCore.pyqtSignal(str, list) + itemAdded = QtCore.pyqtSignal(str) + values_selected = QtCore.pyqtSignal(str, list, list) + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.setupUi(self) + + self.graph_shown = None + self.shown_set = None + self.items = {} + + self.model = ValueModel() + self.model.itemChanged.connect(self.update_items) + + self.selection_model = QtCore.QItemSelectionModel(self.model) + self.selection_model.selectionChanged.connect(self.show_position) + + self.tableView.setModel(self.model) + self.tableView.setSelectionModel(self.selection_model) + self.tableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) + self.tableView.customContextMenuRequested.connect(self.ctx) + + self.comboBox.currentIndexChanged.connect(self._populate_sets) + self.comboBox_2.currentIndexChanged.connect(self._populate_table) + + def __call__(self, items: dict): + self.items = items + + self.comboBox.blockSignals(True) + self.comboBox.clear() + for k, v in items.items(): + self.comboBox.addItem(k[1], userData=k[0]) + self.comboBox.blockSignals(False) + + idx = self.comboBox.findData(self.graph_shown) + if idx == -1: + idx = 0 + + self.comboBox.setCurrentIndex(idx) + self.comboBox.currentIndexChanged.emit(idx) + + return self + + @QtCore.pyqtSlot(int) + def _populate_sets(self, idx: int): + if idx == -1: + self.comboBox.setCurrentIndex(0) + return + + self.comboBox_2.blockSignals(True) + self.comboBox_2.clear() + self.graph_shown = self.comboBox.currentData() + + if self.items: + for sid, name in self.items[(self.comboBox.currentData(), self.comboBox.currentText())]: + self.comboBox_2.addItem(name, userData=sid) + self.comboBox_2.blockSignals(False) + + sidx = self.comboBox_2.findData(self.shown_set) + if sidx == -1: + sidx = 0 + + self.comboBox_2.setCurrentIndex(sidx) + self.comboBox_2.currentIndexChanged.emit(sidx) + + @QtCore.pyqtSlot(int) + def _populate_table(self, idx): + self.selection_model.clearSelection() + self.shown_set = self.comboBox_2.itemData(idx) + self.requestData.emit(self.comboBox_2.itemData(idx)) + + def set_data(self, data: list, mask: np.ndarray): + self.selection_model.clearSelection() + self.model.loadData(data, mask) + self.spinBox.setMaximum(self.model.rowCount()) + + def ctx(self, pos: QtCore.QPoint): + idx = self.tableView.indexAt(pos) + if not idx.isValid(): + return + + menu = QtWidgets.QMenu() + menu.addSeparator() + + hide_action = menu.addAction('Hide/Show') + menu.addSeparator() + del_action = menu.addAction('Delete') + menu.addSeparator() + cpc_action = menu.addAction('Copy to clipboard') + action = menu.exec(self.tableView.viewport().mapToGlobal(pos)) + + if action == hide_action: + self.mask_row() + elif action == del_action: + self.delete_item() + elif action == cpc_action: + self.copy_selection() + + def keyPressEvent(self, evt): + if evt.matches(QtGui.QKeySequence.Copy): + self.copy_selection() + elif evt.key() == QtCore.Qt.Key_Delete: + self.delete_item() + else: + super().keyPressEvent(evt) + + def copy_selection(self) -> str: + table = '' + for r in self.selection_model.selectedRows(): + table += self.model.data(r) + '\t' + table += '\t'.join([self.model.data(r.sibling(r.row(), i)) for i in [1, 2]]) + '\n' + + QtWidgets.QApplication.clipboard().setText(table) + + return table + + @QtCore.pyqtSlot(name='on_mask_button_clicked') + def mask_row(self): + for r in self.selection_model.selectedRows(): + self.model.setData(r, not self.model.data(r, ValueModel.maskRole), ValueModel.maskRole) + self.maskSignal.emit(self.comboBox_2.currentData(), self.model.mask) + + @QtCore.pyqtSlot(name='on_unmaskbutton_clicked') + def unmask(self): + self.model.unmask() + self.maskSignal.emit(self.comboBox_2.currentData(), self.model.mask) + + @QtCore.pyqtSlot(name='on_delete_button_clicked') + def delete_item(self): + idx = [r.row() for r in self.selection_model.selectedRows()] + success = False + for i in sorted(idx, reverse=True): + success = self.model.removeRow(i) + + if success: + self.itemDeleted.emit(self.comboBox_2.currentData(), idx) + self.spinBox.setMaximum(self.spinBox.maximum()-len(idx)) + + @QtCore.pyqtSlot(name='on_add_button_clicked') + def new_value(self): + success = self.model.addRows() + if success: + self.spinBox.setMaximum(self.spinBox.maximum()+1) + self.itemAdded.emit(self.comboBox_2.currentData()) + + @QtCore.pyqtSlot(int, int, str) + def update_items(self, col, row, val): + sid = self.comboBox_2.currentData() + new_value = complex(val) + new_value = new_value.real if new_value.imag == 0 else new_value + + self.itemChanged.emit(sid, (col, row), new_value) + + @QtCore.pyqtSlot(QtCore.QItemSelection, QtCore.QItemSelection) + def show_position(self, items_selected, items_deselected): + xvals = [] + yvals = [] + for idx in self.selection_model.selectedRows(): + xvals.append(float(self.model.data(idx))) + try: + yvals.append(float(self.model.data(idx.sibling(idx.row(), 1)))) + except ValueError: + yvals.append(complex(self.model.data(idx.sibling(idx.row(), 1))).real) + + self.values_selected.emit(self.graph_shown, xvals, yvals) + + @QtCore.pyqtSlot(name='on_toolButton_clicked') + def goto(self): + self.tableView.scrollTo(self.model.index(self.spinBox.value()-1, 0)) + + +class ValueModel(QtCore.QAbstractTableModel): + """ + TableModel with lazy loading + """ + itemChanged = QtCore.pyqtSignal(int, int, str) + load_number = 20 + maskRole = QtCore.Qt.UserRole+321 + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self._data = None + self.total_rows = 0 + self.rows_loaded = 0 + self.mask = None + self.headers = ['x', 'y', '\u0394y'] + for i, hd in enumerate(self.headers): + self.setHeaderData(i, QtCore.Qt.Horizontal, hd) + + def rowCount(self, *args, **kwargs) -> int: + return self.total_rows + + def columnCount(self, *args, **kwargs) -> int: + return len(self.headers) + + def loadData(self, data: List[np.ndarray], mask: np.ndarray): + self.beginResetModel() + self._data = [] + for x, y, y_err in zip(*data): + self._data.append([x, y, y_err]) + self.total_rows = len(self._data) + + self.mask = mask.tolist() + + self.endResetModel() + self.dataChanged.emit(self.index(0, 0), self.index(0, 1), [QtCore.Qt.DisplayRole]) + + def data(self, idx: QtCore.QModelIndex, role=QtCore.Qt.DisplayRole) -> object: + if not idx.isValid(): + return + + row = idx.row() + if role in [QtCore.Qt.DisplayRole, QtCore.Qt.EditRole]: + val = self._data[row][idx.column()] + if isinstance(val, complex): + return f'{val.real:.8g}{val.imag:+.8g}j' + else: + return f'{val:.8g}' + + elif role == QtCore.Qt.BackgroundRole: + pal = QtGui.QGuiApplication.palette() + if not self.mask[row]: + return pal.color(QtGui.QPalette.Disabled, QtGui.QPalette.Base) + else: + return pal.color(QtGui.QPalette.Base) + + elif role == QtCore.Qt.ForegroundRole: + pal = QtGui.QGuiApplication.palette() + if not self.mask[row]: + return pal.color(QtGui.QPalette.Disabled, QtGui.QPalette.Text) + else: + return pal.color(QtGui.QPalette.Text) + + elif role == ValueModel.maskRole: + return self.mask[row] + + else: + return + + def setData(self, idx: QtCore.QModelIndex, value: Union[str, bool], role=QtCore.Qt.DisplayRole) -> object: + col, row = idx.column(), idx.row() + + if role == ValueModel.maskRole: + self.mask[row] = bool(value) + self.dataChanged.emit(self.index(0, 0), self.index(0, 1), [role]) + + return True + + if value: + if role == QtCore.Qt.EditRole: + try: + value = complex(value) + except ValueError: + # not a number + return False + self._data[row][col] = value.real if value.imag == 0 else value + self.itemChanged.emit(col, row, str(value)) + self.dataChanged.emit(self.index(0, 0), self.index(0, 1), [role]) + + else: + return super().setData(idx, value, role=role) + + return True + + else: + return False + + def headerData(self, section: int, orientation, role=QtCore.Qt.DisplayRole) -> object: + if role == QtCore.Qt.DisplayRole: + if orientation == QtCore.Qt.Horizontal: + return self.headers[section] + else: + return str(section+1) + + return + + def canFetchMore(self, idx: QtCore.QModelIndex) -> bool: + if not idx.isValid(): + return False + + return self.total_rows > self.rows_loaded + + def fetchMore(self, idx: QtCore.QModelIndex): + remaining = self.total_rows - self.rows_loaded + to_be_loaded = min(remaining, ValueModel.load_number) + + self.beginInsertRows(QtCore.QModelIndex(), self.rows_loaded, self.rows_loaded + to_be_loaded - 1) + self.rows_loaded += to_be_loaded + self.endInsertRows() + + def flags(self, idx: QtCore.QModelIndex) -> QtCore.Qt.ItemFlags: + return QtCore.QAbstractTableModel.flags(self, idx) | QtCore.Qt.ItemIsEditable + + def removeRows(self, pos: int, rows: int, parent=None, *args, **kwargs) -> bool: + self.beginRemoveRows(parent, pos, pos+rows-1) + + for _ in range(rows): + self._data.pop(pos) + self.mask.pop(pos) + + self.endRemoveRows() + return True + + def addRows(self, num=1): + return self.insertRows(self.rowCount(), num) + + def insertRows(self, pos: int, rows: int, parent=QtCore.QModelIndex(), *args, **kwargs): + self.beginInsertRows(parent, pos, pos+rows-1) + + for _ in range(rows): + self._data.insert(pos, [0.0] * self.columnCount()) + self.mask.insert(pos, True) + self.total_rows += rows + + self.endInsertRows() + + return True + + def unmask(self): + self.mask = [True] * self.total_rows + self.dataChanged.emit(self.index(0, 0), self.index(0, 1), [ValueModel.maskRole]) diff --git a/nmreval/gui_qt/fit/__init__.py b/nmreval/gui_qt/fit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nmreval/gui_qt/fit/fit_forms.py b/nmreval/gui_qt/fit/fit_forms.py new file mode 100644 index 0000000..958e883 --- /dev/null +++ b/nmreval/gui_qt/fit/fit_forms.py @@ -0,0 +1,453 @@ +from typing import Tuple, Union + +from ...utils.text import convert +from ..Qt import QtCore, QtWidgets, QtGui +from .._py.fitmodelwidget import Ui_FitParameter +from .._py.save_fitmodel_dialog import Ui_SaveDialog +from ..lib import get_icon + + +class FitModelWidget(QtWidgets.QWidget, Ui_FitParameter): + value_requested = QtCore.pyqtSignal(object) + value_changed = QtCore.pyqtSignal(str) + state_changed = QtCore.pyqtSignal() + + def __init__(self, label: str = 'Fitparameter', parent=None, fixed: bool = False): + super().__init__(parent) + self.setupUi(self) + + self.parametername.setText(label + ' ') + + validator = QtGui.QDoubleValidator() + validator.setDecimals(9) + self.parameter_line.setValidator(validator) + self.parameter_line.setText('1') + self.parameter_line.setMaximumWidth(60) + self.lineEdit.setMaximumWidth(60) + self.lineEdit_2.setMaximumWidth(60) + + self.label_3.setText(f'< {label} <') + + self.checkBox.stateChanged.connect(self.enableBounds) + self.global_checkbox.stateChanged.connect(lambda: self.state_changed.emit()) + self.parameter_line.values_requested.connect(lambda: self.value_requested.emit(self)) + self.parameter_line.editingFinished.connect(lambda: self.value_changed.emit(self.parameter_line.text())) + self.fixed_check.toggled.connect(self.set_fixed) + + if fixed: + self.fixed_check.hide() + + self.menu = QtWidgets.QMenu(self) + self.add_links() + + self.is_linked = None + self.parameter_pos = None + self.func_idx = None + + self._linetext = '1' + + @property + def name(self): + return convert(self.parametername.text().strip(), old='html', new='str') + + def set_parameter_string(self, p: str): + self.parameter_line.setText(str(p)) + self.parameter_line.setToolTip(str(p)) + + def set_bounds(self, lb: float, ub: float, cbox: bool = True): + self.checkBox.setCheckState(QtCore.Qt.Checked if cbox else QtCore.Qt.Unchecked) + for val, bds_line in [(lb, self.lineEdit), (ub, self.lineEdit_2)]: + if val is not None: + bds_line.setText(str(val)) + else: + bds_line.setText('') + + def enableBounds(self, value: int): + self.lineEdit.setEnabled(value == 2) + self.lineEdit_2.setEnabled(value == 2) + + def set_parameter(self, p: list, bds: Tuple[float, float, bool] = (None, None, False), + fixed: bool = False, glob: bool = False): + if p is None: + # bad hack: linked parameter return (None, linked parameter) + # if p is None -> parameter is linked to argument given by bds + self.link_parameter(linkto=bds) + else: + ptext = ' '.join([f'{pp:.4g}' for pp in p]) + + self.set_parameter_string(ptext) + + self.set_bounds(*bds) + + self.fixed_check.setCheckState(QtCore.Qt.Unchecked if fixed else QtCore.Qt.Checked) + self.global_checkbox.setCheckState(QtCore.Qt.Checked if glob else QtCore.Qt.Unchecked) + + def get_parameter(self): + if self.is_linked: + try: + p = float(self._linetext) + except ValueError: + p = 1.0 + else: + try: + p = float(self.parameter_line.text().replace(',', '.')) + except ValueError: + _ = QtWidgets.QMessageBox().warning(self, 'Invalid value', + f'{self.parametername.text()} contains invalid values', + QtWidgets.QMessageBox.Cancel) + return None + + if self.checkBox.isChecked(): + try: + lb = float(self.lineEdit.text().replace(',', '.')) + except ValueError: + lb = None + + try: + rb = float(self.lineEdit_2.text().replace(',', '.')) + except ValueError: + rb = None + else: + lb = rb = None + + bounds = (lb, rb) + + return p, bounds, not self.fixed_check.isChecked(), self.global_checkbox.isChecked(), self.is_linked + + @QtCore.pyqtSlot(bool) + def set_fixed(self, state: bool): + # self.global_checkbox.setVisible(not state) + self.frame.setVisible(not state) + + def add_links(self, parameter: dict = None): + if parameter is None: + parameter = {} + self.menu.clear() + + ac = QtWidgets.QAction('Link to...', self) + ac.triggered.connect(self.link_parameter) + self.menu.addAction(ac) + + for model_key, model_funcs in parameter.items(): + m = QtWidgets.QMenu('Model ' + model_key, self) + for func_name, func_params in model_funcs.items(): + m2 = QtWidgets.QMenu(func_name, m) + for p_name, idx in func_params: + ac = QtWidgets.QAction(p_name, m2) + ac.setData((model_key, *idx)) + ac.triggered.connect(self.link_parameter) + m2.addAction(ac) + m.addMenu(m2) + self.menu.addMenu(m) + + self.toolButton.setMenu(self.menu) + + @QtCore.pyqtSlot() + def link_parameter(self, linkto=None): + if linkto is None: + action = self.sender() + else: + action = False + for m in self.menu.actions(): + if m.menu(): + for a in m.menu().actions(): + if a.data() == linkto: + action = a + break + if action: + break + + if (self.func_idx, self.parameter_pos) == action.data(): + return + + try: + new_text = f'Linked to {action.parentWidget().title()}.{action.text()}' + self._linetext = self.parameter_line.text() + self.parameter_line.setText(new_text) + self.parameter_line.setEnabled(False) + self.global_checkbox.hide() + self.global_checkbox.blockSignals(True) + self.global_checkbox.setCheckState(QtCore.Qt.Checked) + self.global_checkbox.blockSignals(False) + self.frame.hide() + self.is_linked = action.data() + + except AttributeError: + self.parameter_line.setText(self._linetext) + self.parameter_line.setEnabled(True) + if self.fixed_check.isEnabled(): + self.global_checkbox.show() + self.frame.show() + self.is_linked = None + + self.state_changed.emit() + + +class QSaveModelDialog(QtWidgets.QDialog, Ui_SaveDialog): + def __init__(self, types=None, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + if types is None: + types = [] + + self.comboBox.blockSignals(True) + self.comboBox.addItems(types) + self.comboBox.addItem('New group...') + self.comboBox.blockSignals(False) + + self.frame.hide() + + @QtCore.pyqtSlot(int, name='on_comboBox_currentIndexChanged') + def new_group(self, idx: int): + if idx == self.comboBox.count() - 1: + self.frame.show() + else: + self.lineEdit_2.clear() + self.frame.hide() + + @QtCore.pyqtSlot(name='on_toolButton_clicked') + def accept_group(self): + self.comboBox.insertItem(self.comboBox.count() - 1, self.lineEdit_2.text()) + self.comboBox.setCurrentIndex(self.comboBox.count() - 2) + + def accept(self): + if self.lineEdit.text(): + self.close() + + +class FitModelTree(QtWidgets.QTreeWidget): + icons = ['plus', 'mal_icon', 'minus_icon', 'geteilt_icon'] + + treeChanged = QtCore.pyqtSignal() + itemRemoved = QtCore.pyqtSignal(int) + + counterRole = QtCore.Qt.UserRole + 1 + operatorRole = QtCore.Qt.UserRole + 2 + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setHeaderHidden(True) + self.setDragEnabled(True) + self.setDragDropMode(QtWidgets.QTreeWidget.InternalMove) + self.setDefaultDropAction(QtCore.Qt.MoveAction) + + self.itemSelectionChanged.connect(lambda: self.treeChanged.emit()) + + def keyPressEvent(self, evt): + operators = [QtCore.Qt.Key_Plus, QtCore.Qt.Key_Asterisk, + QtCore.Qt.Key_Minus, QtCore.Qt.Key_Slash] + + if evt.key() == QtCore.Qt.Key_Delete: + for item in self.selectedItems(): + self.remove_function(item) + + elif evt.key() == QtCore.Qt.Key_Space: + for item in self.treeWidget.selectedItems(): + item.setCheckState(0, QtCore.Qt.Checked) if item.checkState( + 0) == QtCore.Qt.Unchecked else item.setCheckState(0, QtCore.Qt.Unchecked) + + elif evt.key() in operators: + idx = operators.index(evt.key()) + for item in self.selectedItems(): + item.setData(0, self.operatorRole, idx) + item.setIcon(0, get_icon(self.icons[idx])) + + else: + super().keyPressEvent(evt) + + def dropEvent(self, evt: QtGui.QDropEvent): + super().dropEvent(evt) + self.treeChanged.emit() + + def remove_function(self, item: QtWidgets.QTreeWidgetItem): + """ + Remove function and children from tree and dictionary + """ + while item.childCount(): + self.remove_function(item.child(0)) + + if item.parent(): + item.parent().removeChild(item) + else: + self.invisibleRootItem().removeChild(item) + + idx = item.data(0, self.counterRole) + self.itemRemoved.emit(idx) + + def add_function(self, idx: int, cnt: int, op: int, name: str, color: Union[QtGui.QColor, str, tuple], + parent: QtWidgets.QTreeWidgetItem = None, children: list = None, active: bool = True, **kwargs): + """ + Add function to tree and dictionary of functions. + """ + if not isinstance(color, QtGui.QColor): + if isinstance(color, tuple): + color = QtGui.QColor.fromRgbF(*color) + else: + color = QtGui.QColor(color) + + it = QtWidgets.QTreeWidgetItem() + it.setData(0, QtCore.Qt.UserRole, idx) + it.setData(0, self.counterRole, cnt) + it.setData(0, self.operatorRole, op) + it.setText(0, name) + it.setForeground(0, QtGui.QBrush(color)) + + it.setIcon(0, get_icon(self.icons[op])) + it.setCheckState(0, QtCore.Qt.Checked if active else QtCore.Qt.Unchecked) + + if parent is None: + self.addTopLevelItem(it) + else: + parent.addChild(it) + + if children is not None: + for c in children: + self.add_function(**c, parent=it) + + self.setCurrentIndex(self.indexFromItem(it, 0)) + + def sizeHint(self): + w = super().sizeHint().width() + return QtCore.QSize(w, 100) + + def get_selected(self): + try: + it = self.selectedItems()[0] + function_nr = it.data(0, QtCore.Qt.UserRole) + idx = it.data(0, self.counterRole) + + except IndexError: + function_nr = None + idx = None + + return function_nr, idx + + def get_functions(self, full=True, parent=None, pos=-1, return_pos=False): + """ + Create nested list of functions in tree. Parameters saved are idx (Index of function in list of all functions), + cnt (counter of number to associate with functione values), ops (+, -, *, /), and maybe children. + """ + if parent is None: + parent = self.invisibleRootItem() + + funcs = [] + for i in range(parent.childCount()): + pos += 1 + it = parent.child(i) + + child = { + 'idx': it.data(0, QtCore.Qt.UserRole), + 'op': it.data(0, self.operatorRole), + 'pos': pos, + 'active': (it.checkState(0) == QtCore.Qt.Checked), + 'children': [] + } + + if full: + child['name'] = it.text(0) + child['cnt'] = it.data(0, self.counterRole) + child['color'] = it.foreground(0).color().getRgbF() + + if it.childCount(): + child['children'], pos = self.get_functions(full=full, parent=it, pos=pos, return_pos=True) + + funcs.append(child) + + if return_pos: + return funcs, pos + else: + return funcs + + +class FitTableWidget(QtWidgets.QTableWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.horizontalHeader().hide() + self.verticalHeader().hide() + self.setColumnCount(2) + self.setSelectionBehavior(QtWidgets.QTableWidget.SelectRows) + self.horizontalHeader().setStretchLastSection(True) + self.hideColumn(1) + + def add_model(self, idx: str): + model_count = 0 + for r in range(self.rowCount()): + cb = self.cellWidget(r, 1) + cb.addItem('Model ' + str(idx), userData=idx) + model_count = cb.count() + + if model_count > 2: + if self.isColumnHidden(1): + self.showColumn(1) + self.resizeColumnToContents(0) + self.setColumnWidth(1, self.columnWidth(0) - self.columnWidth(1)) + + def remove_model(self, idx: str): + model_count = 0 + for r in range(self.rowCount()): + cb = self.cellWidget(r, 1) + if cb.currentData() == idx: + cb.setCurrentIndex(0) + cb.removeItem(cb.findData(idx)) + model_count = cb.count() + + if model_count == 2: + self.hideColumn(1) + self.resizeColumnToContents(0) + + def load(self, set_ids: list): + self.blockSignals(True) + + while self.rowCount(): + self.removeRow(0) + + for (sid, name) in set_ids: + item = QtWidgets.QTableWidgetItem(name) + item.setCheckState(QtCore.Qt.Checked) + item.setData(QtCore.Qt.UserRole+1, sid) + row = self.rowCount() + self.setRowCount(row+1) + self.setItem(row, 0, item) + + item2 = QtWidgets.QTableWidgetItem('') + self.setItem(row, 1, item2) + cb = QtWidgets.QComboBox() + cb.addItem('Default') + self.setCellWidget(row, 1, cb) + + self.blockSignals(False) + + def collect_data(self, default=None, include_name=False): + + data = {} + + for i in range(self.rowCount()): + item = self.item(i, 0) + if item.checkState() == QtCore.Qt.Checked: + mod = self.cellWidget(i, 1).currentData() + if mod is None: + mod = default + + if include_name: + arg = (item.data(QtCore.Qt.UserRole+1), item.text()) + else: + arg = item.data(QtCore.Qt.UserRole+1) + + if mod not in data: + data[mod] = [] + data[mod].append(arg) + + return data + + def data_list(self, include_name: bool = True) -> list: + ret_val = [] + for i in range(self.rowCount()): + item = self.item(i, 0) + if include_name: + ret_val.append((item.data(QtCore.Qt.UserRole+1), item.text())) + else: + ret_val.append(item.data(QtCore.Qt.UserRole+1)) + + return ret_val diff --git a/nmreval/gui_qt/fit/fit_parameter.py b/nmreval/gui_qt/fit/fit_parameter.py new file mode 100644 index 0000000..96ff18b --- /dev/null +++ b/nmreval/gui_qt/fit/fit_parameter.py @@ -0,0 +1,250 @@ +from ...utils.text import convert +from ..Qt import QtWidgets, QtCore, QtGui +from .._py.fitfuncwidget import Ui_FormFit +from ..lib.forms import FormWidget, SelectionWidget +from .fit_forms import FitModelWidget + + +class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit): + value_requested = QtCore.pyqtSignal(int) + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.func = None + self.func_idx = None + self.max_width = QtCore.QSize(0, 0) + self.global_parameter = [] + self.data_parameter = [] + self.glob_values = None + self.data_values = {} + + self.scrollwidget.setLayout(QtWidgets.QVBoxLayout()) + self.scrollwidget2.setLayout(QtWidgets.QVBoxLayout()) + + def eventFilter(self, src: QtCore.QObject, evt: QtCore.QEvent): + if isinstance(evt, QtGui.QKeyEvent): + if (evt.key() == QtCore.Qt.Key_Right) and \ + (evt.modifiers() == QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier): + self.change_single_parameter(src.value, sender=src) + self.select_next_preview(1) + + return True + + elif (evt.key() == QtCore.Qt.Key_Left) and \ + (evt.modifiers() == QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier): + self.change_single_parameter(src.value, sender=src) + self.select_next_preview(-1) + + return True + + return super().eventFilter(src, evt) + + def load(self, data): + self.comboBox.blockSignals(True) + while self.comboBox.count(): + self.comboBox.removeItem(0) + + for sid, name in data: + self.comboBox.addItem(name, userData=sid) + self._make_parameter(sid) + self.comboBox.blockSignals(False) + + def set_function(self, func, idx): + self.func = func + self.func_idx = idx + + self.glob_values = [1] * len(func.params) + + for k, v in enumerate(func.params): + name = convert(v) + widgt = FitModelWidget(label=name, parent=self.scrollwidget) + widgt.parameter_pos = k + widgt.func_idx = idx + try: + widgt.set_bounds(*func.bounds[k], False) + except (AttributeError, IndexError): + pass + + size = widgt.parametername.sizeHint() + if self.max_width.width() < size.width(): + self.max_width = size + + widgt.state_changed.connect(self.set_global) + widgt.value_requested.connect(self.look_for_value) + widgt.value_changed.connect(self.change_global_parameter) + + self.global_parameter.append(widgt) + self.scrollwidget.layout().addWidget(widgt) + + widgt2 = FormWidget(name=name, fixable=False, parent=self.scrollwidget2) + widgt2.valueChanged.connect(self.change_single_parameter) + widgt2.installEventFilter(self) + self.scrollwidget2.layout().addWidget(widgt2) + self.data_parameter.append(widgt2) + + for w1, w2 in zip(self.global_parameter, self.data_parameter): + w1.parametername.setFixedSize(self.max_width) + w1.checkBox.setFixedSize(self.max_width) + w2.label.setFixedSize(self.max_width) + + if hasattr(func, 'choices') and func.choices is not None: + cbox = func.choices + for c in cbox: + widgt = SelectionWidget(*c) + widgt.selectionChanged.connect(self.change_global_choice) + self.global_parameter.append(widgt) + self.glob_values.append(widgt.value) + self.scrollwidget.layout().addWidget(widgt) + + widgt2 = SelectionWidget(*c) + widgt2.selectionChanged.connect(self.change_single_choice) + self.data_parameter.append(widgt2) + self.scrollwidget2.layout().addWidget(widgt2) + + for i in range(self.comboBox.count()): + self._make_parameter(self.comboBox.itemData(i)) + + self.scrollwidget.layout().addStretch(1) + self.scrollwidget2.layout().addStretch(1) + + def set_links(self, parameter): + for w in self.global_parameter: + if isinstance(w, FitModelWidget): + w.add_links(parameter) + + @QtCore.pyqtSlot(str) + def change_global_parameter(self, value: str): + idx = self.global_parameter.index(self.sender()) + self.glob_values[idx] = float(value) + if self.data_values[self.comboBox.currentData()][idx] is None: + self.data_parameter[idx].blockSignals(True) + self.data_parameter[idx].value = value + self.data_parameter[idx].blockSignals(False) + + @QtCore.pyqtSlot(str, object) + def change_global_choice(self, argname, value): + idx = self.global_parameter.index(self.sender()) + self.glob_values[idx] = value + if self.data_values[self.comboBox.currentData()][idx] is None: + self.data_parameter[idx].blockSignals(True) + self.data_parameter[idx].value = value + self.data_parameter[idx].blockSignals(False) + + def change_single_parameter(self, value, sender=None): + if sender is None: + sender = self.sender() + idx = self.data_parameter.index(sender) + self.data_values[self.comboBox.currentData()][idx] = value + + def change_single_choice(self, argname, value, sender=None): + if sender is None: + sender = self.sender() + idx = self.data_parameter.index(sender) + self.data_values[self.comboBox.currentData()][idx] = value + + @QtCore.pyqtSlot(object) + def look_for_value(self, sender): + self.value_requested.emit(self.global_parameter.index(sender)) + + @QtCore.pyqtSlot() + def set_global(self): + # disable single parameter if it is set global, enable if global is unset + widget = self.sender() + idx = self.global_parameter.index(widget) + enable = (widget.global_checkbox.checkState() == QtCore.Qt.Unchecked) and (widget.is_linked is None) + self.data_parameter[idx].setEnabled(enable) + + def select_next_preview(self, direction): + curr_idx = self.comboBox.currentIndex() + next_idx = (curr_idx + direction) % self.comboBox.count() + self.comboBox.setCurrentIndex(next_idx) + + @QtCore.pyqtSlot(int, name='on_comboBox_currentIndexChanged') + def change_data(self, idx: int): + # new dataset is selected, look for locally set parameter else use global values + sid = self.comboBox.itemData(idx) + if sid not in self.data_values: + self._make_parameter(sid) + + for i, value in enumerate(self.data_values[sid]): + w = self.data_parameter[i] + w.blockSignals(True) + if value is None: + w.value = self.glob_values[i] + else: + w.value = value + w.blockSignals(False) + + def _make_parameter(self, sid): + if sid not in self.data_values: + self.data_values[sid] = [None] * len(self.data_parameter) + + def get_parameter(self, use_func=None): + bds = [] + is_global = [] + is_fixed = [] + globs = [] + is_linked = [] + + for g in self.global_parameter: + if isinstance(g, FitModelWidget): + p_i, bds_i, fixed_i, global_i, link_i = g.get_parameter() + + globs.append(p_i) + bds.append(bds_i) + is_fixed.append(fixed_i) + is_global.append(global_i) + is_linked.append(link_i) + + lb, ub = list(zip(*bds)) + + data_parameter = {} + if use_func is None: + use_func = list(self.data_values.keys()) + + global_p = None + for sid, parameter in self.data_values.items(): + if sid not in use_func: + continue + + kw_p = {} + p = [] + if global_p is None: + global_p = {'p': [], 'idx': [], 'var': [], 'ub': [], 'lb': []} + + for i, (p_i, g) in enumerate(zip(parameter, self.global_parameter)): + if isinstance(g, FitModelWidget): + if (p_i is None) or is_global[i]: + p.append(globs[i]) + if is_global[i]: + if i not in global_p['idx']: + global_p['p'].append(globs[i]) + global_p['idx'].append(i) + global_p['var'].append(is_fixed[i]) + global_p['ub'].append(ub[i]) + global_p['lb'].append(lb[i]) + else: + p.append(p_i) + + try: + if p[i] > ub[i]: + raise ValueError(f'Parameter {g.name} is outside bounds ({lb[i]}, {ub[i]})') + except TypeError: + pass + try: + if p[i] < lb[i]: + raise ValueError(f'Parameter {g.name} is outside bounds ({lb[i]}, {ub[i]})') + except TypeError: + pass + + else: + if p_i is None: + kw_p[g.argname] = g.value + else: + kw_p[g.argname] = p_i + + data_parameter[sid] = (p, kw_p) + + return data_parameter, lb, ub, is_fixed, global_p, is_linked diff --git a/nmreval/gui_qt/fit/fitfunction.py b/nmreval/gui_qt/fit/fitfunction.py new file mode 100644 index 0000000..bff72d2 --- /dev/null +++ b/nmreval/gui_qt/fit/fitfunction.py @@ -0,0 +1,240 @@ +from itertools import cycle, count +from typing import List, Tuple, Union + +from nmreval.configs import config_paths +from ... import models +from ...lib.importer import find_models +from ...lib.colors import BaseColor, Tab10 +from ...utils.text import convert +from ..Qt import QtWidgets, QtCore, QtGui +from .._py.fitfunctionwidget import Ui_Form +from .fit_forms import FitModelTree +from ..lib import get_icon + + +class QFunctionWidget(QtWidgets.QWidget, Ui_Form): + func_cnt = count() + func_colors = cycle(Tab10) + op_names = ['plus_icon', 'mal_icon', 'minus_icon', 'geteilt_icon'] + + newFunction = QtCore.pyqtSignal(int, int) + treeChanged = QtCore.pyqtSignal() + itemRemoved = QtCore.pyqtSignal(int) + showFunction = QtCore.pyqtSignal(int) + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.setupUi(self) + self.functree = FitModelTree() + self.widget.setText('Model structure') + self.widget.addWidget(self.functree) + + self._types = [] + self.functions = find_models(models) + try: + self.functions += find_models(config_paths() / 'usermodels.py') + except FileNotFoundError: + pass + + for m in self.functions: + try: + m.type + except AttributeError: + m.type = 'Other' + + if m.type not in self._types: + self._types.append(m.type) + + self.typecomboBox.addItems(sorted(self._types)) + + self.functree.treeChanged.connect(lambda: self.treeChanged.emit()) + self.functree.itemRemoved.connect(self.remove_function) + + self.iscomplex = False + self.complex_widget.hide() + + for i, op_icon in enumerate(self.op_names): + self.operator_combobox.setItemIcon(i, get_icon(op_icon)) + + def __len__(self): + return self.use_combobox.count() + + @QtCore.pyqtSlot(int, name='on_typecomboBox_currentIndexChanged') + def change_group(self, idx: int): + """ + Change items in fitcombobox to new entries + """ + self.fitcomboBox.blockSignals(True) + while self.fitcomboBox.count(): + self.fitcomboBox.removeItem(0) + + selected_type = self.typecomboBox.itemText(idx) + for m in self.functions: + if m.type == selected_type: + self.fitcomboBox.addItem(m.name, userData=self.functions.index(m)) + self.fitcomboBox.blockSignals(False) + self.on_fitcomboBox_currentIndexChanged(0) + + @QtCore.pyqtSlot(int, name='on_fitcomboBox_currentIndexChanged') + def change_function(self, idx: int): + """ + Display new equation on changing function + """ + index = self.fitcomboBox.itemData(idx) + if self.functions: + fitfunc = self.functions[index] + try: + self.fitequation.setText(convert(fitfunc.equation)) + except AttributeError: + self.fitequation.setText('') + + @QtCore.pyqtSlot(name='on_use_function_button_clicked') + def new_function(self): + idx = self.fitcomboBox.itemData(self.fitcomboBox.currentIndex()) + cnt = next(self.func_cnt) + op = self.operator_combobox.currentIndex() + name = self.functions[idx].name + col = next(self.func_colors) + + self.newFunction.emit(idx, cnt) + + self.add_function(idx, cnt, op, name, col) + + def add_function(self, idx: int, cnt: int, op: int, + name: str, color: Union[str, Tuple[float, float, float], BaseColor], **kwargs): + """ + Add function to tree and dictionary of functions. + """ + if isinstance(color, BaseColor): + qcolor = QtGui.QColor.fromRgbF(*color.rgb(normed=True)) + elif isinstance(color, tuple): + qcolor = QtGui.QColor.fromRgbF(*color) + else: + qcolor = QtGui.QColor(color) + self.functree.add_function(idx, cnt, op, name, qcolor, **kwargs) + + self.use_combobox.addItem(name, userData=cnt) + + self.use_combobox.setItemData(self.use_combobox.count()-1, color, QtCore.Qt.DecorationRole) + self.use_combobox.setCurrentIndex(self.use_combobox.count() - 1) + + f = self.functions[idx] + if hasattr(f, 'iscomplex') and f.iscomplex: + self.iscomplex = True + self.complex_widget.show() + + @QtCore.pyqtSlot(int) + def remove_function(self, idx: int): + iterator = QtWidgets.QTreeWidgetItemIterator(self.functree) + self.iscomplex = False + while iterator.value(): + item = iterator.value() + f = self.functions[item.data(0, QtCore.Qt.UserRole)] + if hasattr(f, 'iscomplex') and f.iscomplex: + self.iscomplex = True + break + + iterator += 1 + self.complex_widget.setVisible(self.iscomplex) + + for i in range(self.use_combobox.count()): + if idx == self.use_combobox.itemData(i): + self.use_combobox.removeItem(i) + break + + self.itemRemoved.emit(idx) + + @QtCore.pyqtSlot(int, name='on_use_combobox_currentIndexChanged') + def show_parameter(self, idx: int): + if self.use_combobox.count(): + self.showFunction.emit(self.use_combobox.itemData(idx, QtCore.Qt.UserRole)) + + def get_selected(self): + function_nr, idx = self.functree.get_selected() + + if function_nr is not None: + return self.functions[function_nr], idx + else: + return None, None + + def get_functions(self, full: bool = True, clsname=False, include_all: bool = True): + """ + Create nested list of functions in tree. Parameters saved are idx (Index of function in list of all functions), + cnt (counter of number to associate with functione values), ops (+, -, *, /), and maybe children. + """ + + used_functions = self.functree.get_functions(full=full) + self._prepare_function_for_model(used_functions, full=full, clsname=clsname, include_all=include_all) + + return used_functions + + def _prepare_function_for_model(self, func_list: List[dict], + full: bool = True, clsname: bool = False, include_all: bool = True): + + for func_args in func_list: + is_active = func_args.get('active') + if (not is_active) and (not include_all): + continue + + if not clsname: + func_args['func'] = self.functions[func_args['idx']] + else: + func_args['func'] = self.functions[func_args['idx']].name + + if not full: + func_args.pop('active') + func_args.pop('idx') + + if func_args['children']: + self._prepare_function_for_model(func_args['children'], + full=full, clsname=clsname, + include_all=include_all) + + def get_parameter_list(self): + all_parameters = {} + + iterator = QtWidgets.QTreeWidgetItemIterator(self.functree) + while iterator.value(): + item = iterator.value() + f = self.functions[item.data(0, QtCore.Qt.UserRole)] + cnt = item.data(0, self.functree.counterRole) + all_parameters[f'{f.name}_{cnt}'] = [(convert(pp, new='str'), (cnt, i)) for i, pp in enumerate(f.params)] + + iterator += 1 + + return all_parameters + + def get_complex_state(self): + return self.complex_comboBox.currentIndex() if self.iscomplex else None + + def set_complex_state(self, state): + if state is not None: + self.complex_comboBox.setCurrentIndex(state) + + def clear(self): + self.functree.blockSignals(True) + self.functree.clear() + self.functree.blockSignals(False) + + self.use_combobox.blockSignals(True) + self.use_combobox.clear() + self.use_combobox.blockSignals(False) + + self.complex_comboBox.setCurrentIndex(0) + self.complex_widget.hide() + + +if __name__ == '__main__': + import sys + from numpy.random import choice + + app = QtWidgets.QApplication(sys.argv) + qw = choice(QtWidgets.QStyleFactory.keys()) + + app.setStyle(QtWidgets.QStyleFactory.create(qw)) + + fd = QFunctionWidget() + fd.show() + + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/fit/fitwindow.py b/nmreval/gui_qt/fit/fitwindow.py new file mode 100644 index 0000000..55099a9 --- /dev/null +++ b/nmreval/gui_qt/fit/fitwindow.py @@ -0,0 +1,455 @@ +from itertools import count, cycle +from string import ascii_letters + +from pyqtgraph import PlotDataItem, mkPen + +from nmreval.gui_qt.lib.pg_objects import PlotItem +from ...fit._meta import MultiModel, ModelFactory +from ..Qt import QtGui, QtCore, QtWidgets +from .._py.fitdialog import Ui_FitDialog +from .fit_forms import FitTableWidget +from .fit_parameter import QFitParameterWidget + + +class QFitDialog(QtWidgets.QWidget, Ui_FitDialog): + func_cnt = count() + model_cnt = cycle(ascii_letters) + preview_num = 201 + + preview_emit = QtCore.pyqtSignal(dict, int, bool) + fitStartSig = QtCore.pyqtSignal(dict, list, dict) + abortFit = QtCore.pyqtSignal() + + def __init__(self, mgmt=None, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.parameters = {} + self.preview_lines = [] + self._current_function = None + self.function_widgets = {} + self._management = mgmt + + self._current_model = next(QFitDialog.model_cnt) + self.show_combobox.setItemData(0, self._current_model, QtCore.Qt.UserRole) + self.default_combobox.setItemData(0, self._current_model, QtCore.Qt.UserRole) + + self.data_table = FitTableWidget(self.data_widget) + self.data_widget.addWidget(self.data_table) + self.data_widget.setText('Data') + + self.models = {} + self._func_list = {} + self._complex = {} + + self.connected_figure = '' + + self.model_frame.hide() + self.preview_button.hide() + + self.abort_button.clicked.connect(lambda: self.abortFit.emit()) + + self.functionwidget.newFunction.connect(self.add_function) + self.functionwidget.showFunction.connect(self.show_function_parameter) + self.functionwidget.itemRemoved.connect(self.remove_function) + + @QtCore.pyqtSlot(int, int) + def add_function(self, function_idx: int, function_id: int): + self.show_function_parameter(function_id, function_idx) + self.newmodel_button.setEnabled(True) + + @QtCore.pyqtSlot(int) + def remove_function(self, idx: int): + """ + Remove function and children from tree and dictionary + """ + w = self.function_widgets[idx] + self.stackedWidget.removeWidget(w) + w.deleteLater() + del self.function_widgets[idx] + + if len(self.functionwidget) == 0: + # empty model + self.newmodel_button.setEnabled(False) + self.deletemodel_button.setEnabled(False) + self._current_function = None + + else: + self._current_function = self.functionwidget.use_combobox.currentData() + + @QtCore.pyqtSlot(int) + def show_function_parameter(self, function_id: int, function_idx: int = None): + """ + Display parameter associated with selected function. + """ + if function_id in self.function_widgets: + dialog = self.function_widgets[function_id] + + else: + # create new widget for function + if function_idx is not None: + function = self.functionwidget.functions[function_idx] + else: + raise ValueError('No function index given') + + if function is None: + return + + dialog = QFitParameterWidget() + data_names = self.data_table.data_list(include_name=True) + + dialog.set_function(function, function_idx) + dialog.load(data_names) + dialog.value_requested.connect(self.look_value) + + self.stackedWidget.addWidget(dialog) + self.function_widgets[function_id] = dialog + + self.stackedWidget.setCurrentWidget(dialog) + + # collect parameter names etc. to allow linkage + self._func_list[self._current_model] = self.functionwidget.get_parameter_list() + dialog.set_links(self._func_list) + + # show same tab (general parameter/Data parameter) + tab_idx = 0 + if self._current_function is not None: + tab_idx = self.function_widgets[self._current_function].tabWidget.currentIndex() + dialog.tabWidget.setCurrentIndex(tab_idx) + + self._current_function = function_id + + def look_value(self, idx): + func_widget = self.function_widgets[self._current_function] + set_ids = [func_widget.comboBox.itemData(i) for i in range(func_widget.comboBox.count())] + for s in set_ids: + func_widget.data_values[s][idx] = self._management[s].value + func_widget.change_data(func_widget.comboBox.currentIndex()) + + def get_functions(self): + """ update functions, parameters""" + self.models[self._current_model] = self.functionwidget.get_functions() + self._complex[self._current_model] = self.functionwidget.get_complex_state() + self._func_list[self._current_model] = self.functionwidget.get_parameter_list() + + def load(self, ids: list): + """ + Add name and id of dataset to list. + """ + self.data_table.load(ids) + if self.models: + for m in self.models.keys(): + self.data_table.add_model(m) + else: + self.data_table.add_model(self._current_model) + + for dialog in self.function_widgets.values(): + dialog.load(ids) + + @QtCore.pyqtSlot(name='on_newmodel_button_clicked') + def make_new_model(self): + """ + Save model with all its functions in dictionary and adjust gui. + """ + self.deletemodel_button.setEnabled(True) + self.model_frame.show() + idx = next(QFitDialog.model_cnt) + + self.data_table.add_model(idx) + + self.default_combobox.addItem('Model '+idx, userData=idx) + self.show_combobox.addItem('Model '+idx, userData=idx) + self.show_combobox.setItemData(self.show_combobox.count()-1, idx, QtCore.Qt.UserRole) + self.show_combobox.setCurrentIndex(self.show_combobox.count()-1) + + self._current_model = idx + self.stackedWidget.setCurrentIndex(0) + + @QtCore.pyqtSlot(int, name='on_show_combobox_currentIndexChanged') + def change_model(self, idx: int): + """ + Save old model and display new model. + """ + self.get_functions() + self.functionwidget.clear() + + self._current_model = self.show_combobox.itemData(idx, QtCore.Qt.UserRole) + if self._current_model in self.models and len(self.models[self._current_model]): + for el in self.models[self._current_model]: + self.functionwidget.add_function(**el) + self.functionwidget.set_complex_state(self._complex[self._current_model]) + else: + self.stackedWidget.setCurrentIndex(0) + + @QtCore.pyqtSlot(name='on_deletemodel_button_clicked') + def remove_model(self): + model_id = self._current_model + + self.show_combobox.removeItem(self.show_combobox.findData(model_id)) + self.default_combobox.removeItem(self.default_combobox.findData(model_id)) + + for m in self.models[model_id]: + func_id = m['cnt'] + self.stackedWidget.removeWidget(self.function_widgets[func_id]) + + self.function_widgets.pop(func_id) + + self._complex.pop(model_id) + self._func_list.pop(model_id) + self.models.pop(model_id) + + self.data_table.remove_model(model_id) + + if len(self.models) == 1: + self.model_frame.hide() + + def _prepare(self, model: list, function_use=None, parameter=None, add_idx=False, cnt=0): + if parameter is None: + parameter = {'parameter': {}, 'lb': (), 'ub': (), 'var': [], + 'glob': {'idx': [], 'p': [], 'var': [], 'lb': [], 'ub': []}, + 'links': [], 'color': []} + + for i, f in enumerate(model): + if not f['active']: + continue + try: + p, lb, ub, var, glob, links = self.function_widgets[f['cnt']].get_parameter(function_use) + except ValueError as e: + _ = QtWidgets.QMessageBox().warning(self, 'Invalid value', str(e), + QtWidgets.QMessageBox.Ok) + return None, -1 + + p_len = len(parameter['lb']) + + parameter['lb'] += lb + parameter['ub'] += ub + parameter['var'] += var + parameter['links'] += links + parameter['color'] += [f['color']] + + for p_k, v_k in p.items(): + if add_idx: + kw_k = {f'{k}_{cnt}': v for k, v in v_k[1].items()} + else: + kw_k = v_k[1] + + if p_k in parameter['parameter']: + params, kw = parameter['parameter'][p_k] + params += v_k[0] + kw.update(kw_k) + else: + parameter['parameter'][p_k] = (v_k[0], kw_k) + + for g_k, g_v in glob.items(): + if g_k != 'idx': + parameter['glob'][g_k] += g_v + else: + parameter['glob']['idx'] += [idx_i + p_len for idx_i in g_v] + + if add_idx: + cnt += 1 + + if f['children']: + # recurse for children + child_parameter, cnt = self._prepare(f['children'], parameter=parameter, add_idx=add_idx, cnt=cnt) + + return parameter, cnt + + @QtCore.pyqtSlot(name='on_fit_button_clicked') + def start_fit(self): + self.get_functions() + + data = self.data_table.collect_data(default=self.default_combobox.currentData()) + + func_dict = {} + for k, mod in self.models.items(): + func, order, param_len = ModelFactory.create_from_list(mod) + + if func is None: + continue + + if k in data: + parameter, _ = self._prepare(mod, function_use=data[k], add_idx=isinstance(func, MultiModel)) + if parameter is None: + return + + parameter['func'] = func + parameter['order'] = order + parameter['len'] = param_len + if self._complex[k] is None: + parameter['complex'] = self._complex[k] + else: + parameter['complex'] = ['complex', 'real', 'imag'][self._complex[k]] + + func_dict[k] = parameter + + replaceable = [] + for k, v in func_dict.items(): + for i, link_i in enumerate(v['links']): + if link_i is None: + continue + + rep_model, rep_func, rep_pos = link_i + try: + f = func_dict[rep_model] + except KeyError: + QtWidgets.QMessageBox().warning(self, 'Invalid value', + 'Parameter cannot be linked: Model is unused', + QtWidgets.QMessageBox.Ok) + return + + try: + f_idx = f['order'].index(rep_func) + except ValueError: + QtWidgets.QMessageBox().warning(self, 'Invalid value', + 'Parameter cannot be linked: ' + 'Function is probably not checked or deleted', + QtWidgets.QMessageBox.Ok) + return + + repl_idx = sum(f['len'][:f_idx])+rep_pos + if repl_idx not in f['glob']['idx']: + _ = QtWidgets.QMessageBox().warning(self, 'Invalid value', + 'Parameter cannot be linked: ' + 'Destination is not a global parameter.', + QtWidgets.QMessageBox.Ok) + return + + replaceable.append((k, i, rep_model, repl_idx)) + + replace_value = None + for p_k in f['parameter'].values(): + replace_value = p_k[0][repl_idx] + break + + if replace_value is not None: + for p_k in v['parameter'].values(): + p_k[0][i] = replace_value + + weight = ['None', 'y', 'y2', 'Deltay'][self.weight_combobox.currentIndex()] + + fit_args = {'we': weight} + + if func_dict: + self.fitStartSig.emit(func_dict, replaceable, fit_args) + + return func_dict + + @QtCore.pyqtSlot(int, name='on_preview_checkbox_stateChanged') + def show_preview(self, state: int): + print('state', state) + if state: + self.preview_button.show() + self.preview_checkbox.setText('') + + self._prepare_preview() + + else: + self.preview_emit.emit({}, -1, False) + self.preview_lines = [] + self.preview_button.hide() + self.preview_checkbox.setText('Preview') + + @QtCore.pyqtSlot(name='on_preview_button_clicked') + def _prepare_preview(self): + self.get_functions() + + default_model = self.default_combobox.currentData() + data = self.data_table.collect_data(default=default_model) + + func_dict = {} + for k, mod in self.models.items(): + func, order, param_len = ModelFactory.create_from_list(mod) + multiple_funcs = isinstance(func, MultiModel) + + if k in data: + parameter, _ = self._prepare(mod, function_use=data[k], add_idx=multiple_funcs) + parameter['func'] = func + parameter['order'] = order + parameter['len'] = param_len + + func_dict[k] = parameter + + for v in func_dict.values(): + for i, link_i in enumerate(v['links']): + if link_i is None: + continue + + rep_model, rep_func, rep_pos = link_i + f = func_dict[rep_model] + f_idx = f['order'].index(rep_func) + repl_idx = sum(f['len'][:f_idx]) + rep_pos + + replace_value = None + for p_k in f['parameter'].values(): + replace_value = p_k[0][repl_idx] + break + + if replace_value is not None: + for p_k in v['parameter'].values(): + p_k[0][i] = replace_value + + self.preview_emit.emit(func_dict, QFitDialog.preview_num, True) + + def make_previews(self, x, models_parameters: dict): + self.preview_lines = [] + + for k, model in models_parameters.items(): + f = model['func'] + is_complex = self._complex[k] + + parameters = model['parameter'] + color = model['color'] + + for p, kwargs in parameters.values(): + y = f.func(x, *p, **kwargs) + if is_complex is None: + self.preview_lines.append(PlotItem(x=x, y=y, pen=mkPen(width=3))) + + elif is_complex == 0: + self.preview_lines.append(PlotItem(x=x, y=y.real, pen=mkPen(width=3))) + self.preview_lines.append(PlotItem(x=x, y=y.imag, pen=mkPen(width=3))) + elif is_complex == 1: + self.preview_lines.append(PlotItem(x=x, y=y.real, pen=mkPen(width=3))) + else: + self.preview_lines.append(PlotItem(x=x, y=y.imag, pen=mkPen(width=3))) + + if isinstance(f, MultiModel): + for i, s in enumerate(f.subs(x, *p, **kwargs)): + pen_i = mkPen(QtGui.QColor.fromRgbF(*color[i])) + if is_complex is None: + self.preview_lines.append(PlotItem(x=x, y=s, pen=pen_i)) + elif is_complex == 0: + self.preview_lines.append(PlotItem(x=x, y=s.real, pen=pen_i)) + self.preview_lines.append(PlotItem(x=x, y=s.imag, pen=pen_i)) + elif is_complex == 1: + self.preview_lines.append(PlotItem(x=x, y=s.real, pen=pen_i)) + else: + self.preview_lines.append(PlotItem(x=x, y=s.imag, pen=pen_i)) + + return self.preview_lines + + def closeEvent(self, evt: QtGui.QCloseEvent): + self.preview_emit.emit({}, -1, False) + self.preview_lines = [] + + super().closeEvent(evt) + + +if __name__ == '__main__': + import sys + from numpy.random import choice + + app = QtWidgets.QApplication(sys.argv) + # while qw == 'QtCurve': + qw = choice(QtWidgets.QStyleFactory.keys()) + app.setStyle(QtWidgets.QStyleFactory.create(qw)) + + fd = QFitDialog() + + fd.load([('fff', 'testtesttesttest'), + ('ggg', 'testtesttesttesttest'), + ('hhh', 'testtesttesttesttesttest')]) + fd.show() + + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/fit/function_creation_dialog.py b/nmreval/gui_qt/fit/function_creation_dialog.py new file mode 100644 index 0000000..0a9f07b --- /dev/null +++ b/nmreval/gui_qt/fit/function_creation_dialog.py @@ -0,0 +1,247 @@ +import re + +import numexpr as ne +import numpy as np + +from nmreval.gui_qt.Qt import QtCore, QtWidgets +from nmreval.gui_qt._py.fitcreationdialog import Ui_Dialog + + +_numexpr_funcs = [] +for k, _ in ne.expressions.functions.items(): + pat = k + r'\(' + _numexpr_funcs.append((re.compile(pat), 'np.' + k + '(')) + + +class QUserFitCreator(QtWidgets.QDialog, Ui_Dialog): + classCreated = QtCore.pyqtSignal(object) + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.namespace_widget.make_namespace() + + self.tableWidget.itemChanged.connect(self.update_function) + + self.groupBox.toggled.connect(self.change_visibility) + self.groupBox_2.toggled.connect(self.change_visibility) + self.groupBox_3.toggled.connect(self.change_visibility) + self.groupBox_4.toggled.connect(self.change_visibility) + + self.groupBox.setChecked(True) + + def __call__(self, *args, **kwargs): + for w in [self.lineEdit_4, self.lineEdit, self.lineEdit_3, self.lineEdit_2, + self.parameterLineEdit, self.externalParametersLineEdit]: + w.clear() + + def check(self): + self.name = self.name_lineedit.text() + self.group = self.group_lineedit.text() + self.eq = str(self.lineEdit.text()) + self.p = str(self.parameterLineEdit.text()).split() + self.func = str(self.lineEdit_4.text()) + self._func_string = '' + + error = [] + for k, v in [('Name', self.name), ('Group', self.group), ('Parameters', self.p), ('Function', self.func)]: + if not v: + error.append('Empty ' + str(k)) + if self.name: + if self.name[0].isdigit(): + error.append('Name starts with digit') + if self.p: + if set(self.p) & set(self.ext_p): + error.append('Duplicate entries: {}'.format(list(set(self.p) & set(self.ext_p)))) + if self.p and self.func: + p_test = np.ones((len(self.p)+len(self.ext_p))) + _x = np.arange(2) + namespace = {'x': _x} + for i, pp in enumerate(p_test): + namespace[f'p_{i}'] = pp + self._func_string = self.func + '' + self._func_string = self._func_string.replace('[', '_').replace(']', '') + try: + ne.evaluate(self._func_string, local_dict=namespace) + except KeyError: + error.append(f'Incorrect evaluation {self.func}') + + if error: + QtWidgets.QMessageBox().warning(self, 'Invalid entries', '\n'.join(error)) + else: + return True + + def accept(self): + self.confirm() + super().accept() + + def confirm(self): + print(f' name = {self.name_lineedit.text()}') + group_type = self.group_lineedit.text() + if group_type: + print(f' group = "{group_type}"') + else: + print(' group = "User-defined"') + var = [] + for row in range(self.tableWidget.rowCount()): + var.append(self.tableWidget.item(row, 1).text()) + if var: + print(' params = [r"', end='') + print('", r"'.join(var) + '"]') + else: + print(' params = []') + + print('\n@staticmethod') + print(self.label.text()) + import inspect + for k, v in self.namespace_widget.namespace.flatten().items(): + if inspect.isfunction(v): + print(k, inspect.getmodule(v)) + print(k, [cc[1] for cc in inspect.getmembers(v) if cc[0] == '__qualname__']) + else: + print(k, v) + print(self.plainTextEdit.toPlainText()) + + @QtCore.pyqtSlot(name='on_parameter_button_clicked') + def add_variable(self): + self.tableWidget.blockSignals(True) + row = self.tableWidget.rowCount() + self.tableWidget.setRowCount(row+1) + + self.tableWidget.setItem(row, 0, QtWidgets.QTableWidgetItem('p'+str(row))) + self.tableWidget.setItem(row, 1, QtWidgets.QTableWidgetItem('p_{'+str(row)+'}')) + self.tableWidget.setItem(row, 2, QtWidgets.QTableWidgetItem('--')) + self.tableWidget.setItem(row, 3, QtWidgets.QTableWidgetItem('--')) + self.tableWidget.blockSignals(False) + self.update_function(None) + + @QtCore.pyqtSlot(name='on_selection_button_clicked') + def add_choice(self): + cnt = self.tabWidget.count() + self.tabWidget.addTab(ChoiceWidget(self), 'choice' + str(cnt)) + self.tabWidget.setCurrentIndex(cnt) + + def register(self): + i = 0 + basename = self.name.replace(' ', '') + classname = basename + # while classname in _userfits: + # classname = basename + '_' + str(i) + # i += 1 + c = register_class(classname, self.name, self.group, self.p, self.eq, self._func_string) + self.classCreated.emit(c) + return classname, c + + def save(self, cname): + t = '\n# Created automatically\n' \ + 'class {cname:}(object):\n'\ + ' name = "{name:}"\n' \ + ' type = "{group:}"\n'\ + ' equation = "{eq:}"\n'\ + ' params = {p:}\n' \ + ' ext_params = {ep:}\n\n' \ + ' @staticmethod\n' \ + ' def func(p, x):\n' \ + ' return {func:}\n' + f_string = self.func + for pat, repl in _numexpr_funcs: + f_string = re.sub(pat, repl, f_string) + + @QtCore.pyqtSlot(QtWidgets.QTableWidgetItem) + @QtCore.pyqtSlot(str) + def update_function(self, _): + var = [] + for row in range(self.tableWidget.rowCount()): + var.append(self.tableWidget.item(row, 0).text()) + + if self.use_nuclei.isChecked(): + var.append('nucleus=2.67522128e8') + + # for row in range(self.selection_combobox.count()): + # var.append(self.selection_combobox.itemText(row) + '=') + + self.label.setText('def func(x, ' + ', '.join(var) + '):') + + def change_visibility(self): + sender = self.sender() + + for gb in [self.groupBox, self.groupBox_2, self.groupBox_3, self.groupBox_4]: + gb.blockSignals(True) + gb.setChecked(sender == gb) + gb.blockSignals(False) + + self.widget_2.setVisible(sender == self.groupBox) + self.widget_3.setVisible(sender == self.groupBox_2) + self.widget.setVisible(sender == self.groupBox_3) + self.namespace_widget.setVisible(sender == self.groupBox_4) + + +class ChoiceWidget(QtWidgets.QWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + + self._init_ui() + + def _init_ui(self): + layout = QtWidgets.QGridLayout() + layout.setContentsMargins(3, 3, 3, 3) + layout.setHorizontalSpacing(6) + + self.label = QtWidgets.QLabel('Name', parent=self) + layout.addWidget(self.label, 0, 0) + self.name_line = QtWidgets.QLineEdit(self) + layout.addWidget(self.name_line, 0, 1) + + self.label_2 = QtWidgets.QLabel('Displayed name', parent=self) + layout.addWidget(self.label_2, 0, 2) + self.display_line = QtWidgets.QLineEdit(self) + layout.addWidget(self.display_line, 0, 3) + + self.label_3 = QtWidgets.QLabel('Type', parent=self) + layout.addWidget(self.label_3) + self.types = QtWidgets.QComboBox(self) + self.types.addItems(['str', 'int', 'float']) + layout.addWidget(self.types) + + self.add_button = QtWidgets.QPushButton('Add option') + layout.addWidget(self.add_button) + + self.table = QtWidgets.QTableWidget(self) + self.table.setColumnCount(2) + self.table.setHorizontalHeaderLabels(['Name', 'Value']) + layout.addWidget(self.table, 2, 0, 1, 4) + + self.setLayout(layout) + + +def register_class(cname, name, group, p, eq, func): + c = type(cname, (), {}) + c.name = name + c.type = group + c.params = p + c.equation = eq + c.func = func_decorator(func) + + return c + + +def func_decorator(f_string): + # we need this decorator because the result is used in a class + + def wrapped_f(*args): + namespace = {'x': args[1]} + for i, pp in enumerate(args[0]): + namespace['p_{}'.format(i)] = pp + return ne.evaluate(f_string, local_dict=namespace) + + return wrapped_f + + +if __name__ == '__main__': + import sys + + app = QtWidgets.QApplication([]) + w = QUserFitCreator() + w.show() + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/fit/result.py b/nmreval/gui_qt/fit/result.py new file mode 100644 index 0000000..3e9ede7 --- /dev/null +++ b/nmreval/gui_qt/fit/result.py @@ -0,0 +1,245 @@ +from math import isnan + +from numpy import r_ +from pyqtgraph import mkBrush + +from ..lib.utils import RdBuCMap +from ...utils.text import convert +from ..Qt import QtWidgets, QtGui, QtCore +from .._py.fitresult import Ui_Dialog +from ..lib.pg_objects import PlotItem + + +class QFitResult(QtWidgets.QDialog, Ui_Dialog): + closed = QtCore.pyqtSignal(dict, list) + redoFit = QtCore.pyqtSignal(dict) + + def __init__(self, results: list, management, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self._management = management + + self._prevs = {} + self._models = {} + + for (res, parts) in results: + idx = res.idx + print(parts) + data_k = management.data[idx] + + if res.name not in self._models: + self._models[res.name] = [] + + self._models[res.name].append(idx) + + self._prevs[idx] = [] + for fit in data_k.get_fits(): + self._prevs[idx].append((fit.name, fit.statistics, fit.nobs-fit.nvar)) + + self._results = {res.idx: res for (res, _) in results} + self._parts = {res.idx: parts for (res, parts) in results} + self._opts = [(False, False) for _ in range(len(self._results))] + + self.residplot = self.graphicsView.addPlot(row=0, col=0) + self.resid_graph = PlotItem(x=[], y=[], symbol='o', symbolPen=None, symbolBrush=mkBrush(color='r'), pen=None) + self.residplot.addItem(self.resid_graph) + self.residplot.setLabel('left', 'Residual') + + self.fitplot = self.graphicsView.addPlot(row=1, col=0) + self.data_graph = PlotItem(x=[], y=[], symbol='o', symbolPen=None, symbolBrush=mkBrush(color='r'), pen=None) + self.fitplot.addItem(self.data_graph) + self.fitplot.setLabel('left', 'Function') + + self.fit_graph = PlotItem(x=[], y=[]) + self.fitplot.addItem(self.fit_graph) + + self.cmap = RdBuCMap(vmin=-1, vmax=1) + + self.sets_comboBox.blockSignals(True) + for n in self._models.keys(): + self.sets_comboBox.addItem(n) + self.sets_comboBox.blockSignals(False) + + self.set_parameter(0) + self.buttonBox.accepted.connect(self.accept) + + self.param_tableWidget.horizontalHeader().sectionClicked.connect(self.show_results) + self.logy_box.stateChanged.connect(lambda x: self.fitplot.setLogMode(y=bool(x))) + + def add_graphs(self, graphs: list): + self.graph_comboBox.clear() + for (graph_id, graph_name) in graphs: + self.graph_comboBox.addItem(graph_name, userData=graph_id) + + @QtCore.pyqtSlot(int, name='on_graph_checkBox_stateChanged') + def change_graph(self, state: int): + self.graph_comboBox.setEnabled(state == QtCore.Qt.Unchecked) + + @QtCore.pyqtSlot(int, name='on_sets_comboBox_currentIndexChanged') + def set_parameter(self, idx: int): + model_name = self.sets_comboBox.itemText(idx) + sets = self._models[model_name] + self.param_tableWidget.setColumnCount(len(sets)) + + r = self._results[sets[0]] + self.param_tableWidget.setRowCount(len(r.parameter)) + + for i, pval in enumerate(r.parameter.values()): + name = pval.full_name + p_header = QtWidgets.QTableWidgetItem(convert(name, 'tex', 'html', brackets=False)) + self.param_tableWidget.setVerticalHeaderItem(i, p_header) + + for i, set_id in enumerate(sets): + data_i = self._management[set_id] + header_item = QtWidgets.QTableWidgetItem(data_i.name) + header_item.setData(QtCore.Qt.UserRole, set_id) + self.param_tableWidget.setHorizontalHeaderItem(i, header_item) + + res = self._results[set_id] + for j, pvalue in enumerate(res.parameter.values()): + item_text = f'{pvalue.value:.4g}' + if pvalue.error is not None: + item_text += f' \u00b1 {pvalue.error:.4g}' + self.param_tableWidget.setItem(2*j+1, i, QtWidgets.QTableWidgetItem('-')) + else: + self.param_tableWidget.setItem(2*j+1, i, QtWidgets.QTableWidgetItem()) + item = QtWidgets.QTableWidgetItem(item_text) + self.param_tableWidget.setItem(j, i, item) + + self.param_tableWidget.resizeColumnsToContents() + self.param_tableWidget.selectColumn(0) + self.show_results(0) + + @QtCore.pyqtSlot(int, name='on_reject_fit_checkBox_stateChanged') + @QtCore.pyqtSlot(int, name='on_del_prev_checkBox_stateChanged') + def change_opts(self, _): + idx = self.sets_comboBox.currentIndex() + + self._opts[idx] = (self.reject_fit_checkBox.checkState() == QtCore.Qt.Checked, + self.del_prev_checkBox.checkState() == QtCore.Qt.Checked) + + def show_results(self, idx: int): + set_id = self.param_tableWidget.horizontalHeaderItem(idx).data(QtCore.Qt.UserRole) + self.set_plot(set_id) + self.set_correlation(set_id) + self.set_statistics(set_id) + + def set_plot(self, idx: str): + res = self._results[idx] + iscomplex = res.iscomplex + + self.resid_graph.setData(x=res.x_data, y=res.residual) + if iscomplex == 'complex': + self.data_graph.setData(x=r_[res.x_data, res.x_data], + y=r_[res.y_data.real, res.y_data.imag]) + self.fit_graph.setData(x=r_[res.x, res.x], + y=r_[res.y.real, res.y.imag]) + else: + self.data_graph.setData(x=res.x_data, y=res.y_data) + self.fit_graph.setData(x=res.x, y=res.y) + + self.fitplot.setLogMode(x=res.islog) + self.residplot.setLogMode(x=res.islog) + + def set_correlation(self, idx: str): + while self.corr_tableWidget.rowCount(): + self.corr_tableWidget.removeRow(0) + + res = self._results[idx] + c = res.correlation_list() + for pi, pj, corr, pcorr in c: + cnt = self.corr_tableWidget.rowCount() + self.corr_tableWidget.insertRow(cnt) + self.corr_tableWidget.setItem(cnt, 0, QtWidgets.QTableWidgetItem(convert(pi, old='tex', new='html'))) + self.corr_tableWidget.setItem(cnt, 1, QtWidgets.QTableWidgetItem(convert(pj, old='tex', new='html'))) + + for i, val in enumerate([corr, pcorr]): + if isnan(val): + val = 1000. + val_item = QtWidgets.QTableWidgetItem(f'{val:.4g}') + val_item.setBackground(self.cmap.color(val)) + if abs(val) > 0.75: + val_item.setForeground(QtGui.QColor('white')) + self.corr_tableWidget.setItem(cnt, i+2, val_item) + + self.corr_tableWidget.resizeColumnsToContents() + + def set_statistics(self, idx: str): + while self.stats_tableWidget.rowCount(): + self.stats_tableWidget.removeRow(0) + + res = self._results[idx] + + self.stats_tableWidget.setColumnCount(1 + len(self._prevs[idx])) + self.stats_tableWidget.setRowCount(len(res.statistics)+3) + + it = QtWidgets.QTableWidgetItem(f'{res.dof}') + it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable) + self.stats_tableWidget.setVerticalHeaderItem(0, QtWidgets.QTableWidgetItem('DoF')) + self.stats_tableWidget.setItem(0, 0, it) + + for col, (name, _, dof) in enumerate(self._prevs[idx], start=1): + self.stats_tableWidget.setHorizontalHeaderItem(0, QtWidgets.QTableWidgetItem(name)) + it = QtWidgets.QTableWidgetItem(f'{dof}') + it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable) + self.stats_tableWidget.setItem(0, col, it) + + for row, (k, v) in enumerate(res.statistics.items(), start=1): + self.stats_tableWidget.setVerticalHeaderItem(row, QtWidgets.QTableWidgetItem(k)) + it = QtWidgets.QTableWidgetItem(f'{v:.4f}') + it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable) + self.stats_tableWidget.setItem(row, 0, it) + + best_idx = -1 + best_val = v + for col, (_, stats, _) in enumerate(self._prevs[idx], start=1): + if k in ['adj. R^2', 'R^2']: + best_idx = col if best_val < stats[k] else max(0, best_idx) + else: + best_idx = col if best_val > stats[k] else max(0, best_idx) + it = QtWidgets.QTableWidgetItem(f'{stats[k]:.4f}') + it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable) + self.stats_tableWidget.setItem(row, col, it) + + if best_idx > -1: + self.stats_tableWidget.item(row, best_idx).setBackground(QtGui.QColor('green')) + self.stats_tableWidget.item(row, best_idx).setForeground(QtGui.QColor('white')) + + row = self.stats_tableWidget.rowCount() - 2 + self.stats_tableWidget.setVerticalHeaderItem(row, QtWidgets.QTableWidgetItem('F')) + self.stats_tableWidget.setItem(row, 0, QtWidgets.QTableWidgetItem('-')) + + self.stats_tableWidget.setVerticalHeaderItem(row+1, QtWidgets.QTableWidgetItem('Pr(>F)')) + self.stats_tableWidget.setItem(row+1, 0, QtWidgets.QTableWidgetItem('-')) + + for col, (_, stats, dof) in enumerate(self._prevs[idx], start=1): + f_value, prob_f = res.f_test(stats['chi^2'], dof) + it = QtWidgets.QTableWidgetItem(f'{f_value:.4g}') + it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable) + self.corr_tableWidget.setItem(row, col, it) + + it = QtWidgets.QTableWidgetItem(f'{prob_f:.4g}') + it.setFlags(it.flags() ^ QtCore.Qt.ItemIsEditable) + if prob_f < 0.05: + it.setBackground(QtGui.QColor('green')) + it.setForeground(QtGui.QColor('white')) + self.stats_tableWidget.setItem(row+1, col, it) + + @QtCore.pyqtSlot(QtWidgets.QAbstractButton) + def on_buttonBox_clicked(self, button: QtWidgets.QAbstractButton): + button_type = self.buttonBox.standardButton(button) + + if button_type == self.buttonBox.Retry: + self.redoFit.emit(self._results) + + elif button_type == self.buttonBox.Ok: + graph = '' if self.graph_checkBox.checkState() == QtCore.Qt.Checked else self.graph_comboBox.currentData() + subplots = self.partial_checkBox.checkState() == QtCore.Qt.Checked + self._opts.extend([graph, subplots]) + self.closed.emit(self._results, self._opts) + + self.accept() + + else: + self.reject() diff --git a/nmreval/gui_qt/graphs/__init__.py b/nmreval/gui_qt/graphs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nmreval/gui_qt/graphs/graphwindow.py b/nmreval/gui_qt/graphs/graphwindow.py new file mode 100644 index 0000000..fab3989 --- /dev/null +++ b/nmreval/gui_qt/graphs/graphwindow.py @@ -0,0 +1,705 @@ +import itertools +import os +import uuid + +from math import isnan +from typing import List, Union + +from numpy import errstate, floor, log10 +from pyqtgraph import GraphicsObject, getConfigOption, mkColor + +from ..lib.pg_objects import RegionItem +from ...utils.text import convert +from ..Qt import QtCore, QtWidgets, QtGui +from .._py.graph import Ui_GraphWindow +from ..lib import make_action_icons +from ..lib.configurations import GraceMsgBox + + +class QGraphWindow(QtWidgets.QGraphicsView, Ui_GraphWindow): + mousePositionChanged = QtCore.pyqtSignal(float, float) + mouseDoubleClicked = QtCore.pyqtSignal() + positionClicked = QtCore.pyqtSignal(tuple, bool) + aboutToClose = QtCore.pyqtSignal(str) + + counter = itertools.count() + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self._bgcolor = mkColor(getConfigOption('background')) + self._fgcolor = mkColor(getConfigOption('foreground')) + self._prev_colors = mkColor('k'), mkColor('w') + + self._init_gui() + + make_action_icons(self) + + self.id = str(uuid.uuid4()) + + self.sets = [] + self.active = [] + + self.real_plots = {} + self.imag_plots = {} + self.error_plots = {} + + self._special_needs = [] + self.closable = True + + self.log = [False, False] + + self.scene = self.plotItem.scene() + self.scene.sigMouseMoved.connect(self.move_mouse) + + self.checkBox.stateChanged.connect(lambda x: self.legend.setVisible(x == QtCore.Qt.Checked)) + self.label_button.toggled.connect(lambda x: self.label_widget.setVisible(x)) + self.limit_button.toggled.connect(lambda x: self.limit_widget.setVisible(x)) + self.gridbutton.toggled.connect(lambda x: self.graphic.showGrid(x=x, y=x)) + self.logx_button.toggled.connect(lambda x: self.set_logmode(xmode=x)) + self.logy_button.toggled.connect(lambda x: self.set_logmode(ymode=x)) + self.graphic.plotItem.vb.sigRangeChanged.connect(self.update_limits) + self.listWidget.itemChanged.connect(self.show_legend) + + # reconnect "Export..." in context menu to our function + self.scene.contextMenu[0].disconnect() + self.scene.contextMenu[0].triggered.connect(self.export) + + def _init_gui(self): + self.setWindowTitle('Graph ' + str(next(QGraphWindow.counter))) + + self.label_widget.hide() + self.limit_widget.hide() + self.listWidget.hide() + self.checkBox.hide() + + self.plotItem = self.graphic.plotItem + for orient in ['top', 'bottom', 'left', 'right']: + self.plotItem.showAxis(orient) + ax = self.plotItem.getAxis(orient) + ax.enableAutoSIPrefix(False) + if orient == 'top': + ax.setStyle(showValues=False) + ax.setHeight(10) + elif orient == 'right': + ax.setStyle(showValues=False) + ax.setWidth(10) + + self.legend = self.plotItem.addLegend() + self.legend.setVisible(True) + # self.legend.setBrush(color=self._bgcolor) + self.legend.layout.setContentsMargins(1, 1, 1, 1) + + self.plotItem.setMenuEnabled(False, True) + self.plotItem.ctrl.logXCheck.blockSignals(True) + self.plotItem.ctrl.logYCheck.blockSignals(True) + + for lineedit in [self.xmin_lineedit, self.xmax_lineedit, self.ymin_lineedit, self.ymax_lineedit]: + lineedit.setValidator(QtGui.QDoubleValidator()) + + def __contains__(self, item: str): + return item in self.sets + + def __iter__(self): + return iter(self.active) + + def __len__(self): + return len(self.active) + + def curves(self): + for a in self.active: + if self.real_button.isChecked(): + if self.error_plots[a] is not None: + yield self.real_plots[a], self.error_plots[a] + else: + yield self.real_plots[a], + + if self.imag_button.isChecked() and self.imag_plots[a] is not None: + yield self.imag_plots[a], + + @property + def title(self): + return self.windowTitle() + + @title.setter + def title(self, value): + self.setWindowTitle(str(value)) + + @property + def ranges(self): + r = self.plotItem.getViewBox().viewRange() + for i in [0, 1]: + if self.log[i]: + r[i] = tuple([10**x for x in r[i]]) + else: + r[i] = tuple(r[i]) + + return tuple(r) + + def add(self, name: Union[str, List], plots: List): + if isinstance(name, str): + name = [name] + plots = [plots] + + for (real_plot, imag_plot, err_plot), n in zip(plots, name): + toplevel = len(self.sets) + self.sets.append(n) + + real_plot.setZValue(2*toplevel+1) + if imag_plot: + imag_plot.setZValue(2*toplevel+1) + if err_plot: + err_plot.setZValue(2*toplevel) + + self.real_plots[n] = real_plot + self.imag_plots[n] = imag_plot + self.error_plots[n] = err_plot + + list_item = QtWidgets.QListWidgetItem(real_plot.opts.get('name', '')) + list_item.setData(QtCore.Qt.UserRole, n) + list_item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable) + list_item.setCheckState(QtCore.Qt.Checked) + self.listWidget.addItem(list_item) + + self.show_item(name) + + def remove(self, name: Union[str, List]): + if isinstance(name, str): + name = [name] + + for n in name: + self.sets.remove(n) + + for plot in [self.real_plots, self.imag_plots, self.error_plots]: + self.graphic.removeItem(plot[n]) + + if n in self.active: + self.active.remove(n) + + # remove from label list + self.listWidget.blockSignals(True) + + for i in range(self.listWidget.count()-1, 0, -1): + item = self.listWidget.item(i) + if item.data(QtCore.Qt.UserRole) in name: + self.listWidget.takeItem(i) + + self.listWidget.blockSignals(False) + + self._update_zorder() + self.show_legend() + + def move_sets(self, sets, position): + move_plots = [] + move_items = [] + + self.listWidget.blockSignals(True) + + for s in sets: + idx = self.sets.index(s) + move_plots.append(self.sets.pop(idx)) + move_items.append(self.listWidget.takeItem(idx)) + + if position == -1: + self.sets.extend(move_plots) + for it in move_items: + self.listWidget.addItem(it) + else: + self.sets = self.sets[:position] + move_plots + self.sets[position:] + for it in move_items[::-1]: + self.listWidget.insertItem(position, it) + + self.listWidget.blockSignals(False) + self._update_zorder() + + def show_item(self, idlist: list): + if len(self.sets) == 0: + return + + for a in idlist: + if a not in self.active: + self.active.append(a) + + if self.imag_button.isChecked(): + item = self.imag_plots[a] + if (item is not None) and (item not in self.graphic.items()): + self.graphic.addItem(item) + + if self.real_button.isChecked(): + item = self.real_plots[a] + if item not in self.graphic.items(): + self.graphic.addItem(item) + + if self.error_button.isChecked(): + item = self.error_plots[a] + if (item is not None) and (item not in self.graphic.items()): + self.graphic.addItem(item) + + self.show_legend() + + def hide_item(self, idlist: list): + if len(self.sets) == 0: + return + + for r in idlist: + if r in self.active: + self.active.remove(r) + + for plt in [self.real_plots, self.imag_plots, self.error_plots]: + item = plt[r] + if item in self.graphic.items(): + self.graphic.removeItem(item) + + @QtCore.pyqtSlot(bool, name='on_imag_button_toggled') + @QtCore.pyqtSlot(bool, name='on_real_button_toggled') + def set_imag_visible(self, visible: bool): + if self.sender() == self.real_button: + plots = self.real_plots + other = self.imag_plots + if self.error_button.isChecked() and not visible: + self.error_button.setChecked(False) + else: + plots = self.imag_plots + other = self.real_plots + + if visible: + func = self.graphic.addItem + else: + func = self.graphic.removeItem + + for a in self.active: + item = plots[a] + other_item = other[a] + if (item is not None) and (other_item is not None): + func(item) + + self.show_legend() + + @QtCore.pyqtSlot(bool, name='on_error_button_toggled') + def show_errorbar(self, visible: bool): + if visible and not self.real_button.isChecked(): + # no errorbars without points + self.error_button.blockSignals(True) + self.error_button.setChecked(False) + self.error_button.blockSignals(False) + return + + if visible: + for a in self.active: + item = self.error_plots[a] + if (item is not None) and (item not in self.graphic.items()): + self.graphic.addItem(item) + else: + for a in self.active: + item = self.error_plots[a] + if (item is not None) and (item in self.graphic.items()): + self.graphic.removeItem(item) + + def add_external(self, item): + if isinstance(item, RegionItem) and item.first: + # Give regions nice values on first addition to a graph + x, _ = self.ranges + + if item.mode == 'mid': + onset = item.getRegion()[0] + if self.log[0]: + delta = log10(x[1]/x[0])/20 + span = (onset / 10**delta , onset * 10**delta) + else: + delta = x[1]-x[0] + span = (onset-delta/20, onset + delta/20) + elif item.mode == 'half': + span = (0.75*x[0]+0.25*x[1], 0.25*x[0]+0.75*x[1]) + else: + span = item.getRegion() + + item.setRegion(span) + item.first = False + + if item in self.graphic.items(): + return False + + if not hasattr(item, 'setLogMode'): + self._special_needs.append(item) + + self.graphic.addItem(item) + item.setZValue(1000) + + return True + + @QtCore.pyqtSlot(GraphicsObject) + def remove_external(self, item): + if item not in self.graphic.items(): + return False + + if item in self._special_needs: + self._special_needs.remove(item) + + self.graphic.removeItem(item) + + return True + + def closeEvent(self, evt: QtGui.QCloseEvent): + if not self.closable: + evt.ignore() + return + + res = QtWidgets.QMessageBox.Yes + if len(self.sets) != 0: + res = QtWidgets.QMessageBox.question(self, 'Plot not empty', 'Graph is not empty. Deleting with all data?', + QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) + + if res == QtWidgets.QMessageBox.Yes: + self.aboutToClose.emit(self.id) + evt.accept() + else: + evt.ignore() + + def move_mouse(self, evt): + vb = self.plotItem.getViewBox() + if self.plotItem.sceneBoundingRect().contains(evt): + pos = vb.mapSceneToView(evt) + if self.log[0]: + try: + _x = 10**(pos.x()) + except OverflowError: + _x = pos.x() + else: + _x = pos.x() + + if self.log[1]: + try: + _y = 10**(pos.y()) + except OverflowError: + _y = pos.y() + else: + _y = pos.y() + self.mousePositionChanged.emit(_x, _y) + + @QtCore.pyqtSlot(name='on_title_lineedit_returnPressed') + @QtCore.pyqtSlot(name='on_xaxis_linedit_returnPressed') + @QtCore.pyqtSlot(name='on_yaxis_linedit_returnPressed') + def labels_changed(self): + label = {self.title_lineedit: 'title', self.xaxis_linedit: 'x', self.yaxis_linedit: 'y'}[self.sender()] + self.set_label(**{label: self.sender().text()}) + + def set_label(self, x=None, y=None, title=None): + if title is not None: + self.plotItem.setTitle(convert(title, old='tex', new='html'), **{'size': '10pt', 'color': self._fgcolor}) + + if x is not None: + self.plotItem.setLabel('bottom', convert(x, old='tex', new='html'), + **{'font-size': '10pt', 'color': self._fgcolor.name()}) + + if y is not None: + self.plotItem.setLabel('left', convert(y, old='tex', new='html'), + **{'font-size': '10pt', 'color': self._fgcolor.name()}) + + def set_logmode(self, xmode: bool = None, ymode: bool = None): + r = self.ranges + + if xmode is None: + xmode = self.plotItem.ctrl.logXCheck.isChecked() + else: + self.plotItem.ctrl.logXCheck.setCheckState(xmode) + + if ymode is None: + ymode = self.plotItem.ctrl.logYCheck.isChecked() + else: + self.plotItem.ctrl.logYCheck.setCheckState(ymode) + + self.log = [xmode, ymode] + + for item in self._special_needs: + item.logmode[0] = self.log[:] + + self.plotItem.updateLogMode() + + self.set_range(x=r[0], y=r[1]) + + def enable_picking(self, enabled: bool): + if enabled: + self.scene.sigMouseClicked.connect(self.position_picked) + else: + try: + self.scene.sigMouseClicked.disconnect() + except TypeError: + pass + + def position_picked(self, evt): + vb = self.graphic.plotItem.vb + + if self.graphic.plotItem.sceneBoundingRect().contains(evt.scenePos()) and evt.button() == 1: + pos = vb.mapSceneToView(evt.scenePos()) + _x, _y = pos.x(), pos.y() + + if self.log[0]: + _x = 10**_x + + if self.log[1]: + _y = 10**_y + + self.positionClicked.emit((_x, _y), evt.double()) + + @QtCore.pyqtSlot(name='on_apply_button_clicked') + def set_range(self, x: tuple = None, y: tuple = None): + if x is None: + x = float(self.xmin_lineedit.text()), float(self.xmax_lineedit.text()) + x = min(x), max(x) + + if y is None: + y = float(self.ymin_lineedit.text()), float(self.ymax_lineedit.text()) + y = min(y), max(y) + + for log, xy, func in zip(self.log, (x, y), (self.graphic.setXRange, self.graphic.setYRange)): + if log: + with errstate(all='ignore'): + xy = [log10(val) for val in xy] + + if isnan(xy[1]): + xy = [-1, 1] + elif isnan(xy[0]): + xy[0] = xy[1]-4 + + func(xy[0], xy[1], padding=0) + + @QtCore.pyqtSlot(object) + def update_limits(self, _): + r = self.ranges + self.xmin_lineedit.setText('%.5g' % r[0][0]) + self.xmax_lineedit.setText('%.5g' % r[0][1]) + + self.ymin_lineedit.setText('%.5g' % r[1][0]) + self.ymax_lineedit.setText('%.5g' % r[1][1]) + + def _update_zorder(self): + for i, sid in enumerate(self.sets): + plt = self.real_plots[sid] + if plt.zValue() != 2*i+1: + plt.setZValue(2*i+1) + if self.imag_plots[sid] is not None: + self.imag_plots[sid].setZValue(2*i+1) + if self.error_plots[sid] is not None: + self.error_plots[sid].setZValue(2*i) + + self.show_legend() + + @QtCore.pyqtSlot(bool, name='on_legend_button_toggled') + def show_legend_item_list(self, visible: bool): + self.listWidget.setVisible(visible) + self.checkBox.setVisible(visible) + + def update_legend(self, sid, name): + self.listWidget.blockSignals(True) + + for i in range(self.listWidget.count()): + item = self.listWidget.item(i) + if item.data(QtCore.Qt.UserRole) == sid: + item.setText(convert(name, old='tex', new='html')) + + self.listWidget.blockSignals(False) + self.show_legend() + + def show_legend(self): + if not self.legend.isVisible(): + return + + self.legend.clear() + + for i, sid in enumerate(self.sets): + item = self.real_plots[sid] + other_item = self.imag_plots[sid] + # should legend be visible? is either real part or imaginary part shown? + if self.listWidget.item(i).checkState() and \ + (item in self.graphic.items() or other_item in self.graphic.items()): + self.legend.addItem(item, convert(item.opts.get('name', ''), old='tex', new='html')) + + def export(self): + filters = 'All files (*.*);;AGR (*.agr);;SVG (*.svg);;PDF (*.pdf)' + for imgformat in QtGui.QImageWriter.supportedImageFormats(): + str_format = imgformat.data().decode('utf-8') + filters += ';;' + str_format.upper() + ' (*.' + str_format + ')' + + outfile, _ = QtWidgets.QFileDialog.getSaveFileName(self, caption='Export graphic', filter=filters, + options=QtWidgets.QFileDialog.DontConfirmOverwrite) + if outfile: + _, suffix = os.path.splitext(outfile) + if suffix == '': + QtWidgets.QMessageBox.warning(self, 'No file extension', + 'No file extension found, graphic was not saved.') + return + + if suffix == '.agr': + res = 0 + if os.path.exists(outfile): + res = GraceMsgBox(outfile, parent=self).exec() + if res == -1: + return + + opts = self.export_graphics() + + from ..io.exporters import GraceExporter + if res == 0: + mode = 'w' + elif res == 1: + mode = 'a' + else: + mode = res-2 + + GraceExporter(opts).export(outfile, mode=mode) + + else: + if os.path.exists(outfile): + if QtWidgets.QMessageBox.warning(self, 'Export graphic', + f'{os.path.split(outfile)[1]} already exists.\n' + f'Do you REALLY want to replace it?', + QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, + QtWidgets.QMessageBox.No) == QtWidgets.QMessageBox.No: + return + + bg_color = self._bgcolor + fg_color = self._fgcolor + self.set_color(foreground='k', background='w') + + if suffix == '.pdf': + from ..io.exporters import PDFPrintExporter + PDFPrintExporter(self.graphic).export(outfile) + + + elif suffix == '.svg': + from pyqtgraph.exporters import SVGExporter + SVGExporter(self.scene).export(outfile) + + else: + from pyqtgraph.exporters import ImageExporter + + ImageExporter(self.scene).export(outfile) + + self.set_color(foreground=fg_color, background=bg_color) + + def export_graphics(self): + dic = self.get_state() + dic['items'] = [] + + for item in self.curves(): + item_dic = item[0].get_data_opts() + if len(item) == 2: + # plot can show errorbars + item_dic['yerr'] = item[1].opts['topData'] + + if item_dic: + dic['items'].append(item_dic) + + return dic + + def get_state(self) -> dict: + dic = { + 'id': self.id, + 'limits': (self.ranges[0], self.ranges[1]), + 'ticks': (), + 'labels': (self.plotItem.getAxis('bottom').labelText, + self.plotItem.getAxis('left').labelText, + self.plotItem.titleLabel.text, + self.title), + 'log': self.log, + 'grid': self.gridbutton.isChecked(), + 'legend': self.legend.isVisible(), + 'plots': (self.real_button.isChecked(), self.imag_button.isChecked(), self.error_button.isChecked()), + 'children': self.sets, + 'active': self.active, + } + + in_legend = [] + for i in range(self.listWidget.count()): + in_legend.append(bool(self.listWidget.item(i).checkState())) + dic['in_legend'] = in_legend + + # bottomLeft gives top left corner + l_topleft = self.plotItem.vb.itemBoundingRect(self.legend).bottomLeft() + legend_origin = [l_topleft.x(), l_topleft.y()] + for i in [0, 1]: + if self.log[i]: + legend_origin[i] = 10**legend_origin[i] + dic['legend_pos'] = legend_origin + + for i, ax in enumerate(['bottom', 'left']): + if self.log[i]: + major = 10 + minor = 9 + else: + vmin, vmax = dic['limits'][i][0], dic['limits'][i][1] + dist = vmax - vmin + scale = 10**floor(log10(abs(dist))) + steps = [0.1, 0.2, 0.25, 0.5, 1., 2., 2.5, 5., 10., 20., 50., 100.] + for step_i in steps: + if dist / step_i / scale <= 10: + break + major = step_i * scale + minor = 1 + + dic['ticks'] += (major, minor), + + return dic + + @staticmethod + def set_state(state): + graph = QGraphWindow() + graph.id = state.get('id', graph.id) + + graph.plotItem.setLabel('bottom', state['labels'][0], **{'font-size': '10pt', 'color': graph._fgcolor.name()}) + graph.plotItem.setLabel('left', state['labels'][1], **{'font-size': '10pt', 'color': graph._fgcolor.name()}) + graph.plotItem.setTitle(state['labels'][2], **{'size': '10pt', 'color': graph._fgcolor.name()}) + graph.setWindowTitle(state['labels'][3]) + + graph.graphic.showGrid(x=state['grid'], y=state['grid']) + + graph.checkBox.setCheckState(QtCore.Qt.Checked if state['legend'] else QtCore.Qt.Unchecked) + + graph.real_button.setChecked(state['plots'][0]) + graph.imag_button.setChecked(state['plots'][1]) + graph.error_button.setChecked(state['plots'][2]) + + graph.set_range(x=state['limits'][0], y=state['limits'][1]) + graph.logx_button.setChecked(state['log'][0]) + graph.logy_button.setChecked(state['log'][1]) + + return graph + + def set_color(self, foreground=None, background=None): + if background is not None: + self._bgcolor = mkColor(background) + self.graphic.setBackground(self._bgcolor) + self.legend.setBrush(self._bgcolor) + + if foreground is not None: + self._fgcolor = mkColor(foreground) + + for ax in ['left', 'bottom']: + pen = self.plotItem.getAxis(ax).pen() + pen.setColor(self._fgcolor) + + self.plotItem.getAxis(ax).setPen(pen) + self.plotItem.getAxis(ax).setTextPen(pen) + + self.legend.setLabelTextColor(self._fgcolor) + if self.legend.isVisible(): + self.show_legend() + + title = self.plotItem.titleLabel.text + if title is not None: + self.plotItem.setTitle(title, **{'size': '10pt', 'color': self._fgcolor}) + + x = self.plotItem.getAxis('bottom').labelText + if x is not None: + self.plotItem.setLabel('bottom', x, **{'font-size': '10pt', 'color': self._fgcolor.name()}) + + y = self.plotItem.getAxis('left').labelText + if y is not None: + self.plotItem.setLabel('left', y, **{'font-size': '10pt', 'color': self._fgcolor.name()}) + + @QtCore.pyqtSlot(bool, name='on_bwbutton_toggled') + def change_background(self, _): + temp = self._fgcolor, self._bgcolor + self.set_color(foreground=self._prev_colors[0], background=self._prev_colors[1]) + self._prev_colors = temp diff --git a/nmreval/gui_qt/graphs/guide_lines.py b/nmreval/gui_qt/graphs/guide_lines.py new file mode 100644 index 0000000..e821f55 --- /dev/null +++ b/nmreval/gui_qt/graphs/guide_lines.py @@ -0,0 +1,166 @@ +from pyqtgraph import InfiniteLine + +from ..Qt import QtWidgets, QtCore, QtGui +from .._py.guidelinewidget import Ui_Form +from ..lib.pg_objects import LogInfiniteLine + + +class LineWidget(QtWidgets.QWidget, Ui_Form): + line_created = QtCore.pyqtSignal(object, str) + line_deleted = QtCore.pyqtSignal(object, str) + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.lines = {} + self.comments = {} + + self.vh_pos_lineEdit.setValidator(QtGui.QDoubleValidator()) + + self.tableWidget.installEventFilter(self) + + @QtCore.pyqtSlot(name='on_pushButton_clicked') + def make_line(self): + invalid = True + + idx = self.mode_comboBox.currentIndex() + try: + pos = float(self.vh_pos_lineEdit.text()) + # Vertical: idx=0; horizontal: idx = 1 + angle = 90*abs(1-idx) + invalid = False + except ValueError: + pos = None + angle = None + pass + + if invalid: + QtWidgets.QMessageBox().information(self, 'Invalid input', 'Input is not a valid number') + return + + qcolor = QtGui.QColor.fromRgb(*self.color_comboBox.value.rgb()) + comment = self.comment_lineEdit.text() + line = LogInfiniteLine(pos=pos, angle=angle, movable=self.drag_checkBox.isChecked(), pen=qcolor) + line.sigPositionChanged.connect(self.move_line) + + self.make_table_row(pos, angle, qcolor, comment) + + graph_id = self.graph_comboBox.currentData() + try: + self.lines[graph_id].append(line) + self.comments[graph_id].append(comment) + except KeyError: + self.lines[graph_id] = [line] + self.comments[graph_id] = [comment] + + self.line_created.emit(line, graph_id) + + def set_graphs(self, graphs: list): + for graph_id, name in graphs: + self.graph_comboBox.addItem(name, userData=graph_id) + + def remove_graph(self, graph_id: str): + idx = self.graph_comboBox.findData(graph_id) + if idx != -1: + self.graph_comboBox.removeItem(idx) + + if graph_id in self.lines: + del self.lines[graph_id] + + @QtCore.pyqtSlot(int, name='on_graph_comboBox_currentIndexChanged') + def change_graph(self, idx: int): + self.tableWidget.clear() + self.tableWidget.setRowCount(0) + + graph_id = self.graph_comboBox.itemData(idx) + if graph_id in self.lines: + lines = self.lines[graph_id] + comments = self.comments[graph_id] + for i, line in enumerate(lines): + self.make_table_row(line.pos(), line.angle, line.pen.color(), comments[i]) + + def make_table_row(self, position, angle, color, comment): + if angle == 0: + try: + pos_label = 'x = ' + str(position.y()) + except AttributeError: + pos_label = 'x = {position}' + + elif angle == 90: + try: + pos_label = f'y = {position.x()}' + except AttributeError: + pos_label = f'y = {position}' + + else: + raise ValueError('Only horizontal or vertical lines are supported') + + item = QtWidgets.QTableWidgetItem(pos_label) + item.setFlags(QtCore.Qt.ItemIsSelectable) + item.setForeground(QtGui.QBrush(QtGui.QColor('black'))) + + row_count = self.tableWidget.rowCount() + self.tableWidget.setRowCount(row_count+1) + self.tableWidget.setItem(row_count, 0, item) + + item2 = QtWidgets.QTableWidgetItem(comment) + self.tableWidget.setItem(row_count, 1, item2) + + colitem = QtWidgets.QTableWidgetItem(' ') + colitem.setBackground(QtGui.QBrush(color)) + colitem.setFlags(QtCore.Qt.ItemIsSelectable) + self.tableWidget.setVerticalHeaderItem(row_count, colitem) + + def eventFilter(self, src: QtCore.QObject, evt: QtCore.QEvent) -> bool: + if evt.type() == QtCore.QEvent.KeyPress: + if evt.key() == QtCore.Qt.Key_Delete: + self.delete_line() + return True + + return super().eventFilter(src, evt) + + def delete_line(self): + remove_rows = sorted([item.row() for item in self.tableWidget.selectedItems()]) + graph_id = self.graph_comboBox.currentData() + current_lines = self.lines[graph_id] + + print(remove_rows) + for i in reversed(remove_rows): + print(i) + self.tableWidget.removeRow(i) + self.line_deleted.emit(current_lines[i], graph_id) + + current_lines.pop(i) + self.comments[graph_id].pop(i) + + @QtCore.pyqtSlot(object) + def move_line(self, line: InfiniteLine): + current_idx = self.graph_comboBox.currentData() + graphs = self.lines[current_idx] + i = -1 + for i, line_i in enumerate(graphs): + if line == line_i: + break + pos = line.value() + text_item = self.tableWidget.item(i, 0) + text_item.setText(text_item.text()[:4]+f'{pos:.4g}') + + +if __name__ == '__main__': + import sys + from numpy.random import choice + + app = QtWidgets.QApplication([]) + + qw = 'QtCurve' + while qw == 'QtCurve': + qw = choice(QtWidgets.QStyleFactory.keys()) + print(qw) + app.setStyle(QtWidgets.QStyleFactory.create(qw)) + + mplQt = LineWidget() + mplQt.show() + mplQt.set_graphs([('a', 'a'), ('b', 'b')]) + + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/graphs/movedialog.py b/nmreval/gui_qt/graphs/movedialog.py new file mode 100644 index 0000000..5b7378b --- /dev/null +++ b/nmreval/gui_qt/graphs/movedialog.py @@ -0,0 +1,89 @@ +from ..Qt import QtCore, QtWidgets +from .._py.move_dialog import Ui_MoveDialog + + +class QMover(QtWidgets.QDialog, Ui_MoveDialog): + moveData = QtCore.pyqtSignal(list, str, str) + copyData = QtCore.pyqtSignal(list, str) + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.entries = {} + + self.fromcomboBox.currentIndexChanged.connect(self.change_graph) + self.buttonBox.clicked.connect(self.button_clicked) + + def setup(self, entries: dict): + self.fromcomboBox.blockSignals(True) + self.tocomboBox.blockSignals(True) + for k, v in entries.items(): + self.entries[k[0]] = v + self.fromcomboBox.addItem(k[1], userData=k[0]) + self.tocomboBox.addItem(k[1], userData=k[0]) + self.fromcomboBox.blockSignals(False) + self.tocomboBox.blockSignals(False) + self.change_graph(0) + + @QtCore.pyqtSlot(int) + def change_graph(self, idx: int): + self.listWidget.clear() + idd = self.fromcomboBox.itemData(idx) + if idd is not None: + for i, j in self.entries[idd]: + it = QtWidgets.QListWidgetItem(j) + it.setData(QtCore.Qt.UserRole, i) + self.listWidget.addItem(it) + + @QtCore.pyqtSlot(QtWidgets.QAbstractButton) + def button_clicked(self, btn: QtWidgets.QAbstractButton): + if self.buttonBox.buttonRole(btn) in [QtWidgets.QDialogButtonBox.ApplyRole, + QtWidgets.QDialogButtonBox.AcceptRole]: + from_graph = self.fromcomboBox.itemData(self.fromcomboBox.currentIndex()) + to_graph = self.tocomboBox.itemData(self.tocomboBox.currentIndex()) + if from_graph != to_graph: + moving = [] + for idx in self.listWidget.selectedIndexes(): + it = self.listWidget.itemFromIndex(idx) + moving.append(it.data(QtCore.Qt.UserRole)) + it_data = (it.data(QtCore.Qt.UserRole), it.text()) + if self.move_button.isChecked(): + self.entries[from_graph].remove(it_data) + self.entries[to_graph].append(it_data) + self.change_graph(self.fromcomboBox.currentIndex()) + + if self.move_button.isChecked(): + self.moveData.emit(moving, to_graph, from_graph) + else: + self.copyData.emit(moving, to_graph) + + if self.buttonBox.buttonRole(btn) == QtWidgets.QDialogButtonBox.AcceptRole: + self.close() + + elif self.buttonBox.buttonRole(btn) == QtWidgets.QDialogButtonBox.RejectRole: + self.close() + else: + return + + def close(self): + self.listWidget.clear() + self.tocomboBox.clear() + self.fromcomboBox.clear() + self.entries = {} + + super().close() + + +if __name__ == '__main__': + import sys + global propData + + app = QtWidgets.QApplication([]) + + m = QMover() + m.setup({('a', '1'): ('z', '100'), ('b', '2'): ('y', '99'), ('c', '3'): ('x', '98')}) + + m.show() + + sys.exit(app.exec()) \ No newline at end of file diff --git a/nmreval/gui_qt/io/__init__.py b/nmreval/gui_qt/io/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nmreval/gui_qt/io/asciireader.py b/nmreval/gui_qt/io/asciireader.py new file mode 100644 index 0000000..fd6472a --- /dev/null +++ b/nmreval/gui_qt/io/asciireader.py @@ -0,0 +1,182 @@ +from ...io.asciireader import AsciiReader + +from ..Qt import QtGui, QtCore, QtWidgets +from .._py.asciidialog import Ui_ascii_reader + + +class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader): + data_read = QtCore.pyqtSignal(list) + file_ext = ['.dat', '.txt'] + skip = False + + def __init__(self, fname=None, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.reader = AsciiReader(fname) + + self.ascii_table.horizontalHeader().setStretchLastSection(True) + self.buttonbox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.apply) + self.buttonbox.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self.accept) + + self.changestaggeredrange(0) + + self.ascii_table.contextMenuEvent = self.ctx_table + self.ascii_table.horizontalHeader().setContextMenuPolicy(QtCore.Qt.CustomContextMenu) + self.ascii_table.horizontalHeader().customContextMenuRequested.connect(self.ctx_table) + + def __call__(self, fname, *args, **kwargs): + + for i in [self.stag_lineEdit, self.start_lineedit, self.end_lineedit, + self.plainTextEdit_2, self.ascii_table, self.delay_lineedit]: + i.clear() + self.checkBox_2.setChecked(False) + self.checkBox.setChecked(False) + self.plainTextEdit_2.show() + + self.reader = AsciiReader(fname) + self.set_gui() + + if QAsciiReader.skip: + self.accept() + else: + self.skippy_checkbox.blockSignals(True) + self.skippy_checkbox.setCheckState(QtCore.Qt.Unchecked) + self.skippy_checkbox.blockSignals(False) + + return self + + def set_gui(self): + for text in self.reader.header: + self.plainTextEdit_2.appendPlainText(text) + + self.ascii_table.setRowCount(self.reader.shape[0]) + self.ascii_table.setColumnCount(self.reader.shape[1]) + try: + last_header_line = self.reader.header[-1].split() + if len(last_header_line) == self.reader.shape[1]: + self.ascii_table.setHorizontalHeaderLabels(last_header_line) + except IndexError: + self.plainTextEdit_2.hide() + + for i, line in enumerate(self.reader.data): + for j, field in enumerate(line): + it = QtWidgets.QTableWidgetItem(field) + self.ascii_table.setItem(i, j, it) + + self.ascii_table.resizeColumnsToContents() + + if self.reader.delays is not None: + set_string = ''.join(str(d) + '\n' for d in self.reader.delays) + self.plainTextEdit.setPlainText(set_string) + self.delay_lineedit.setText(str(len(self.reader.delays))) + + def ctx_table(self, _): + menu = QtWidgets.QMenu(self) + x_action = QtWidgets.QAction('Set as x', self) + x_action.triggered.connect(lambda: self.set_columns('x')) + y_action = QtWidgets.QAction('Set as y', self) + y_action.triggered.connect(lambda: self.set_columns('y')) + menu.addActions([x_action, y_action]) + if self.label_5.isVisible(): + yerr_action = QtWidgets.QAction('Set as \u0394y', self) + yerr_action.triggered.connect(lambda: self.set_columns('yerr')) + menu.addAction(yerr_action) + menu.popup(QtGui.QCursor.pos()) + + def set_columns(self, mode): + cols = ' '.join([str(s.column()+1) for s in self.ascii_table.selectionModel().selectedColumns()]) + try: + lineedit = {'x': self.x_lineedit, 'y': self.y_lineedit, 'yerr': self.lineEdit}[mode] + lineedit.setText(cols) + except KeyError: + pass + + @QtCore.pyqtSlot(int, name='on_checkBox_2_stateChanged') + def changestaggeredrange(self, evt): + if evt == 2: + self.stag_lineEdit.show() + self.stag_lineEdit.setEnabled(True) + else: + self.stag_lineEdit.hide() + self.stag_lineEdit.setDisabled(True) + + @QtCore.pyqtSlot(name='on_pushButton_clicked') + def calc_delays(self): + self.reader.calc_delays(float(self.start_lineedit.text()), float(self.end_lineedit.text()), + int(self.delay_lineedit.text()), log=self.checkBox.isChecked(), + stagg=self.checkBox_2.isChecked(), stag_size=int(self.stag_lineEdit.text())) + + set_string = ''.join(str(d) + '\n' for d in self.reader.delays) + self.plainTextEdit.setPlainText(set_string) + + def update_header(self, text, comment='#'): + text = text.replace(comment, '').lstrip().rstrip() + self.plainTextEdit_2.appendPlainText(text) + + @QtCore.pyqtSlot() + def on_plainTextEdit_textChanged(self): + new_delays = str(self.plainTextEdit.toPlainText()).rstrip('\n').split('\n') + self.delay_lineedit.setText(str(len(new_delays))) + if new_delays[0] == '': + new_delays = None + else: + for k, v in enumerate(new_delays): + try: + new_delays[k] = float(v) + except ValueError: + new_delays[k] = -1 + self.reader.delays = new_delays + + @QtCore.pyqtSlot() + def accept(self): + if self.apply(): + self.close() + + def apply(self): + # default row for x is the first row, it will be superseded if an integer number is given. + + try: + x = [int(self.x_lineedit.text())-1] + except ValueError: + x = None + try: + y = [int(t)-1 for t in str(self.y_lineedit.text()).split(' ')] + except ValueError: + y = None + try: + y_err = [int(t)-1 for t in str(self.lineEdit.text()).split(' ')] + except ValueError: + y_err = None + + ret_dic = self.reader.export(xidx=x, yidx=y, yerridx=y_err, + mode=self.buttonGroup.checkedButton().text()) + + self.data_read.emit(ret_dic) + + return True + + @staticmethod + def _update_dic(key, value, old_dic): + old_dic_keys = list(old_dic.keys()) + if key in old_dic_keys: + counter = 0 + replace_key = key + str(counter) + while replace_key in old_dic_keys: + counter += 1 + replace_key = key + str(counter) + else: + replace_key = key + old_dic[replace_key] = value + + @QtCore.pyqtSlot(int, name='on_buttonGroup_buttonClicked') + def show_error(self, val): + if val == -2: + self.widget.show() + else: + self.lineEdit.setText('') + self.widget.hide() + + @QtCore.pyqtSlot(int, name='on_skippy_checkbox_stateChanged') + def skip_next_dial(self, _): + QAsciiReader.skip = self.skippy_checkbox.isChecked() diff --git a/nmreval/gui_qt/io/bdsreader.py b/nmreval/gui_qt/io/bdsreader.py new file mode 100644 index 0000000..8ecc837 --- /dev/null +++ b/nmreval/gui_qt/io/bdsreader.py @@ -0,0 +1,66 @@ +from ...io.bds_reader import BDSReader + +from ..Qt import QtCore, QtWidgets +from .._py.bdsdialog import Ui_Dialog + + +class QBDSReader(QtWidgets.QDialog, Ui_Dialog): + data_read = QtCore.pyqtSignal(list) + file_ext = ['.eps'] + + def __init__(self, fname: str = None, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + if fname is not None: + self.reader = BDSReader(fname) + self.setup_gui() + + def __call__(self, fname: str): + self.reader = BDSReader(fname) + self.setup_gui() + + return self + + def setup_gui(self): + self.listWidget.clear() + + for temp in self.reader.set_temp: + item = QtWidgets.QListWidgetItem(str(temp)) + item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsSelectable) + item.setCheckState(QtCore.Qt.Checked) + self.listWidget.addItem(item) + + def accept(self): + data = [] + + temps = [] + for i in range(self.listWidget.count()): + item = self.listWidget.item(i) + if item.checkState() == QtCore.Qt.Checked: + temps.append(i) + + for (mode, cb) in [('epsilon', self.eps_checkBox), + ('sigma', self.cond_checkBox), + ('modulus', self.modul_checkBox)]: + + if cb.checkState() == QtCore.Qt.Checked: + values = self.reader.export(mode=mode) + for t in temps: + data.append(values[t]) + + self.data_read.emit(data) + + super().accept() + + +if __name__ == '__main__': + import sys + + app = QtWidgets.QApplication(sys.argv) + + reader = QBDSReader() + reader('/autohome/dominik/nmreval/testdata/ZWEITECHANCE_EGD4H2O.EPS') + reader.show() + sys.exit(app.exec()) + diff --git a/nmreval/gui_qt/io/dscreader.py b/nmreval/gui_qt/io/dscreader.py new file mode 100644 index 0000000..e11eae5 --- /dev/null +++ b/nmreval/gui_qt/io/dscreader.py @@ -0,0 +1,273 @@ +from pathlib import Path +from typing import Union + +import numpy as np +from pyqtgraph import PlotDataItem + +from nmreval.data.points import Points +from nmreval.io.dsc import Cyclohexane, DSCCalibrator, DSCSample + +from nmreval.gui_qt.Qt import QtWidgets, QtCore +from nmreval.gui_qt._py.dscfile_dialog import Ui_Dialog + + +class QDSCReader(QtWidgets.QDialog, Ui_Dialog): + data_read = QtCore.pyqtSignal(list) + file_ext = ['.txt', '.dsc'] + + def __init__(self, sample= None, empty=None, reference=None, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.calibrator = DSCCalibrator() + self.current_run = (-1, 'h') + self.sample_idx = None + self.fname = None + + self.raw_graph.setLabel('bottom', text='T', units='K') + self.raw_graph.setTitle('Raw data') + self.raw_graph.addLegend() + self.raw_sample = PlotDataItem(x=[], y=[], name='Sample') + self.empty_sample = PlotDataItem(x=[], y=[], pen={'dash': (5, 5)}, name='Empty') + self.raw_graph.addItem(self.raw_sample) + self.raw_graph.addItem(self.empty_sample) + + self.end_graph.setTitle('End result') + self.end_graph.setLabel('bottom', text='T', units='K') + self.baseline_sample = PlotDataItem(x=[], y=[]) + self.end_graph.addItem(self.baseline_sample) + + self.baseline_graph.setTitle('Time dependence') + self.baseline_graph.setLabel('bottom', text='t', units='min') + self.drift_sample = PlotDataItem(x=[], y=[]) + self.slope_graph = PlotDataItem(x=[], y=[], pen={'color': 'r', 'dash': (5, 5)}) + self.baseline_graph.addItem(self.drift_sample) + self.baseline_graph.addItem(self.slope_graph) + + self.calib_graph.setTitle('Calibration') + self.calib_graph.setLabel('bottom', text='T', units='K') + self.ref_plotitems = [] + + self.sample = None + if sample is not None: + self.add_sample(sample) + + self.empty = None + if empty is not None: + self.add_empty(empty=empty) + + self.references = [] + if reference is not None: + if isinstance(reference, (str, Path, DSCSample)): + reference = [reference] + for r in reference: + self.add_reference(ref=r) + + def add_sample(self, fname: Union[Path, str]): + self.sample = self.calibrator.set_measurement(fname, mode='sample') + self.fname = self.sample.fname + + self.step_listWidget.clear() + + for opts in self.sample.steps: + item = QtWidgets.QListWidgetItem() + item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable) + item.setCheckState(QtCore.Qt.Unchecked) + + if opts[0] == 'i': + item.setFlags(QtCore.Qt.NoItemFlags) + item.setText(f'{opts[1]:.2f} K for {opts[1] / 60:.0f} min') + else: + item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable) + item.setText(f'{opts[2]:.2f} K to {opts[3]:.2f} K with {opts[1]} K/min') + + self.step_listWidget.addItem(item) + + @QtCore.pyqtSlot(name='on_loadempty_button_clicked') + def add_empty(self, empty=None): + if empty is None: + empty, _ = QtWidgets.QFileDialog.getOpenFileName(directory=str(self.fname.parent)) + + if empty: + self.empty = self.calibrator.set_measurement(empty, mode='empty') + self.empty_label.setText(str(self.empty.fname.name)) + + self.update_plots() + + @QtCore.pyqtSlot(name='on_delempty_button_clicked') + def remove_empty(self): + self.empty_label.setText('Empty measurement') + self.calibrator.empty = None + + self.update_plots() + + @QtCore.pyqtSlot(name='on_ref_add_pushButton_clicked') + def add_reference(self, ref=None): + if ref is None: + ref, _ = QtWidgets.QFileDialog.getOpenFileName(directory=str(self.fname.parent)) + + if ref: + ref = self.calibrator.set_measurement(ref, mode='reference') + + self.references.append(ref) + item = QtWidgets.QTableWidgetItem(str(ref.fname.name)) + item.setData(QtCore.Qt.UserRole, ref.fname) + item.setFlags(QtCore.Qt.ItemIsEnabled) + + rowcnt = self.reference_tableWidget.rowCount() + self.reference_tableWidget.setRowCount(rowcnt+1) + self.reference_tableWidget.setItem(rowcnt, 0, item) + self.reference_tableWidget.setCellWidget(rowcnt, 1, ReferenceComboBox()) + self.reference_tableWidget.resizeColumnsToContents() + + self.update_plots() + + @QtCore.pyqtSlot(name='on_ref_remove_pushButton_clicked') + def remove_reference(self): + idx = self.reference_tableWidget.currentRow() + self.calibrator.remove_reference(self.reference_tableWidget.item(idx, 0).data(QtCore.Qt.UserRole)) + + self.reference_tableWidget.removeRow(idx) + + print(self.calibrator.reference) + + self.update_plots() + + @QtCore.pyqtSlot(QtWidgets.QListWidgetItem, name='on_step_listWidget_itemChanged') + def select_run(self, item: QtWidgets.QListWidgetItem): + + idx = self.step_listWidget.indexFromItem(item).row() + self.step_listWidget.blockSignals(True) + for row in range(self.step_listWidget.count()): + if idx == row: + continue + self.step_listWidget.item(row).setCheckState(QtCore.Qt.Unchecked) + self.step_listWidget.blockSignals(False) + + if item.checkState() == QtCore.Qt.Checked: + mode, rate, _, _ = self.sample.steps[idx] + self.current_run = (rate, mode) + self.sample_idx = idx + self.update_plots() + else: + self.current_run = (-1, 'h') + self.sample_idx = None + self.clear_plots() + + @QtCore.pyqtSlot(QtWidgets.QAbstractButton, name='on_buttonGroup_buttonClicked') + def update_plots(self, _=None): + if self.sample_idx is None: + return + + slope_type = {self.none_radioButton: None, + self.isotherm_radioButton: 'iso', + self.slope_radioButton: 'curve'}[self.buttonGroup.checkedButton()] + + rate = self.current_run[0] + try: + raw_sample, drift_value, sample_data, empty_data, slope = self.calibrator.get_data(self.sample_idx, + slope=slope_type) + except ValueError as e: + _msg = QtWidgets.QMessageBox.warning(self, 'No rate found', e.args[0]) + return + + self.raw_sample.setData(x=raw_sample[0], y=raw_sample[1]) + self.drift_sample.setData(x=drift_value[0]/60., y=drift_value[1]) + self.slope_graph.setData(x=slope[0]/60., y=slope[1]) + + if empty_data is not None: + self.empty_sample.setData(x=empty_data[0], y=empty_data[1]) + + self.calibrator.ref_list = [] + for row in range(self.reference_tableWidget.rowCount()): + self.calibrator.ref_list.append(self.reference_tableWidget.cellWidget(row, 1).get_reference()) + + self.calib_graph.clear() + + calib_x, calib_y, regions = self.calibrator.get_calibration(rate) + + if calib_x is not None: + for ref_zoom, onset, grad_points in regions: + ref_plot = PlotDataItem(x=ref_zoom[0], y=ref_zoom[1]) + self.calib_graph.addItem(ref_plot) + + self.calib_graph.addItem(PlotDataItem(x=grad_points[0], y=grad_points[1], + symbol='x')) + + view_limits = -np.max(ref_zoom[1])/10, np.max(ref_zoom[1]) * 1.1 + cut_idx, = np.where((onset < view_limits[1]) & (onset > view_limits[0])) + self.calib_graph.addItem(PlotDataItem(x=ref_zoom[0, cut_idx], y=onset[cut_idx], + pen={'color': 'r', 'dash': (2, 5)})) + self.calib_graph.addItem(PlotDataItem(x=[ref_zoom[0, 0], ref_zoom[0, -1]], y=[0, 0], + pen={'color': 'r', 'dash': (2, 5)})) + + else: + calib_x = [1, 0] + calib_y = 1 + + if self.cp_checkBox.isChecked(): + self.baseline_sample.setData(x=calib_x[0]*sample_data[0]+calib_x[1], y=calib_y*sample_data[1]) + else: + self.baseline_sample.setData(x=calib_x[0]*sample_data[0]+calib_x[1], y=sample_data[1]) + + def clear_plots(self): + for plot in [self.raw_sample, self.baseline_sample, self.empty_sample, self.drift_sample, self.slope_graph]: + plot.setData(x=[], y=[]) + + self.calib_graph.clear() + + def accept(self): + run_list = [] + for i in range(self.step_listWidget.count()): + if self.step_listWidget.item(i).checkState() == QtCore.Qt.Checked: + run_list.append(i) + + if self.baseline_groupBox.isChecked(): + empty = self.empty + slope = {self.none_radioButton: None, + self.isotherm_radioButton: 'iso', + self.slope_radioButton: 'heat'}[self.buttonGroup.checkedButton()] + else: + empty = None + slope = None + + if self.reference_groupBox.isChecked(): + calibrations = [] + for j, ref in enumerate(self.references): + calibrations.append((ref, self.reference_tableWidget.cellWidget(j, 1).get_reference())) + else: + calibrations = None + + new_vals = [] + + for run in run_list: + mode, rate, _, _ = self.sample.steps[run] + xy = self.sample.curve(rate, mode, empty=empty, slope=slope, calibration=calibrations) + new_vals.append(Points(xy[0], xy[1], value=rate, name=f'{self.fname.stem} {rate} ({mode})')) + + self.data_read.emit(new_vals) + + super().accept() + + +class ReferenceComboBox(QtWidgets.QComboBox): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.references = [Cyclohexane] + for ref in self.references: + self.addItem(ref.name) + + def get_reference(self): + return self.references[self.currentIndex()] + + +if __name__ == '__main__': + import sys + app = QtWidgets.QApplication(sys.argv) + + reader = QDSCReader(sample='/autohome/dominik/nmreval/testdata/dsc/20m_LiTFSI_H2O.txt', + empty='/autohome/dominik/nmreval/testdata/dsc/leer.txt', + reference='/autohome/dominik/nmreval/testdata/dsc/cyclohexan_10K-min.txt') + reader.show() + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/io/exporters.py b/nmreval/gui_qt/io/exporters.py new file mode 100644 index 0000000..bbca4a6 --- /dev/null +++ b/nmreval/gui_qt/io/exporters.py @@ -0,0 +1,143 @@ +from numpy import c_ + +from ...io.graceeditor import GraceEditor +from ...lib.colors import Colors +from ...lib.lines import LineStyle +from ...lib.symbols import SymbolStyle +from ...utils.text import convert + +from ..Qt import QtGui, QtCore, QtPrintSupport + + +class GraceExporter: + def __init__(self, kwargs: dict): + self.__agr = None + self.__opts = kwargs + + def export(self, outfile: str, mode: (int, str) = 'w'): + if mode == 'w': + self.__agr = GraceEditor() + else: + self.__agr = GraceEditor(outfile) + + if isinstance(mode, str): + new_g = self.__agr.new_graph() + + new_g.set_limits(x=self.__opts['limits'][0], y=self.__opts['limits'][1]) + new_g.set_log(x=self.__opts['log'][0], y=self.__opts['log'][1]) + + new_g.set_onoff('legend', self.__opts['legend']) + new_g.set_property(**{'title': '"' + convert(self.__opts['labels'][2], old="html", new="agr") + '"', + 'legend loctype': 'view', + 'legend': ', '.join(str(i) for i in new_g.world_to_view(self.__opts['legend_pos']))}) + + for i, ax in enumerate('xy'): + new_g.set_axis_property(ax, **{'label': f'"{convert(self.__opts["labels"][i], old="html", new="agr")}"', + 'tick major': self.__opts['ticks'][i][0], + 'tick minor ticks': self.__opts['ticks'][i][1],}) + new_g.set_axis_onoff(ax, 'tick major grid', self.__opts['grid']) + g_idx = new_g.idx + else: + g_idx = mode + + colors = self.__agr.colors + + new_colors = [] + for item in self.__opts['items']: + new_s = self.__agr.new_set(g_idx) + + sc = item['symbolcolor'] + c_num = -1 + for i, (_, rgb) in colors.items(): + if rgb == sc: + c_num = i + break + + if c_num == -1: + c_num = max(colors.keys()) + colors[c_num + 1] = (f'color{c_num + 1}', sc) + new_colors.append((c_num + 1, f'color{c_num + 1}', sc)) + + new_s.set_symbol(**{'symbol': item['symbol'].value, 'size': item['symbolsize'] / 10., 'color': c_num, + 'fill color': c_num, 'fill pattern': 1}) + new_s.set_onoff('errorbar', self.__opts['plots'][2]) + + lc = item['linecolor'] + c_num = -1 + for c_num, (_, rgb) in colors.items(): + if rgb == lc: + break + + if c_num == -1: + c_num = max(colors.keys()) + colors[c_num + 1] = () + new_colors.append((c_num, f'color{c_num + 1}', sc)) + + new_s.set_line(**{'color': c_num, 'linewidth': item['linewidth'], + 'linestyle': item['linestyle'].to_agr()}) + new_s.set_property(comment='"' + item['name'] + '"', legend='"' + item['name'] + '"') + + data = self.__agr.dataset(g_idx, new_s.idx) + if 'yerr' in item: + data.type = 'xydy' + data.data = c_[item['x'], item['y'], item['yerr']] + new_s.set_property(**{'errorbar color': c_num}) + else: + data.data = c_[item['x'], item['y']] + + for c in new_colors: + self.__agr.set_color(c[1], c[2], idx=c[0]) + + self.__agr.write(outfile) + + +class PDFPrintExporter: + def __init__(self, graphview): + self.graphic = graphview + + def export(self, outfile): + printer = QtPrintSupport.QPrinter() + + printer.setOutputFormat(printer.PdfFormat) + printer.setOutputFileName(outfile) + + printer.setPaperSize(QtCore.QSizeF(self.graphic.width(), self.graphic.height()), + printer.DevicePixel) + printer.setPageMargins(0, 0, 0, 0, printer.DevicePixel) + + painter = QtGui.QPainter(printer) + self.graphic.render(painter) + painter.end() + + +def pgitem_to_dic(item): + x, y = item.xData, item.yData + if (x is None) or (len(x) == 0): + return + + opts = item.opts + item_dic = { + 'x': x, 'y': y, + 'name': opts['name'], + 'symbolsize': opts['symbolSize'] + } + + if opts['symbol'] is None: + item_dic['symbol'] = SymbolStyle.No + item_dic['symbolcolor'] = Colors.Black + else: + item_dic['symbol'] = SymbolStyle.from_str(opts['symbol']) + item_dic['symbolcolor'] = Colors.from_rgb(*opts['symbolBrush'].color().getRgbF()[:3]) + + pen = opts['pen'] + + if pen is not None: + item_dic['linestyle'] = LineStyle(pen.style()) + item_dic['linecolor'] = Colors.from_rgb(*pen.color().getRgbF()[:3]) + item_dic['linewidth'] = pen.widthF() + else: + item_dic['linestyle'] = LineStyle.No + item_dic['linecolor'] = item_dic['symbolcolor'] + item_dic['linewidth'] = 0.0 + + return item_dic diff --git a/nmreval/gui_qt/io/fcbatchreader.py b/nmreval/gui_qt/io/fcbatchreader.py new file mode 100644 index 0000000..e94a750 --- /dev/null +++ b/nmreval/gui_qt/io/fcbatchreader.py @@ -0,0 +1,116 @@ +import pathlib + +from ...io.fcbatchreader import FCReader +from ..lib.utils import busy_cursor +from ..Qt import QtCore, QtWidgets, QtGui +from .._py.fcreader import Ui_FCEval_dialog + + +class QFCReader(QtWidgets.QDialog, Ui_FCEval_dialog): + data_read = QtCore.pyqtSignal(list, str) + + def __init__(self, path=None, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + if path is None: + path = pathlib.Path().home() + self.path = path + + self.start_lineedit.setValidator(QtGui.QDoubleValidator()) + self.stop_lineedit.setValidator(QtGui.QDoubleValidator()) + + self.listWidget.installEventFilter(self) + + def eventFilter(self, src: QtCore.QObject, evt: QtCore.QEvent) -> bool: + # intercept key press in listwidget to allow deletion with Del + if evt.type() == QtCore.QEvent.KeyPress: + if evt.key() == QtCore.Qt.Key_Delete: + self.listWidget.takeItem(self.listWidget.currentRow()) + return True + + return super().eventFilter(src, evt) + + @QtCore.pyqtSlot(int, name='on_region_checkBox_stateChanged') + def use_region(self, state: int): + self.start_lineedit.setEnabled(state == QtCore.Qt.Checked) + self.stop_lineedit.setEnabled(state == QtCore.Qt.Checked) + + @QtCore.pyqtSlot(name='on_file_pushbutton_clicked') + @QtCore.pyqtSlot(name='on_dir_pushbutton_clicked') + def get_input(self): + if self.sender() == self.file_pushbutton: + infiles, _ = QtWidgets.QFileDialog.getOpenFileNames(caption='Select HDF files', + directory=str(self.path), + filter='HDF files (*.h5)') + if infiles: + self.listWidget.addItems(infiles) + self.label.setText(str(pathlib.Path(infiles[-1]).parent)) + else: + infiles = QtWidgets.QFileDialog.getExistingDirectory(caption='Select input directory', + directory=str(self.path), + options=QtWidgets.QFileDialog.ShowDirsOnly) + + if infiles: + self.listWidget.addItem(infiles) + self.label.setText(str(pathlib.Path(infiles).parent)) + + @QtCore.pyqtSlot(name='on_savebutton_clicked') + def save_path(self): + outfile = QtWidgets.QFileDialog.getExistingDirectory(self, caption='Select directory', + directory=self.label.text(), + options=QtWidgets.QFileDialog.ShowDirsOnly) + if outfile: + self.label.setText(outfile) + + def accept(self): + items = [self.listWidget.item(i).text() for i in range(self.listWidget.count())] + if items: + with busy_cursor(): + self.read(items) + + self.close() + + def read(self, items): + region = (None, None) + if self.region_box.isChecked(): + start = None + if self.start_lineedit.text(): + start = float(self.start_lineedit.text()) + + stop = None + if self.stop_lineedit.text(): + stop = float(self.stop_lineedit.text()) + region = (start, stop) + + fc_eval = FCReader(items) + try: + fc_eval.load_magnetization(region=region, overwrite=self.overwrite_cb.isChecked()) + except OSError as e: + QtWidgets.QMessageBox.warning(self, 'Mssing data', e.strerror) + self.statelabel.setText('') + return + + fc_eval.fit(kww=self.kww_checkbox.isChecked(), save_fits=True, save_fig=True) + + save_variables = [] + for name, cb in [('t1', self.t1_cb), ('beta', self.beta_cb), ('m0', self.m0_cb), ('off', self.off_cb)]: + if cb.isChecked(): + save_variables.append(name) + + ret_vals = [] + ret_vals.extend(fc_eval.get_parameter(path=self.label.text(), kind='temp', parameter=save_variables)) + + grp = '' + if self.graph_checkbox.isChecked(): + grp = self.graph_comboBox.currentData(QtCore.Qt.UserRole) + + self.data_read.emit(ret_vals, grp) + + +if __name__ == '__main__': + import sys + app = QtWidgets.QApplication([]) + qfc = QFCReader() + qfc.show() + + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/io/filedialog.py b/nmreval/gui_qt/io/filedialog.py new file mode 100644 index 0000000..30306b6 --- /dev/null +++ b/nmreval/gui_qt/io/filedialog.py @@ -0,0 +1,88 @@ +from ..Qt import QtWidgets, QtCore + + +class _FileDialog(QtWidgets.QFileDialog): + def __init__(self, directory=None, caption=None, filters='', parent=None): + super().__init__(parent=parent) + + self.setOption(QtWidgets.QFileDialog.DontUseNativeDialog, True) + + self.setWindowTitle(caption) + self.setDirectory(str(directory)) + self.setNameFilters(filters.split(';;')) + + file_tree = self.findChild(QtWidgets.QTreeView, 'treeView') + file_tree.setSortingEnabled(True) + for i in range(file_tree.header().count()): + file_tree.header().setSectionResizeMode(i, 0) + file_tree.model().sort(0) + + file_list = self.findChild(QtWidgets.QListView, 'listView') + file_list.model().sort(0) + + line = QtWidgets.QFrame(self) + line.setFrameShape(line.HLine) + line.setFrameShadow(line.Sunken) + self.layout().addWidget(line, self.layout().rowCount(), 0, 1, self.layout().columnCount()) + + +class OpenFileDialog(_FileDialog): + def __init__(self, directory=None, caption=None, filters='', parent=None): + super().__init__(directory=directory, caption=caption, filters=filters, parent=parent) + + self.setFileMode(QtWidgets.QFileDialog.ExistingFiles) + + self.checkBox = QtWidgets.QCheckBox(self) + self.checkBox.setChecked(False) + self.checkBox.setText('Use existing graph') + self.checkBox.stateChanged.connect(self.checkbox_state) + self.layout().addWidget(self.checkBox) + + self.comboBox = QtWidgets.QComboBox(self) + self.comboBox.setEnabled(False) + self.layout().addWidget(self.comboBox) + + self.add_to_graph = None + + def set_graphs(self, graphs): + self.comboBox.blockSignals(True) + for gid, name in graphs: + self.comboBox.addItem(name, userData=gid) + self.comboBox.blockSignals(False) + + if not self.comboBox.count(): + self.comboBox.hide() + self.checkBox.hide() + + def checkbox_state(self, checked: QtCore.Qt.CheckState): + if checked == QtCore.Qt.Checked: + self.comboBox.setEnabled(True) + self.add_to_graph = self.comboBox.currentData() + else: + self.comboBox.setEnabled(False) + self.add_to_graph = None + + @QtCore.pyqtSlot(int, name='on_comboBox_currentIndexChanged') + def graph_changed(self, idx: int): + self.add_to_graph = self.comboBox.itemData(idx) + + +class SaveDirectoryDialog(_FileDialog): + def __init__(self, directory=None, filters='', parent=None): + super().__init__(directory=directory, filters=filters, parent=parent) + + self.setOption(QtWidgets.QFileDialog.DontConfirmOverwrite, False) + self.setAcceptMode(QtWidgets.QFileDialog.AcceptSave) + + self.label = QtWidgets.QLabel(self) + self.label.setTextFormat(QtCore.Qt.RichText) + self.label.setText('Use <label> as placeholder in filename. (e.g. t1_<label>.dat)') + self.layout().addWidget(self.label, self.layout().rowCount(), 0, 1, self.layout().columnCount()) + + self.checkBox = QtWidgets.QCheckBox(self) + self.checkBox.setChecked(True) + self.checkBox.setText('Replace spaces with underscore') + self.layout().addWidget(self.checkBox, self.layout().rowCount(), 0, 1, self.layout().columnCount()) + + self.setWindowTitle('Save') + self.setNameFilters(['All files (*.*)', 'Session file (*.nmr)', 'Text file (*.dat)', 'HDF file (*.h5)', 'Grace files (*.agr)']) diff --git a/nmreval/gui_qt/io/filereaders.py b/nmreval/gui_qt/io/filereaders.py new file mode 100755 index 0000000..27d54ec --- /dev/null +++ b/nmreval/gui_qt/io/filereaders.py @@ -0,0 +1,133 @@ +from pathlib import Path +import struct +from typing import List, Union + +from ..Qt import QtCore + +from .asciireader import QAsciiReader +from .hdfreader import QHdfViewer +from .bdsreader import QBDSReader +from .gracereader import QGraceReader +from .dscreader import QDSCReader +from .nmrreader import QNMRReader + + +class QFileReader(QtCore.QObject): + data_read = QtCore.pyqtSignal([list], [dict]) + + def __init__(self, manager=None): + QtCore.QObject.__init__(self) + + self.select = 'all' + self.data = [] + self.filenames = None + self.extensions = set() + + self.reader = {} + + for ext, reader in [ + ('txt', QAsciiReader), ('dsc', QDSCReader), ('agr', QGraceReader), + ('bds', QBDSReader), ('hdf', QHdfViewer), ('nmr', QNMRReader) + ]: + self.register(ext, reader) + + def __call__(self, files: Union[List[str], str]) -> List: + self.data = [] + if isinstance(files, str): + self.filenames = [files] + else: + self.filenames = files + + return self.readfiles(files) + + def readfiles(self, fname: Union[List[str], str]) -> List: + if not isinstance(fname, list): + fname = [fname] + + for f in fname: + f = Path(f) + dtype = self.guess_type(f) + if dtype in self.reader: + r = self.reader[dtype] + else: + raise ValueError(f'Unknown type for file {f}') + + if r(f) is not None: + # If QAsciiReader.skip = True it accepts automatically and returns None + r(f).exec() + + self.data_read.emit(self.data) + + try: + self.reader['txt'].skip = False + except KeyError: + pass + + return self.data + + def readtnt(self, fname): + """ Special treatment for tnt. If data is a single measurement, skip dialog """ + raise NotImplementedError + # tntreader = self.reader[2] + # tntreader(fname) + # if not tntreader.reader.onedimensional: + # tntreader.exec() + + @QtCore.pyqtSlot(list) + def _update_dic(self, other: list): + self.data.extend(other) + + def register(self, key, new_reader): + if key in self.reader: + return self.reader[key] + r = new_reader() + self.reader[key] = r + r.data_read.connect(self._update_dic) + self.extensions.update(r.file_ext) + + return r + + def guess_type(self, fname: Path) -> str: + ext = fname.suffix.lower() + + if ext in self.extensions: + if ext in ('.dat', '.txt'): + with fname.open('r', encoding='iso-8859-15') as fp: + line = fp.readline() + if line.strip().startswith('Filename: C:\\'): + return 'dsc' + + return 'txt' + + if ext in ('.h5', '.hdf', '.hdf5'): + return 'hdf' + + if ext == '.eps': + return 'bds' + + return ext[1:] # remove dot + + else: + with fname.open('rb') as fp: + s16 = fp.read(16) + + # copied from whichdb (Python 2.7) to look for magic value of dbhash + (magic,) = struct.unpack("=l", s16[-4:]) + if magic in (0x00061561, 0x61150600): + return 'nmr' + + else: + ret_types = ('nmr', 'bds', 'tnt', 'agr', 'dsc') + strings = (b'NMREVAL', b'NOVOCONTROL', b'TNT1.005', b'# Grace project', b'Filename:\tC:') + + (magic,) = struct.unpack('<16s', s16) + for dtype, startstring in zip(ret_types, strings): + if magic.startswith(startstring): + return dtype + + # nothing matched, text file is best guess + return 'txt' + + +if __name__ == '__main__': + pass diff --git a/nmreval/gui_qt/io/gracereader.py b/nmreval/gui_qt/io/gracereader.py new file mode 100644 index 0000000..7261571 --- /dev/null +++ b/nmreval/gui_qt/io/gracereader.py @@ -0,0 +1,110 @@ +from ...lib.lines import LineStyle +from ...lib.symbols import SymbolStyle +from ...data.points import Points +from ...io.graceeditor import GraceEditor + +from ..Qt import QtCore, QtWidgets, QtGui +from .._py.gracereader import Ui_Dialog + + +class QGraceReader(QtWidgets.QDialog, Ui_Dialog): + data_read = QtCore.pyqtSignal(list) + file_ext = ['.agr'] + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + self._reader = GraceEditor() + self.treeWidget.itemClicked.connect(self.show_property) + + self.treeWidget.installEventFilter(self) + + def __call__(self, fname, *args, **kwargs): + self.read(fname) + + return self + + def eventFilter(self, src: QtCore.QObject, evt: QtCore.QEvent): + if evt.type() == QtCore.QEvent.KeyPress: + if evt.key() == QtCore.Qt.Key_Space: + iterator = QtWidgets.QTreeWidgetItemIterator(self.treeWidget) + while iterator.value(): + item = iterator.value() + if item.parent() is not None and item.isSelected(): + item.setCheckState(0, + QtCore.Qt.Checked if item.checkState(0) == QtCore.Qt.Unchecked else + QtCore.Qt.Unchecked) + + iterator += 1 + + return True + + return super().eventFilter(src, evt) + + def read(self, fname): + self._reader.parse(fname) + + for graphs in self._reader.graphs: + item = QtWidgets.QTreeWidgetItem([f'Graph {graphs.idx} (Title "{graphs.get_property("title")}")']) + for gset in graphs.set: + item_2 = QtWidgets.QTreeWidgetItem([f'Set {gset.idx} (Label: {gset.get_property("legend")}, ' + f'shape: {self._reader.dataset(graphs.idx, gset.idx).shape})']) + item_2.setCheckState(0, QtCore.Qt.Checked) + item_2.setData(0, QtCore.Qt.UserRole, (graphs.idx, gset.idx)) + item.addChild(item_2) + + self.treeWidget.addTopLevelItem(item) + self.treeWidget.expandAll() + + @QtCore.pyqtSlot(QtWidgets.QTreeWidgetItem, int) + def show_property(self, item: QtWidgets.QTreeWidgetItem, col: int): + keys = item.data(col, QtCore.Qt.UserRole) + if keys is not None: + cols = self._reader.colors + + self.tableWidget.item(0, 1).setText(SymbolStyle(self._reader.get_property(*keys, 'symbol')).name) + sym_col = cols[self._reader.get_property(*keys, 'symbol fill color')][1] + self.tableWidget.item(1, 1).setBackground(QtGui.QBrush(QtGui.QColor(*sym_col))) + + self.tableWidget.item(2, 1).setText(LineStyle(self._reader.get_property(*keys, 'line linestyle')).name) + + line_col = cols[self._reader.get_property(*keys, 'line color')][1] + self.tableWidget.item(3, 1).setBackground(QtGui.QBrush(QtGui.QColor(*line_col))) + + def accept(self): + data = [] + iterator = QtWidgets.QTreeWidgetItemIterator(self.treeWidget, + QtWidgets.QTreeWidgetItemIterator.NoChildren | + QtWidgets.QTreeWidgetItemIterator.Checked) + + while iterator.value(): + item = iterator.value() + key = (item.data(0, QtCore.Qt.UserRole)) + s = self._reader.dataset(*key) + label = self._reader.get_property(*key, 'legend').replace('"', '') + # label = self._reader.graphs[key[0]].sets[key[1]]['legend'].replace('"', '') + sd = s.data + if s.type == 'xydy': + data.append(Points(x=sd[:, 0], y=sd[:, 1], y_err=sd[:, 2], name=label)) + else: + data.append(Points(x=sd[:, 0], y=sd[:, 1], name=label)) + + iterator += 1 + + self.data_read.emit(data) + + self.close() + + def close(self): + self._reader.clear() + super().close() + + +if __name__ == '__main__': + import sys + app = QtWidgets.QApplication(sys.argv) + + reader = QGraceReader() + reader.read('/autohome/dominik/nmreval/testdata/02_relax_2.agr') + reader.show() + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/io/hdfreader.py b/nmreval/gui_qt/io/hdfreader.py new file mode 100644 index 0000000..e0c673c --- /dev/null +++ b/nmreval/gui_qt/io/hdfreader.py @@ -0,0 +1,196 @@ +from ...io.hdfreader import HdfReader + +from ..Qt import QtGui, QtCore, QtWidgets +from .._py.hdftree import Ui_Hdf_Dialog + + +class QHdfViewer(QtWidgets.QDialog, Ui_Hdf_Dialog): + data_read = QtCore.pyqtSignal(list) + file_ext = ['.h5', '.hdf', '.hdf5'] + + def __init__(self, fname: str = None, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.treewidget = HDFTreeWidget(self) + self.verticalLayout_3.addWidget(self.treewidget) + + self.variables = VarTable(self) + self.widget_2.addWidget(self.variables) + self.widget_2.setText('Variables') + + self._reader = HdfReader() + + if fname is not None: + self.__call__(fname) + + def __call__(self, fname, *args, **kwargs): + self.treewidget.clear() + for cb in [self.comboBox, self.comboBox_2]: + cb.clear() + cb.addItem('Automatic for the people') + cb.show() + + self._reader(filename=fname) + self._fill_boxes() + self._populate_tree(self._reader, self.treewidget.invisibleRootItem()) + + if self.comboBox.count() == 1: + self.comboBox.hide() + self.comboBox_2.hide() + + self.treewidget.expandToDepth(0) + self.treewidget.resizeColumnToContents(1) + + return self + + def _populate_tree(self, node, item): + self.treewidget.blockSignals(True) + + # add varied parameter to comboboxes + for key, value in node.title_parameter[1].items(): + if isinstance(value, list): + idx = self.comboBox.findText(key) + if idx == -1: + self.comboBox.addItem(key) + self.comboBox_2.addItem(key) + + if node.children is not None: + for child in node.children.values(): + label_item = QtWidgets.QTreeWidgetItem([child.name]) + label_item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsSelectable) + label_item.setCheckState(0, QtCore.Qt.Unchecked) + if child.type == 'signal': + label_item.setBackground(0, QtGui.QBrush(QtGui.QColor('cyan'))) + label_item.setCheckState(1, QtCore.Qt.Unchecked) + elif child.type == 'points': + label_item.setBackground(0, QtGui.QBrush(QtGui.QColor('red'))) + item.addChild(label_item) + self._populate_tree(child, label_item) + + self.treewidget.blockSignals(False) + + def _fill_boxes(self): + for k, v in self._reader.parameter.items(): + if isinstance(v, list): + idx = self.comboBox.findText(k) + if idx == -1: + self.comboBox.addItem(k) + self.comboBox_2.addItem(k) + + self.variables.populate(self._reader.parameter) + + @QtCore.pyqtSlot() + def get_selected(self): + + if self.comboBox.currentIndex() == 0: + value = None + else: + value = self.comboBox.currentText() + + if self.comboBox_2.currentIndex() == 0: + group = None + else: + group = self.comboBox_2.currentText() + + iterator = QtWidgets.QTreeWidgetItemIterator(self.treewidget, QtWidgets.QTreeWidgetItemIterator.NoChildren) + selected = [] + while iterator.value(): + item = iterator.value() + iterator += 1 + if item.checkState(0) == QtCore.Qt.Checked: + path = item.text(0) + parent = item.parent() + while parent is not None: + path = parent.text(0) + '/' + path + parent = parent.parent() + + if item.checkState(1) == QtCore.Qt.Checked: + selected.extend(self._reader.get_selected(path, flag='spectrum', value=value, group=group)) + else: + selected.extend(self._reader.get_selected(path, value=value, group=group)) + + self.data_read.emit(selected) + + def accept(self): + self.get_selected() + self.close() + + +class VarTable(QtWidgets.QTableWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.setColumnCount(2) + self.setHorizontalHeaderLabels(['Key', 'Value']) + self.horizontalHeader().setStretchLastSection(True) + self.verticalHeader().setVisible(False) + self.horizontalHeader().setVisible(True) + + def populate(self, vars: dict): + self.setHorizontalHeaderLabels(['Key', 'Value']) + self.setRowCount(len(vars)) + for i, (k, v) in enumerate(vars.items()): + key_item = QtWidgets.QTableWidgetItem(k) + key_item.setFlags(QtCore.Qt.NoItemFlags) + key_item.setForeground(QtGui.QBrush(QtGui.QColor(0, 0, 0))) + if isinstance(v, list): + val = f'<{len(v)} values>' + if len(v) < 40: + tip = '\n'.join(str(p) for p in v) + else: + tip = '\n'.join(str(p) for p in v[:40]) + tip += '\n...' + else: + val = str(v) + tip = val + value_item = QtWidgets.QTableWidgetItem(val) + value_item.setFlags(QtCore.Qt.NoItemFlags) + value_item.setForeground(QtGui.QBrush(QtGui.QColor(0, 0, 0))) + value_item.setToolTip(tip) + self.setItem(i, 0, key_item) + self.setItem(i, 1, value_item) + + +class HDFTreeWidget(QtWidgets.QTreeWidget): + def __init__(self, parent): + super().__init__(parent=parent) + + self.setHeaderLabels(['Data', 'Spectrum?']) + self.header().setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch) + self.header().setSectionResizeMode(1, QtWidgets.QHeaderView.Fixed) + self.header().setStretchLastSection(False) + self.header().setCascadingSectionResizes(True) + self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectItems) + + self.itemChanged.connect(self.change_item) + + def keyPressEvent(self, evt: QtGui.QKeyEvent): + if evt.key() == QtCore.Qt.Key_Space: + for idx in self.selectedIndexes(): + item = self.itemFromIndex(idx) + col = idx.column() + cs = item.checkState(col) + item.setCheckState(col, QtCore.Qt.Unchecked if cs == QtCore.Qt.Checked else QtCore.Qt.Checked) + else: + super().keyPressEvent(evt) + + @staticmethod + def change_item(item: QtWidgets.QTreeWidgetItem, column: int): + state = item.checkState(column) + for i in range(item.childCount()): + child = item.child(i) + child.setCheckState(column, state) + + +if __name__ == '__main__': + import sys + + app = QtWidgets.QApplication([]) + # w = QHdfViewer('/autohome/dominik/nmreval/testdata/fc_test/abc.h5') + w = QHdfViewer('/autohome/dominik/nmreval/testdata/L8_313K_17O_GG_KG_2020-12-02_1535.h5') + + w.show() + + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/io/nmrreader.py b/nmreval/gui_qt/io/nmrreader.py new file mode 100644 index 0000000..6e2a374 --- /dev/null +++ b/nmreval/gui_qt/io/nmrreader.py @@ -0,0 +1,34 @@ +from struct import unpack + +from ...io.nmrreader import NMRReader + +from ..Qt import QtCore + + +class QNMRReader(QtCore.QObject): + data_read = QtCore.pyqtSignal(list) + file_ext = ['.nmr'] + + def __init__(self): + super().__init__() + self._reader = NMRReader() + + def __call__(self, fname): + with fname.open('rb') as fp: + s16 = fp.read(16) + + # copied from whichdb (Python 2.7) to look for magic value of dbhash + (magic,) = unpack("=l", s16[-4:]) + if magic in (0x00061561, 0x61150600): + self._reader(fname, '-1') + + else: + (magic,) = unpack('<16s', s16) + if magic.startswith(b'NMREVAL'): + self._reader(fname, str(magic[7:].rstrip(b'\x00'), 'utf8')) + + return self + + def exec(self): + data = self._reader.make_data() + self.data_read.emit([data]) diff --git a/nmreval/gui_qt/io/save_fitparameter.py b/nmreval/gui_qt/io/save_fitparameter.py new file mode 100644 index 0000000..4c7b63a --- /dev/null +++ b/nmreval/gui_qt/io/save_fitparameter.py @@ -0,0 +1,78 @@ +from ..Qt import QtWidgets, QtCore, QtGui +from .._py.save_fit_parameter import Ui_fitparameter_save_dialog + + +class QSaveFit(QtWidgets.QDialog, Ui_fitparameter_save_dialog): + def __init__(self, path: str = None, parent=None): + super().__init__(parent=parent) + + self.pnames = None + self.outpath = path + + self.setupUi(self) + + self.tableWidget.cellDoubleClicked.connect(self.clicketyclick) + self.tableWidget.setColumnCount(2) + + self.save_path_line.textEdited.connect(lambda: self.change_path(self.save_path_line.text())) + self.save_path_button.clicked.connect(self.set_save_path) + + self.header_edit.hide() + self.header_checkBox.stateChanged.connect(lambda state: self.header_edit.setVisible(state)) + + self.missing_value_line.setValidator(QtGui.QDoubleValidator()) + + def set_parameter(self, fits: dict): + for model_name, parameter in fits.items(): + for p in parameter: + item = QtWidgets.QTableWidgetItem(p) + item2 = QtWidgets.QTableWidgetItem(model_name) + item2.setToolTip(model_name) + row = self.tableWidget.rowCount() + self.tableWidget.setRowCount(row+1) + self.tableWidget.setItem(row, 0, item) + self.tableWidget.setItem(row, 1, item2) + + self.tableWidget.resizeColumnsToContents() + + @QtCore.pyqtSlot(int, int) + def clicketyclick(self, row: int, _): + if self.col_line.text(): + self.col_line.setText(self.col_line.text() + '; ' + self.tableWidget.item(row, 0).text()) + else: + self.col_line.setText(self.tableWidget.item(row, 0).text()) + + def set_save_path(self): + fname, _ = QtWidgets.QFileDialog.getSaveFileName(options=QtWidgets.QFileDialog.DontConfirmOverwrite, + directory=self.outpath) + + if fname: + self.outpath = fname + self.save_path_line.setText(fname) + + def add_header(self, idx: int): + self.textEdit.setVisible(idx != 0) + + @QtCore.pyqtSlot(name='on_usage_button_clicked') + def show_usage(self): + _ = QtWidgets.QMessageBox.information(self, 'Usage', + 'Separate each column by semicolon.\n' + 'Use p_err to save error of parameter p.\n' + 'If a column shall contain different parameters use {p1/p2}.\n' + 'KWW mean is calculated by mean(τ,β), KWW peak by peak(τ,β).') + + def accept(self): + super().accept() + + +if __name__ == '__main__': + import sys + + app = QtWidgets.QApplication([]) + + dialog = QSaveFit() + dialog.set_parameter({'fit1': ['p1', 'p2'], 'fit2': ['p2', 'p3']}) + + dialog.show() + + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/io/tntreader.py b/nmreval/gui_qt/io/tntreader.py new file mode 100644 index 0000000..cd97c76 --- /dev/null +++ b/nmreval/gui_qt/io/tntreader.py @@ -0,0 +1,109 @@ +from ...io.tntreader import TNTReader + +from ..Qt import QtCore, QtWidgets +from .._py.tntdialog import Ui_tntdialog + + +class QTNTReader(QtWidgets.QDialog, Ui_tntdialog): + data_read = QtCore.pyqtSignal(dict) + file_ext = ['.tnt'] + + def __init__(self, fname=None, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self.reader = TNTReader(fname) + + self.frame.hide() + + if fname is not None: + if self.reader.onedimensional: + self.export() + else: + self.set_gui() + + def __call__(self, fname, *args, **kwargs): + self.reader(fname) + for s in [self.widget, self.widget_2, self.widget_3]: + s.__call__() + + self.frame.hide() + self.frame_2.show() + self.unknown_delay_combobox.clear() + + if self.reader.onedimensional: + self.export() + else: + self.set_gui() + + return self + + def set_gui(self): + self.label_3.setText(' x '.join(map(str, self.reader.shape))) + for i, w in enumerate([self.widget, self.widget_2, self.widget_3], start=1): + if self.reader.shape[i] == 1: + w.hide() + else: + w.label.setText('Dimension {}'.format(i+1)) + w.dim = i + w.add_items([x[0] for x in self.reader.delays.items() if len(x[1]) == self.reader.shape[i]]) + w.get_data.connect(self.show_delays) + w.newDelay.connect(self.calc_delays) + for x in self.reader.delays.items(): + if len(x[1]) in self.reader.shape[1:]: + continue + else: + self.unknown_delay_combobox.addItem(x[0]) + if self.unknown_delay_combobox.count() == 0: + self.frame_2.hide() + + @QtCore.pyqtSlot(str) + def show_delays(self, label): + vals = self.reader.delays[str(label)] + self.sender().vals = '\n'.join(map(str, vals)) + + def calc_delays(self): + self.frame.show() + self._caller = self.sender() + + @QtCore.pyqtSlot(name='on_pushButton_2_clicked') + def cancel_delay(self): + self.frame.hide() + + @QtCore.pyqtSlot(name='on_pushButton_clicked') + def add_delay(self): + try: + s = float(self.start_lineedit.text()) + except ValueError: + return + try: + e = float(self.end_lineedit.text()) + except ValueError: + return + d = [] + for w in [self.widget, self.widget_2, self.widget_3]: + if w.isVisible(): + d.append(w.comboBox.currentText()) + self.reader.add_delay(s, e, self._caller.dim, self.lineEdit.text(), + staggered=self.checkBox_2.isChecked(), stag_steps=int(self.spinBox.value()), + log=self.checkBox.isChecked()) + self._caller.add_items(self.lineEdit.text()) + self.frame.hide() + + def export(self): + d = [] + for w in [self.widget, self.widget_2, self.widget_3]: + if w.isVisible(): + d.append(w.comboBox.currentText()) + else: + d.append(None) + + ret_dic = self.reader.export(d) + + self.data_read.emit(ret_dic) + self.close() + + return ret_dic + + def accept(self): + self.export() diff --git a/nmreval/gui_qt/lib/__init__.py b/nmreval/gui_qt/lib/__init__.py new file mode 100644 index 0000000..f273183 --- /dev/null +++ b/nmreval/gui_qt/lib/__init__.py @@ -0,0 +1,76 @@ +import sys + +if sys.version_info < (3, 7): + HAS_IMPORTLIB_RESOURCE = False + from pkg_resources import resource_filename +else: + HAS_IMPORTLIB_RESOURCE = True + from importlib.resources import path + +from ..Qt import QtGui, QtWidgets + + +# def get_path_importlib(package, resource): +# return path(package, resource) +# +# +# def _get_path_pkg(package, resource): +# return resource_filename(package, resource) +# +# +# if HAS_IMPORTLIB_RESOURCE: +# get_path = get_path_importlib +# else: +# get_path = _get_path_pkg + + +def make_action_icons(widget): + global HAS_IMPORTLIB_RESOURCE + icon_type = QtWidgets.QApplication.instance().theme + from json import loads + + if HAS_IMPORTLIB_RESOURCE: + with path('resources.icons', 'icons.json') as fp: + with fp.open('r') as f: + icon_list = loads(f.read()) + + for ac, img in icon_list[widget.objectName()].items(): + dirname = 'resources.icons.%s_light' % icon_type + with path(dirname, img+'.png') as imgpath: + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(str(imgpath)), QtGui.QIcon.Normal, QtGui.QIcon.Off) + getattr(widget, ac).setIcon(icon) + + else: + with open(resource_filename('resources.icons', 'icons.json'), 'r') as f: + icon_list = loads(f.read()) + + for ac, img in icon_list[widget.objectName()].items(): + dirname = 'resources.icons.%s_light' % icon_type + imgpath = resource_filename(dirname, img+'.png') + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(str(imgpath)), QtGui.QIcon.Normal, QtGui.QIcon.Off) + getattr(widget, ac).setIcon(icon) + + +def get_icon(icon_name): + try: + icon_type = QtWidgets.QApplication.instance().theme + except AttributeError: + icon_type = 'normal' + + global HAS_IMPORTLIB_RESOURCE + + dirname = 'resources.icons.%s_light' % icon_type + if HAS_IMPORTLIB_RESOURCE: + with path(dirname, icon_name+'.png') as imgpath: + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(str(imgpath)), QtGui.QIcon.Normal, QtGui.QIcon.Off) + + return icon + else: + imgpath = resource_filename(dirname, icon_name+'.png') + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(imgpath), QtGui.QIcon.Normal, QtGui.QIcon.Off) + + return icon diff --git a/nmreval/gui_qt/lib/codeeditor.py b/nmreval/gui_qt/lib/codeeditor.py new file mode 100644 index 0000000..245a9e1 --- /dev/null +++ b/nmreval/gui_qt/lib/codeeditor.py @@ -0,0 +1,262 @@ +# CodeEditor based on QT example, Python syntax highlighter found on Python site + + +from ..Qt import QtGui, QtCore, QtWidgets + + +def _make_textformats(color, style=''): + """Return a QTextCharFormat with the given attributes. + """ + _color = QtGui.QColor() + _color.setNamedColor(color) + + _format = QtGui.QTextCharFormat() + _format.setForeground(_color) + if 'bold' in style: + _format.setFontWeight(QtGui.QFont.Bold) + if 'italic' in style: + _format.setFontItalic(True) + + return _format + + +# Syntax styles that can be shared by all languages +STYLES = { + 'keyword': _make_textformats('blue'), + 'operator': _make_textformats('black'), + 'brace': _make_textformats('black'), + 'defclass': _make_textformats('black', 'bold'), + 'string': _make_textformats('darkGreen'), + 'comment': _make_textformats('gray', 'italic'), + 'self': _make_textformats('brown', 'italic'), + 'property': _make_textformats('brown'), + 'numbers': _make_textformats('darkRed'), +} + + +class PythonHighlighter(QtGui.QSyntaxHighlighter): + """ + Syntax highlighter for the Python language. + """ + # Python keywords + keywords = [ + 'and', 'assert', 'break', 'class', 'continue', 'def', + 'del', 'elif', 'else', 'except', 'exec', 'finally', + 'for', 'from', 'global', 'if', 'import', 'in', + 'is', 'lambda', 'not', 'or', 'pass', 'print', + 'raise', 'return', 'try', 'while', 'yield', + 'None', 'True', 'False', 'object' + ] + + def __init__(self, document): + super().__init__(document) + + # Multi-line strings (expression, flag, style) + # FIXME: The triple-quotes in these two lines will mess up the + # syntax highlighting from this point onward + self.tri_single = (QtCore.QRegExp("r'{3}"), 1, STYLES['string']) + self.tri_double = (QtCore.QRegExp('r?"{3}'), 2, STYLES['string']) + + rules = [] + + # Keyword, operator, and brace rules + rules += [(rf'\b{w}\b', 0, STYLES['keyword']) for w in PythonHighlighter.keywords] + + # Other rules + rules += [ + # 'self' + (r'\bself\b', 0, STYLES['self']), + + # 'def' followed by an identifier + (r'\bdef\b\s*(\w+)', 1, STYLES['defclass']), + # 'class' followed by an identifier + (r'\bclass\b\s*(\w+)', 1, STYLES['defclass']), + # @ followed by a word + (r'\s*@(\w+)\s*', 0, STYLES['property']), + + # Numeric literals + (r'\b[+-]?\d+[lL]?\b', 0, STYLES['numbers']), + (r'\b[+-]?0[xX][\dA-Fa-f]+[lL]?\b', 0, STYLES['numbers']), + (r'\b[+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b', 0, STYLES['numbers']), + + + # Double-quoted string, possibly containing escape sequences + (r'[rf]?"[^"\\]*(\\.[^"\\]*)*"', 0, STYLES['string']), + # Single-quoted string, possibly containing escape sequences + (r"[rf]?'[^'\\]*(\\.[^'\\]*)*'", 0, STYLES['string']), + + # From '#' until a newline + (r'#[^\n]*', 0, STYLES['comment']), + ] + + # Build a QRegExp for each pattern + self.rules = [(QtCore.QRegExp(pat), index, fmt) for (pat, index, fmt) in rules] + + def highlightBlock(self, text): + """ + Apply syntax highlighting to the given block of text. + """ + # Do other syntax formatting + for expression, nth, rule in self.rules: + index = expression.indexIn(text, 0) + + while index >= 0: + # We actually want the index of the nth match + index = expression.pos(nth) + length = len(expression.cap(nth)) + self.setFormat(index, length, rule) + index = expression.indexIn(text, index + length) + + self.setCurrentBlockState(0) + + # Do multi-line strings + in_multiline = self.match_multiline(text, *self.tri_single) + if not in_multiline: + in_multiline = self.match_multiline(text, *self.tri_double) + + def match_multiline(self, text, delimiter, in_state, style): + """ + Highlighting of multi-line strings. ``delimiter`` should be a + ``QRegExp`` for triple-single-quotes or triple-double-quotes, and + ``in_state`` should be a unique integer to represent the corresponding + state changes when inside those strings. Returns True if we're still + inside a multi-line string when this function is finished. + """ + # If inside triple-single quotes, start at 0 + if self.previousBlockState() == in_state: + start = 0 + add = 0 + # Otherwise, look for the delimiter on this line + else: + start = delimiter.indexIn(text) + # Move past this match + add = delimiter.matchedLength() + + # As long as there's a delimiter match on this line... + while start >= 0: + # Look for the ending delimiter + end = delimiter.indexIn(text, start + add) + # Ending delimiter on this line? + if end >= add: + length = end - start + add + delimiter.matchedLength() + self.setCurrentBlockState(0) + # No; multi-line string + else: + self.setCurrentBlockState(in_state) + try: + length = text.length() - start + add + except AttributeError: + length = len(text) - start + add + # Apply formatting + self.setFormat(start, length, style) + # Look for the next match + start = delimiter.indexIn(text, start + length) + + # Return True if still inside a multi-line string, False otherwise + if self.currentBlockState() == in_state: + return True + else: + return False + + +class LineNumbers(QtWidgets.QWidget): + def __init__(self, editor): + super().__init__(editor) + self.editor = editor + + def sizeHint(self): + return QtCore.QSize(self.editor.width_linenumber, 0) + + def paintEvent(self, event): + self.editor.paintevent_linenumber(event) + + +class CodeEditor(QtWidgets.QPlainTextEdit): + # more or less a direct translation of the Qt example + def __init__(self, parent): + super().__init__(parent) + + self.current_linenumber = LineNumbers(self) + + self.blockCountChanged.connect(self.update_width_linenumber) + self.updateRequest.connect(self.update_current_area) + self.cursorPositionChanged.connect(self.highlight_current_line) + self.update_width_linenumber(0) + + self.highlight = PythonHighlighter(self.document()) + + def keyPressEvent(self, evt): + if evt.key() == QtCore.Qt.Key_Tab: + # use spaces instead of tab + self.insertPlainText(' '*4) + elif evt.key() == QtCore.Qt.Key_Insert: + self.setOverwriteMode(not self.overwriteMode()) + else: + super().keyPressEvent(evt) + + @property + def width_linenumber(self): + digits = 1 + count = max(1, self.blockCount()) + while count >= 10: + count /= 10 + digits += 1 + space = 6 + self.fontMetrics().width('9') * digits + + return space + + def update_width_linenumber(self, _): + self.setViewportMargins(self.width_linenumber, 0, 0, 0) + + def update_current_area(self, rect, dy): + if dy: + self.current_linenumber.scroll(0, dy) + else: + self.current_linenumber.update(0, rect.y(), self.current_linenumber.width(), rect.height()) + if rect.contains(self.viewport().rect()): + self.update_width_linenumber(0) + + def resizeEvent(self, evt): + super().resizeEvent(evt) + + cr = self.contentsRect() + self.current_linenumber.setGeometry(QtCore.QRect(cr.left(), cr.top(), self.width_linenumber, cr.height())) + + def paintevent_linenumber(self, evt): + painter = QtGui.QPainter(self.current_linenumber) + painter.fillRect(evt.rect(), QtCore.Qt.lightGray) + + block = self.firstVisibleBlock() + block_number = block.blockNumber() + top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top() + bottom = top + self.blockBoundingRect(block).height() + + # Just to make sure I use the right font + height = self.fontMetrics().height() + while block.isValid() and (top <= evt.rect().bottom()): + if block.isVisible() and (bottom >= evt.rect().top()): + number = str(block_number + 1) + painter.setPen(QtCore.Qt.black) + painter.drawText(0, top, self.current_linenumber.width() - 3, height, + QtCore.Qt.AlignRight, number) + + block = block.next() + top = bottom + bottom = top + self.blockBoundingRect(block).height() + block_number += 1 + + def highlight_current_line(self): + extra_selections = [] + + if not self.isReadOnly(): + selection = QtWidgets.QTextEdit.ExtraSelection() + + line_color = QtGui.QColor(QtCore.Qt.yellow).lighter(180) + + selection.format.setBackground(line_color) + selection.format.setProperty(QtGui.QTextFormat.FullWidthSelection, True) + selection.cursor = self.textCursor() + selection.cursor.clearSelection() + extra_selections.append(selection) + + self.setExtraSelections(extra_selections) diff --git a/nmreval/gui_qt/lib/color_dialog.py b/nmreval/gui_qt/lib/color_dialog.py new file mode 100644 index 0000000..0c51f64 --- /dev/null +++ b/nmreval/gui_qt/lib/color_dialog.py @@ -0,0 +1,89 @@ +from nmreval.configs import config_paths +from nmreval.gui_qt.Qt import QtWidgets, QtCore, QtGui +from nmreval.gui_qt._py.color_palette import Ui_Dialog +from nmreval.lib.colors import Colors, get_palettes + + +class PaletteDialog(QtWidgets.QDialog, Ui_Dialog): + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self._palettes = get_palettes() + self.palette_combobox.addItems(self._palettes.keys()) + + self.colorlist.installEventFilter(self) + + def eventFilter(self, src: QtCore.QObject, evt: QtCore.QEvent) -> bool: + if evt.type() == evt.KeyPress: + if evt.key() == QtCore.Qt.Key_Delete: + self.colorlist.takeItem(self.colorlist.currentRow()) + + return True + + return super().eventFilter(src, evt) + + @QtCore.pyqtSlot(name='on_add_palette_button_pressed') + @QtCore.pyqtSlot(name='on_append_palette_button_pressed') + def set_palette(self, clear=True): + if self.sender() == self.add_palette_button or clear: + self.colorlist.clear() + + for color in self._palettes[self.palette_combobox.currentText()]: + item = QtWidgets.QListWidgetItem(color.name) + item.setData(QtCore.Qt.DecorationRole, QtGui.QColor.fromRgbF(*color.rgb(normed=True))) + self.colorlist.addItem(item) + + @QtCore.pyqtSlot(name='on_add_color_button_pressed') + def add_color(self): + color = self.color_combobox.value + item = QtWidgets.QListWidgetItem(color.name) + item.setData(QtCore.Qt.DecorationRole, QtGui.QColor.fromRgbF(*color.rgb(normed=True))) + self.colorlist.addItem(item) + + @QtCore.pyqtSlot(name='on_save_button_pressed') + def save_new_palette(self): + if not self.colorlist.count(): + _ = QtWidgets.QMessageBox.warning(self, 'Error', 'No colors to save.') + return + + if not self.new_name_edit.text(): + _ = QtWidgets.QMessageBox.warning(self, 'Error', 'New colors have no name.') + return + + color_name = self.new_name_edit.text() + if color_name in self._palettes: + _ = QtWidgets.QMessageBox.warning(self, 'Error', 'Name already used.') + return + + color_file = config_paths() / 'colorschemes.cfg' + + new_palette = [] + with color_file.open('a') as f: + f.write('#-- %s\n' % color_name) + for i in range(self.colorlist.count()): + item = self.colorlist.item(i) + r, g, b = item.data(QtCore.Qt.DecorationRole).getRgbF()[:3] + new_palette.append(Colors.from_rgb(r, g, b, normed=True)) + f.write('{r*255:.1f}, {g*255:.1f}, {b*255:.1f}\n') + f.write('%.1f, %.1f}, %.1f}\n' % (r*255, g*255, b*255)) + f.write('\n') + + self._palettes[color_name] = new_palette + self.palette_combobox.addItem(color_name) + + def load_palette(self, name: str): + idx = self.palette_combobox.findText(name) + if idx != -1: + self.palette_combobox.setCurrentIndex(idx) + self.set_palette(clear=True) + + +if __name__ == '__main__': + import sys + app = QtWidgets.QApplication([]) + d = PaletteDialog() + d.show() + + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/lib/configurations.py b/nmreval/gui_qt/lib/configurations.py new file mode 100644 index 0000000..0bc114f --- /dev/null +++ b/nmreval/gui_qt/lib/configurations.py @@ -0,0 +1,156 @@ +import os + +from ...configs import * +from ...io.graceeditor import GraceEditor + +from ..Qt import QtWidgets, QtGui +from .._py.agroptiondialog import Ui_Dialog + + +class QGraceSettings(QtWidgets.QDialog, Ui_Dialog): + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.setupUi(self) + self._default_path = config_paths().joinpath('Default.agr') + self._default = GraceEditor(self._default_path) + + self.setup_ui() + + def setup_ui(self): + page = self._default.size + self.widthDoubleSpinBox.setValue(page[0]) + self.heightDoubleSpinBox.setValue(page[1]) + + view = self._default.get_property(0, 'view') + self.leftMarginDoubleSpinBox.setValue(self._default.convert(view[0], direction='abs')) + self.bottomMarginDoubleSpinBox.setValue(self._default.convert(view[1], direction='abs')) + self.rightMarginDoubleSpinBox.setValue(page[0]-self._default.convert(view[2], direction='abs')) + self.topMarginDoubleSpinBox.setValue(page[1]-self._default.convert(view[3], direction='abs')) + + +class GraceMsgBox(QtWidgets.QDialog): + def __init__(self, fname, parent=None): + super(GraceMsgBox, self).__init__(parent=parent) + + agr = GraceEditor() + agr.parse(fname) + + layout = QtWidgets.QGridLayout() + layout.setContentsMargins(13, 13, 13, 13) + self.setLayout(layout) + + label = QtWidgets.QLabel('%s already exists. Select one of the options or cancel:' % os.path.split(fname)[1]) + layout.addWidget(label, 1, 1, 1, 2) + + self.button_grp = QtWidgets.QButtonGroup(self) + + self.overwrite_radiobutton = QtWidgets.QRadioButton('Overwrite file', parent=self) + self.overwrite_radiobutton.setChecked(True) + self.button_grp.addButton(self.overwrite_radiobutton, id=0) + layout.addWidget(self.overwrite_radiobutton, 2, 1, 1, 2) + + self.new_graph_button = QtWidgets.QRadioButton('Create new graph', parent=self) + self.button_grp.addButton(self.new_graph_button, id=1) + layout.addWidget(self.new_graph_button, 3, 1, 1, 2) + + self.addgraph_button = QtWidgets.QRadioButton('Add sets to graph', parent=self) + self.button_grp.addButton(self.addgraph_button, id=3) + layout.addWidget(self.addgraph_button, 4, 1, 1, 1) + + self.graph_combobox = QtWidgets.QComboBox(self) + self.graph_combobox.addItems(['G' + str(g.idx) for g in agr.graphs]) + layout.addWidget(self.graph_combobox, 4, 2, 1, 1) + + self.buttonbox = QtWidgets.QDialogButtonBox(self) + self.buttonbox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok) + layout.addWidget(self.buttonbox, 5, 1, 1, 2) + + self.buttonbox.rejected.connect(self.reject) + self.buttonbox.accepted.connect(self.accept) + + def accept(self) -> None: + super().accept() + self.setResult(self.button_grp.checkedId()) + if self.button_grp.checkedId() == 3: + self.setResult(int(self.graph_combobox.currentText()[1:]) + 2) + + def reject(self) -> None: + super().reject() + self.setResult(-1) + + +class GeneralConfiguration(QtWidgets.QDialog): + def __init__(self, parent=None): + super().__init__(parent=parent) + + layout = QtWidgets.QVBoxLayout() + layout.setContentsMargins(3, 3, 3, 3) + + intro = QtWidgets.QLabel('Changes become active after restart.') + layout.addWidget(intro) + + parser = read_configuration() + for sec in parser.sections(): + group = QtWidgets.QGroupBox(sec, self) + + layout2 = QtWidgets.QGridLayout() + layout2.setContentsMargins(3, 3, 3, 3) + row = 0 + for key, value in parser.items(sec): + label = QtWidgets.QLabel(key.capitalize(), self) + layout2.addWidget(label, row, 0) + if (sec, key) in allowed_values: + edit = QtWidgets.QComboBox(self) + edit.addItems(allowed_values[(sec, key)]) + edit.setCurrentIndex(edit.findText(value)) + else: + edit = QtWidgets.QLineEdit(self) + edit.setText(value) + try: + _ = float(value) + edit.setValidator(QtGui.QDoubleValidator()) + except ValueError: + pass + + layout2.addWidget(edit, row, 1) + row += 1 + + group.setLayout(layout2) + + layout.addWidget(group) + + self.buttonbox = QtWidgets.QDialogButtonBox(self) + self.buttonbox.setStandardButtons(self.buttonbox.Ok|self.buttonbox.Cancel) + self.buttonbox.rejected.connect(self.close) + self.buttonbox.accepted.connect(self.accept) + layout.addWidget(self.buttonbox) + + self.setLayout(layout) + + def accept(self): + options = {} + for section in self.findChildren(QtWidgets.QGroupBox): + args = {} + + layout = section.layout() + for row in range(layout.rowCount()): + key = layout.itemAtPosition(row, 0).widget().text() + + value_widget = layout.itemAtPosition(row, 1).widget() + if isinstance(value_widget, QtWidgets.QComboBox): + value = value_widget.currentText() + elif isinstance(value_widget, QtWidgets.QLineEdit): + value = value_widget.text() + elif isinstance(value_widget, QtWidgets.QDoubleSpinBox): + value = value_widget.text() + else: + raise TypeError('Config key %s has unknown type %s' % (key, repr(value_widget))) + + args[key] = value + + options[section.title()] = args + + write_configuration(options) + + super().accept() diff --git a/nmreval/gui_qt/lib/decorators.py b/nmreval/gui_qt/lib/decorators.py new file mode 100644 index 0000000..9f40149 --- /dev/null +++ b/nmreval/gui_qt/lib/decorators.py @@ -0,0 +1,55 @@ +from functools import wraps + +from ..Qt import QtWidgets + + +def update_indexes(func): + + @wraps(func) + def wrapped(self, *args, **kwargs): + ret_val = func(self, *args, **kwargs) + self.blockSignals(True) + + iterator = QtWidgets.QTreeWidgetItemIterator(self) + i = j = 0 + while iterator.value(): + item = iterator.value() + if item is not None: + if item.parent() is None: + item.setText(1, 'g[{}]'.format(i)) + i += 1 + j = 0 + else: + item.setText(1, '.s[{}]'.format(j)) + j += 1 + iterator += 1 + + self.blockSignals(False) + + return ret_val + + return wrapped + + +def plot_update(func): + + @wraps(func) + def wrapped(self, *args, **kwargs): + ret_val = func(self, *args, **kwargs) + m = self._data.mask + _x = self._data.x + _y = self._data.y + + self.plot_real.setData(x=_x[m], y=_y.real[m], name=self._data.name) + if self.plot_imag is not None: + self.plot_imag.setData(x=_x[m], y=_y.imag[m], name=self._data.name) + + if self.plot_error is not None: + _y_err = self._data.y_err + self.plot_error.setData(x=_x[m], y=_y.real[m], top=_y_err[m], bottom=_y_err[m]) + + self.dataChanged.emit(self.id) + + return ret_val + + return wrapped diff --git a/nmreval/gui_qt/lib/delegates.py b/nmreval/gui_qt/lib/delegates.py new file mode 100644 index 0000000..50f79eb --- /dev/null +++ b/nmreval/gui_qt/lib/delegates.py @@ -0,0 +1,235 @@ +import re + +from ..Qt import QtWidgets, QtGui, QtCore + +from ...lib.colors import BaseColor, Colors +from ...lib.lines import LineStyle +from ...lib.symbols import SymbolStyle, make_symbol_pixmap + + +class PropertyDelegate(QtWidgets.QStyledItemDelegate): + def paint(self, painter: QtGui.QPainter, options: QtWidgets.QStyleOptionViewItem, idx: QtCore.QModelIndex): + r = idx.data(QtCore.Qt.DisplayRole) + if r is not None: + if isinstance(r, BaseColor): + painter.save() + c = QtGui.QColor(*r.value) + rect = options.rect + painter.fillRect(rect, QtGui.QBrush(c)) + painter.restore() + + elif isinstance(r, LineStyle): + painter.save() + pen = QtGui.QPen() + pal = QtGui.QGuiApplication.palette() + pen.setColor(pal.color(QtGui.QPalette.Text)) + pen.setWidth(2) + pen.setStyle(r.value) + pen.setCapStyle(QtCore.Qt.RoundCap) + painter.setPen(pen) + + rect = options.rect + rect.adjust(5, 0, -5, 0) + mid = (rect.bottom()+rect.top()) / 2 + painter.drawLine(rect.left(), mid, rect.right(), mid) + painter.restore() + + elif isinstance(r, SymbolStyle): + painter.save() + pen = QtGui.QPen() + pal = QtGui.QGuiApplication.palette() + pen.setColor(pal.color(QtGui.QPalette.Text)) + painter.setPen(pen) + + pm = make_symbol_pixmap(r) + painter.drawPixmap(options.rect.topLeft()+QtCore.QPoint(3, (options.rect.height()-pm.height())/2), pm) + + style = QtWidgets.QApplication.style() + text_rect = style.subElementRect(QtWidgets.QStyle.SE_ItemViewItemText, options, None) + text_rect.adjust(5+pm.width(), 0, 0, 0) + painter.drawText(text_rect, options.displayAlignment, r.name) + + painter.restore() + + else: + super().paint(painter, options, idx) + + def createEditor(self, parent: QtWidgets.QWidget, + options: QtWidgets.QStyleOptionViewItem, idx: QtCore.QModelIndex) -> QtWidgets.QWidget: + data = idx.data() + if isinstance(data, BaseColor): + editor = ColorListEditor(parent) + + elif isinstance(data, LineStyle): + editor = LineStyleEditor(parent) + + elif isinstance(data, SymbolStyle): + editor = SymbolStyleEditor(parent) + + elif isinstance(data, float): + editor = SpinBoxEditor(parent) + + else: + editor = super().createEditor(parent, options, idx) + + return editor + + def setEditorData(self, editor: QtWidgets.QWidget, idx: QtCore.QModelIndex): + data = idx.data() + if isinstance(data, (BaseColor, LineStyle, SymbolStyle)): + editor.value = data + else: + super().setEditorData(editor, idx) + + def setModelData(self, editor: QtWidgets.QWidget, model: QtCore.QAbstractItemModel, idx: QtCore.QModelIndex): + data = idx.data() + if isinstance(data, (BaseColor, LineStyle, SymbolStyle)): + model.setData(idx, editor.value) + else: + super().setModelData(editor, model, idx) + + +class ColorListEditor(QtWidgets.QComboBox): + def __init__(self, parent=None): + super().__init__(parent) + self.populateList() + + @QtCore.pyqtProperty(BaseColor, user=True) + def value(self): + return self.itemData(self.currentIndex()) + + @value.setter + def value(self, val): + for i in range(self.count()): + if val == self.itemData(i): + self.setCurrentIndex(i) + break + + def populateList(self): + for i, colorName in enumerate(Colors): + color = QtGui.QColor(*colorName.value) + self.insertItem(i, colorName.name) + self.setItemData(i, colorName) + px = QtGui.QPixmap(self.iconSize()) + px.fill(color) + self.setItemData(i, QtGui.QIcon(px), QtCore.Qt.DecorationRole) + + +class SpinBoxEditor(QtWidgets.QDoubleSpinBox): + def __init__(self, parent=None): + super().__init__(parent) + self.setValue(1.0) + self.setSingleStep(0.1) + self.setDecimals(1) + + @QtCore.pyqtProperty(float, user=True) + def value(self): + return super().value() + + @value.setter + def value(self, val): + super().setValue(val) + + +class LineStyleEditor(QtWidgets.QComboBox): + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.setItemDelegate(LineStyleDelegate()) + self.populate() + + @QtCore.pyqtProperty(int, user=True) + def value(self): + return self.itemData(self.currentIndex()) + + @value.setter + def value(self, val): + for i in range(self.count()): + if val == self.itemData(i): + self.setCurrentIndex(i) + break + + def populate(self): + for i, style in enumerate(LineStyle): + self.insertItem(i, re.sub(r'([A-Z])', r' \g<1>', style.name)) + self.setItemData(i, style) + + def paintEvent(self, evt: QtGui.QPaintEvent): + if self.currentData() is not None: + painter = QtWidgets.QStylePainter(self) + opt = QtWidgets.QStyleOptionComboBox() + self.initStyleOption(opt) + painter.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, opt) + pen = QtGui.QPen() + pal = QtGui.QGuiApplication.palette() + pen.setColor(pal.color(QtGui.QPalette.Text)) + pen.setWidth(2) + pen.setStyle(self.currentData().value) + pen.setCapStyle(QtCore.Qt.RoundCap) + painter.setPen(pen) + + rect = painter.style().subControlRect(QtWidgets.QStyle.CC_ComboBox, + opt, QtWidgets.QStyle.SC_ComboBoxEditField, None) + rect.adjust(+10, 0, -10, 0) + mid = (rect.bottom() + rect.top()) / 2 + painter.drawLine(rect.left(), mid, rect.right(), mid) + painter.end() + else: + super().paintEvent(evt) + + +class LineStyleDelegate(QtWidgets.QStyledItemDelegate): + def paint(self, painter, option, index): + data = index.data(QtCore.Qt.UserRole) + + if data is not None: + pen = QtGui.QPen() + pal = QtGui.QGuiApplication.palette() + pen.setColor(pal.color(QtGui.QPalette.Text)) + pen.setWidth(2) + pen.setStyle(data.value) + pen.setCapStyle(QtCore.Qt.RoundCap) + painter.setPen(pen) + + rect = option.rect + rect.adjust(+10, 0, -10, 0) + mid = (rect.bottom()+rect.top()) / 2 + painter.drawLine(rect.left(), mid, rect.right(), mid) + else: + QtWidgets.QStyledItemDelegate.paint(self, painter, option, index) + + +class SymbolStyleEditor(QtWidgets.QComboBox): + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.populate() + + @QtCore.pyqtProperty(SymbolStyle, user=True) + def value(self): + return self.itemData(self.currentIndex()) + + @value.setter + def value(self, val): + for i in range(self.count()): + if val == self.itemData(i): + self.setCurrentIndex(i) + break + + def populate(self): + for i, s in enumerate(SymbolStyle): + self.insertItem(i, re.sub(r'([A-Z])', r' \g<1>', s.name)) + self.setItemData(i, s) + self.setItemData(i, make_symbol_pixmap(s), QtCore.Qt.DecorationRole) + + +class HeaderDelegate(QtWidgets.QStyledItemDelegate): + def paint(self, painter: QtGui.QPainter, option: QtWidgets.QStyleOptionViewItem, index: QtCore.QModelIndex): + + header_option = QtWidgets.QStyleOptionHeader() + header_option.rect = option.rect + + style = QtWidgets.QApplication.style() + style.drawControl(QtWidgets.QStyle.CE_HeaderSection, header_option, painter) + if option.state & QtWidgets.QStyle.State_Selected: + painter.fillRect(option.rect, option.palette.highlight()) \ No newline at end of file diff --git a/nmreval/gui_qt/lib/expandablewidget.py b/nmreval/gui_qt/lib/expandablewidget.py new file mode 100644 index 0000000..29bfd82 --- /dev/null +++ b/nmreval/gui_qt/lib/expandablewidget.py @@ -0,0 +1,65 @@ +from ..Qt import QtWidgets, QtCore + + +class ExpandableWidget(QtWidgets.QWidget): + expansionChanged = QtCore.pyqtSignal() + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self._init_ui() + + self._widget = None + self._expanded = False + + self.toolButton.clicked.connect(self.changeVisibility) + + def _init_ui(self): + self.verticalLayout = QtWidgets.QVBoxLayout(self) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.verticalLayout.setSpacing(0) + + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setSpacing(0) + + self.toolButton = QtWidgets.QToolButton(self) + self.toolButton.setArrowType(QtCore.Qt.RightArrow) + self.toolButton.setStyleSheet('border: 0') + self.toolButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + self.horizontalLayout.addWidget(self.toolButton) + + self.line = QtWidgets.QFrame(self) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.horizontalLayout.addWidget(self.line) + + self.verticalLayout.addLayout(self.horizontalLayout) + + def addWidget(self, widget: QtWidgets.QWidget): + self._widget = widget + self._widget.setVisible(self._expanded) + self.layout().addWidget(widget) + + def setText(self, text: str): + self.toolButton.setText(text) + + def isExpanded(self): + return self._expanded + + def changeVisibility(self): + if not self._widget: + return + + self.setExpansion(not self._expanded) + + self.expansionChanged.emit() + + def setExpansion(self, state: bool): + self.blockSignals(True) + if state: + self.toolButton.setArrowType(QtCore.Qt.DownArrow) + else: + self.toolButton.setArrowType(QtCore.Qt.RightArrow) + + self._expanded = state + self._widget.setVisible(state) + self.blockSignals(False) diff --git a/nmreval/gui_qt/lib/forms.py b/nmreval/gui_qt/lib/forms.py new file mode 100644 index 0000000..fb3058d --- /dev/null +++ b/nmreval/gui_qt/lib/forms.py @@ -0,0 +1,402 @@ +from numpy import inf + +from ...utils.text import convert + +from ..Qt import QtGui, QtCore, QtWidgets +from .._py.mean_form import Ui_mean_form + + +class QDelayWidget(QtWidgets.QWidget): + get_data = QtCore.pyqtSignal(str) + newDelay = QtCore.pyqtSignal() + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.vals = '' + self.dim = 0 + self.plainTextEdit.setVisible(False) + + def __call__(self): + self.vals = '' + self.dim = 0 + self.comboBox.clear() + self.comboBox.blockSignals(True) + self.comboBox.addItem('New list...') + self.comboBox.blockSignals(True) + self.plainTextEdit.setVisible(False) + + def add_items(self, item): + self.comboBox.blockSignals(True) + if isinstance(item, list): + self.comboBox.insertItems(0, item) + else: + self.comboBox.insertItem(0, item) + self.comboBox.setCurrentIndex(0) + self.comboBox.blockSignals(False) + + @QtCore.pyqtSlot(name='on_toolButton_clicked') + def show_values(self): + if self.plainTextEdit.isVisible(): + self.plainTextEdit.clear() + self.plainTextEdit.setVisible(False) + elif self.comboBox.currentText() == 'New list...': + self.newDelay.emit() + else: + self.get_data.emit(self.comboBox.currentText()) + self.plainTextEdit.setVisible(True) + self.plainTextEdit.setPlainText(self.vals) + + +class LineEdit(QtWidgets.QLineEdit): + values_requested = QtCore.pyqtSignal() + + def __init__(self, parent=None): + super().__init__(parent=parent) + + def contextMenuEvent(self, evt): + menu = self.createStandardContextMenu() + request_action = menu.addAction('Use value of set(s)') + + action = menu.exec(evt.globalPos()) + + if action == request_action: + self.values_requested.emit() + + +class LineEditPost(QtWidgets.QLineEdit): + values_requested = QtCore.pyqtSignal() + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.suffix = '' + self.prefix = '' + + self.editingFinished.connect(self.add_fixes) + + def add_fixes(self): + self.setText(self.prefix+super().text()+self.suffix) + + def text(self): + text = super().text() + if text.startswith(self.prefix): + text = text[len(self.prefix):] + if text.endswith(self.suffix): + text = text[:-len(self.suffix)] + + return text + + +class FormWidget(QtWidgets.QWidget): + types = {'float': (float, QtGui.QDoubleValidator), + 'int': (int, QtGui.QIntValidator), + 'str': (str, lambda: 0)} + + valueChanged = QtCore.pyqtSignal(object) + stateChanged = QtCore.pyqtSignal(bool) + + def __init__(self, name: str, validator: str = 'float', fixable: bool = False, parent=None): + super().__init__(parent=parent) + + self._init_ui() + + self._name = name + + self._type = FormWidget.types[validator][0] + self.vals.setValidator(FormWidget.types[validator][1]()) + self.vals.textChanged.connect(lambda: self.valueChanged.emit(self.value) if self.value is not None else 0) + + self.label.setText(convert(name)) + + self._checkable = fixable + self.checkBox.setVisible(fixable) + self.checkBox.stateChanged.connect(lambda x: self.stateChanged.emit(True if x else False)) + + def _init_ui(self): + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(2, 2, 2, 2) + layout.setSpacing(2) + + self.label = QtWidgets.QLabel(self) + layout.addWidget(self.label) + + layout.addSpacerItem(QtWidgets.QSpacerItem(20, 20, + QtWidgets.QSizePolicy.Expanding, + QtWidgets.QSizePolicy.Minimum)) + + self.vals = QtWidgets.QLineEdit(self) + layout.addWidget(self.vals) + + self.checkBox = QtWidgets.QCheckBox('Fix?', self) + layout.addWidget(self.checkBox) + + @property + def value(self): + try: + return self._type(self.vals.text().replace(',', '.')) + except ValueError: + return {float: 0.0, int: 0, str: ''}[self._type] + + @value.setter + def value(self, val): + self.vals.setText(str(val)) + + def setChecked(self, enable): + if self._checkable: + self.checkBox.setCheckState(QtCore.Qt.Checked if enable else QtCore.Qt.Unchecked) + else: + print(f'Parameter {self._name} is not variable') + + def isChecked(self): + return self.checkBox.isChecked() + + +class SelectionWidget(QtWidgets.QWidget): + selectionChanged = QtCore.pyqtSignal(str, object) + + def __init__(self, label: str, argname: str, opts: dict, parent=None): + super().__init__(parent=parent) + + self._init_ui() + self.label.setText(convert(label)) + for k in opts.keys(): + self.comboBox.addItem(k) + + self.argname = argname + self.options = opts + + self.comboBox.currentIndexChanged.connect(lambda idx: self.selectionChanged.emit(self.argname, self.value)) + + def _init_ui(self): + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(1, 1, 1, 1) + layout.setSpacing(2) + + self.label = QtWidgets.QLabel(self) + layout.addWidget(self.label) + + layout.addSpacerItem(QtWidgets.QSpacerItem(65, 20, + QtWidgets.QSizePolicy.Expanding, + QtWidgets.QSizePolicy.Minimum)) + + self.comboBox = QtWidgets.QComboBox(self) + layout.addWidget(self.comboBox) + self.setLayout(layout) + + @property + def value(self): + try: + return float(self.options[str(self.comboBox.currentText())]) + except ValueError: + return str(self.options[str(self.comboBox.currentText())]) + + def get_parameter(self): + return str(self.comboBox.currentText()) + + @value.setter + def value(self, val): + key = [k for k, v in self.options.items() if v == val][0] + self.comboBox.setCurrentIndex(self.comboBox.findText(key)) + + +class Widget(QtWidgets.QWidget, Ui_mean_form): + valueChanged = QtCore.pyqtSignal() + + def __init__(self, name: str, tree: dict, collapsing: bool = False, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self._tree = {} + + self._collapse = collapsing + + self.label.setText(convert(name)) + self.lineEdit.setValidator(QtGui.QDoubleValidator()) + + self.set_graphs(tree) + self.change_graph(0) + + if self._collapse: + self.digit_checkbox.hide() + self.frame.hide() + self.data_checkbox.stateChanged.connect(self.collapse_widgets) + else: + self.data_checkbox.stateChanged.connect(self.change_mode) + self.digit_checkbox.stateChanged.connect(self.change_mode) + + def set_graphs(self, graph: dict): + self.graph_combobox.blockSignals(True) + self._tree.clear() + for key, (name, _) in graph.items(): + self.graph_combobox.addItem(name, userData=key) + self.graph_combobox.blockSignals(False) + self._tree.update(graph) + self.change_graph(0) + + @QtCore.pyqtSlot(int, name='on_graph_combobox_currentIndexChanged') + def change_graph(self, idx: int): + self.set_combobox.clear() + + key = self.graph_combobox.itemData(idx, QtCore.Qt.UserRole) + if key is not None: + for set_key, set_name in self._tree[key][1]: + self.set_combobox.addItem(set_name, userData=set_key) + + def on_lineEdit_textChanged(self, text=''): + if text: + self.valueChanged.emit() + + @property + def value(self): + if self.data_checkbox.isChecked(): + return self.set_combobox.currentData() + else: + try: + return float(self.lineEdit.text()) + except ValueError: + return + + @QtCore.pyqtSlot(int) + def change_mode(self, state: int): + box = self.sender() + other_box = self.data_checkbox if box == self.digit_checkbox else self.digit_checkbox + + if (state == QtCore.Qt.Unchecked) and (other_box.checkState() == QtCore.Qt.Unchecked): + box.blockSignals(True) + box.setCheckState(QtCore.Qt.Checked) + box.blockSignals(False) + return + + other_box.blockSignals(True) + other_box.setChecked(False) + other_box.blockSignals(False) + + self.valueChanged.emit() + + @QtCore.pyqtSlot(int) + def collapse_widgets(self, state: int): + data_is_checked = state == QtCore.Qt.Checked + self.frame.setVisible(data_is_checked) + self.lineEdit.setVisible(not data_is_checked) + + +class CheckBoxHeader(QtWidgets.QHeaderView): + clicked = QtCore.pyqtSignal(int, bool) + + _x_offset = 3 + _y_offset = 0 # This value is calculated later, based on the height of the paint rect + _width = 20 + _height = 20 + + def __init__(self, column_indices, orientation=QtCore.Qt.Horizontal, parent=None): + super().__init__(orientation, parent) + self.setSectionResizeMode(QtWidgets.QHeaderView.Stretch) + # self.setClickable(True) + + if isinstance(column_indices, list) or isinstance(column_indices, tuple): + self.column_indices = column_indices + elif isinstance(column_indices, int): + self.column_indices = [column_indices] + else: + raise RuntimeError('column_indices must be a list, tuple or integer') + + self.isChecked = {} + for column in self.column_indices: + self.isChecked[column] = 0 + + def paintSection(self, painter, rect, logicalIndex): + painter.save() + super().paintSection(painter, rect, logicalIndex) + painter.restore() + + self._y_offset = int((rect.height()-self._width)/2.) + + if logicalIndex in self.column_indices: + option = QtWidgets.QStyleOptionButton() + option.rect = QtCore.QRect(rect.x() + self._x_offset, rect.y() + self._y_offset, self._width, self._height) + option.state = QtWidgets.QStyle.State_Enabled | QtWidgets.QStyle.State_Active + if self.isChecked[logicalIndex] == 2: + option.state |= QtWidgets.QStyle.State_NoChange + elif self.isChecked[logicalIndex]: + option.state |= QtWidgets.QStyle.State_On + else: + option.state |= QtWidgets.QStyle.State_Off + + self.style().drawControl(QtWidgets.QStyle.CE_CheckBox,option,painter) + + def updateCheckState(self, index, state): + self.isChecked[index] = state + self.viewport().update() + + def mousePressEvent(self, event): + index = self.logicalIndexAt(event.pos()) + if 0 <= index < self.count(): + x = self.sectionPosition(index) + if x + self._x_offset < event.pos().x() < x + self._x_offset + self._width and self._y_offset < event.pos().y() < self._y_offset + self._height: + if self.isChecked[index] == 1: + self.isChecked[index] = 0 + else: + self.isChecked[index] = 1 + + self.clicked.emit(index, self.isChecked[index]) + self.viewport().update() + else: + super().mousePressEvent(event) + else: + super().mousePressEvent(event) + + +class CustomRangeDialog(QtWidgets.QDialog): + """ Simple dialog to enter x and y limits to fit regions""" + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.gl = QtWidgets.QGridLayout() + self.gl.addWidget(QtWidgets.QLabel('Leave empty for complete range'), 0, 0, 1, 4) + + self._limits = [[], []] + for i, orient in enumerate(['x', 'y'], start=1): + self.gl.addWidget(QtWidgets.QLabel(orient + ' from'), i, 0) + self.gl.addWidget(QtWidgets.QLabel('to'), i, 2) + for j in [0, 1]: + lim = QtWidgets.QLineEdit() + lim.setValidator(QtGui.QDoubleValidator()) + self._limits[i-1].append(lim) + self.gl.addWidget(lim, i, 2*j+1) + + self.buttonbox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok) + self.buttonbox.accepted.connect(self.accept) + + self.gl.addWidget(self.buttonbox, 3, 0, 1, 4) + self.setLayout(self.gl) + + @property + def limits(self): + ret_val = [] + for orient in self._limits: + for i, w in enumerate(orient): + val = w.text() + if val == '': + ret_val.append(-inf if i == 0 else inf) + else: + ret_val.append(float(val)) + return ret_val + + +class ElideComboBox(QtWidgets.QComboBox): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.view().setTextElideMode(QtCore.Qt.ElideRight) + + def paintEvent(self, evt: QtGui.QPaintEvent): + opt = QtWidgets.QStyleOptionComboBox() + self.initStyleOption(opt) + + painter = QtWidgets.QStylePainter(self) + painter.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, opt) + + rect = self.style().subControlRect(QtWidgets.QStyle.CC_ComboBox, opt, QtWidgets.QStyle.SC_ComboBoxEditField, self) + + opt.currentText = painter.fontMetrics().elidedText(opt.currentText, QtCore.Qt.ElideRight, rect.width()) + painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, opt) diff --git a/nmreval/gui_qt/lib/gol.py b/nmreval/gui_qt/lib/gol.py new file mode 100644 index 0000000..4212e71 --- /dev/null +++ b/nmreval/gui_qt/lib/gol.py @@ -0,0 +1,390 @@ +from __future__ import annotations + +import numbers +import numpy as np +import sys +from itertools import accumulate + +from ..Qt import QtWidgets, QtGui, QtCore +from .._py.gol import Ui_Form + + +def circle(radius): + pxl = [] + for x in range(int(np.ceil(radius/np.sqrt(2)))): + y = round(np.sqrt(radius**2-x**2)) + pxl.extend([[x, y], [y, x], [x, -y], [y, -x], + [-x, -y], [-y, -x], [-x, y], [-y, x]]) + + return np.array(pxl) + + +def square(a): + pxl = [] + pxl.extend(list(zip(range(-a, a+1), [a]*(2*a+1)))) + pxl.extend(list(zip(range(-a, a+1), [-a]*(2*a+1)))) + pxl.extend(list(zip([a]*(2*a+1), range(-a, a+1)))) + pxl.extend(list(zip([-a]*(2*a+1), range(-a, a+1)))) + + return np.array(pxl) + + +def diamond(a): + pxl = [] + for x in range(int(a+1)): + y = a-x + pxl.extend([[x, y], [-x, y], [x, -y], [-x, -y]]) + + print(np.array(pxl).shape) + + return np.array(pxl) + + +def plus(a): + pxl = np.zeros((4*int(a)+2, 2), dtype=int) + pxl[:2*int(a)+1, 0] = np.arange(-a, a+1) + pxl[2*int(a)+1:, 1] = np.arange(-a, a+1) + + return pxl + +# birth, survival +predefined_rules = { + 'Conway': ('23', '3'), + 'Life34': ('34', '34'), + 'Coagulation': ('235678', '378'), + 'Corrosion': ('12345', '45'), + 'Long life': ('5', '345'), + 'Maze': ('12345', '3'), + 'Coral': ('45678', '3'), + 'Pseudo life': ('238', '357'), + 'Flakes': ('012345678', '3'), + 'Gnarl': ('1', '1'), + 'Fabric': ('12', '1'), + 'Assimilation': ('4567', '345'), + 'Diamoeba': ('5678', '35678'), + 'High life': ('23', '36'), + 'More Maze': ('1235', '3'), + 'Replicator': ('1357', '1357'), + 'Seed': ('', '2'), + 'Serviette': ('', '234'), + 'More coagulation': ('235678', '3678'), + 'Domino': ('125', '36'), + 'Anneal': ('35678', '4678'), +} + + +class GameOfLife: + colors = [ + [31, 119, 180], + [255, 127, 14], + [44, 160, 44], + [214, 39, 40], + [148, 103, 189], + [140, 86, 75] + ] + + def __init__(self, + size: tuple = (400, 400), + pattern: np.ndarray = None, + fill: float | list[float] = 0.05, + num_pop: int = 1, + rules: str | tuple = ('23', '3') + ): + self.populations = num_pop if pattern is None else 1 + self._size = size + + self._world = np.zeros(shape=(*self._size, self.populations), dtype=np.uint8) + self._neighbors = np.zeros(shape=self._world.shape, dtype=np.uint8) + self._drawing = 255 * np.zeros(shape=(*self._size, 3), dtype=np.uint8) + + self.fill = np.zeros(self.populations) + self._populate(fill, pattern) + + print(rules) + if isinstance(rules, str): + try: + b_rule, s_rule = predefined_rules[rules] + except KeyError: + raise ValueError('Rule is not predefined') + else: + b_rule, s_rule = rules + + self.survival_condition = np.array([int(c) for c in s_rule]) + self.birth_condition = np.array([int(c) for c in b_rule]) + + # indexes for neighbors + self._neighbor_idx = [ + [[slice(None), slice(1, None)], [slice(None), slice(0, -1)]], # N (:, 1:), S (:, _-1) + [[slice(1, None), slice(1, None)], [slice(0, -1), slice(0, -1)]], # NE (1:, 1:), SW (:-1, :-1) + [[slice(1, None), slice(None)], [slice(0, -1), slice(None)]], # E (1:, :), W (:-1, :) + [[slice(1, None), slice(0, -1)], [slice(0, -1), slice(1, None)]] # SE (1:, :-1), NW (:-1:, 1:) + ] + + def _populate(self, fill, pattern): + if pattern is None: + if isinstance(fill, numbers.Number): + fill = [fill]*self.populations + + prob = (np.random.default_rng().random(size=self._size)) + lower_lim = 0 + for i, upper_lim in enumerate(accumulate(fill)): + self._world[:, :, i] = (lower_lim <= prob) & (prob < upper_lim) + lower_lim = upper_lim + + else: + pattern = np.asarray(pattern) + + x_step = self._size[0]//(self.populations+1) + y_step = self._size[1]//(self.populations+1) + + for i in range(self.populations): + self._world[-pattern[:, 0]+(i+1)*x_step, pattern[:, 1]+(i+1)*y_step, i] = 1 + + for i in range(self.populations): + self.fill[i] = self._world[:, :, i].sum() / (self._size[0]*self._size[1]) + + def tick(self): + n = self._neighbors + w = self._world + + n[...] = 0 + for idx_1, idx_2 in self._neighbor_idx: + n[tuple(idx_1)] += w[tuple(idx_2)] + n[tuple(idx_2)] += w[tuple(idx_1)] + + birth = ((np.in1d(n, self.birth_condition).reshape(n.shape)) & (w.sum(axis=-1) == 0)[:, :, None]) + survive = ((np.in1d(n, self.survival_condition).reshape(n.shape)) & (w == 1)) + + w[...] = 0 + w[birth | survive] = 1 + + def draw(self, shade: int): + if shade == 0: + self._drawing[...] = 0 + elif shade == 1: + self._drawing -= (self._drawing/4).astype(np.uint8) + self._drawing = self._drawing.clip(0, 127) + + for i in range(self.populations): + self._drawing[(self._world[:, :, i] == 1)] = self.colors[i] + self.fill[i] = self._world[:, :, i].sum() / (self._size[0]*self._size[1]) + + return self._drawing + + +class QGameOfLife(QtWidgets.QDialog, Ui_Form): + SPEEDS = [0.5, 1, 2, 5, 7.5, 10, 12.5, 15, 20, 25, 30, 40, 50] + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self._size = (100, 100) + self.game = None + self._step = 0 + self._shading = 1 + self._speed = 5 + + self.timer = QtCore.QTimer() + self.timer.setInterval(100) + self.timer.timeout.connect(self.tick) + + self._init_ui() + + def _init_ui(self): + self.item = None + self.scene = QtWidgets.QGraphicsScene() + self.item = self.scene.addPixmap(QtGui.QPixmap()) + self.view.setScene(self.scene) + + self.rule_cb.addItems(list(predefined_rules.keys())) + + self.random_widgets = [] + for _ in range(6): + w = QSliderText(15, parent=self) + w.slider.valueChanged.connect(self.set_max_population) + self.verticalLayout.addWidget(w) + self.random_widgets.append(w) + + self.birth_line.setValidator(QtGui.QIntValidator()) + self.survival_line.setValidator(QtGui.QIntValidator()) + + for w in self.random_widgets[1:] + [self.object_widget]: + w.hide() + + self.setGeometry(QtWidgets.QStyle.alignedRect(QtCore.Qt.LeftToRight, QtCore.Qt.AlignCenter, + self.size(), QtWidgets.qApp.desktop().availableGeometry())) + + self.view.resizeEvent = self.resizeEvent + + @QtCore.pyqtSlot(int) + def on_object_combobox_currentIndexChanged(self, idx: int): + for w in self.random_widgets + [self.object_widget, self.rand_button_wdgt]: + w.hide() + + if idx == 0: + self.random_widgets[0].show() + self.rand_button_wdgt.show() + else: + self.object_widget.show() + + @QtCore.pyqtSlot() + def on_add_random_button_clicked(self): + if self.object_combobox.currentIndex() != 0: + return + + for w in self.random_widgets[1:]: + if not w.isVisible(): + w.show() + break + + @QtCore.pyqtSlot() + def on_remove_random_button_clicked(self): + if self.object_combobox.currentIndex() != 0: + return + + for w in reversed(self.random_widgets[1:]): + if w.isVisible(): + w.hide() + break + + @QtCore.pyqtSlot(str) + def on_rule_cb_currentIndexChanged(self, entry: str): + rule = predefined_rules[entry] + self.birth_line.setText(rule[1]) + self.survival_line.setText(rule[0]) + + @QtCore.pyqtSlot(int) + def set_max_population(self, _: int): + over_population = -100 + num_tribes = -1 + for w in self.random_widgets: + if w.isVisible(): + over_population += w.slider.value() + num_tribes += 1 + + if over_population > 0: + for w in self.random_widgets: + if w == self.sender() or w.isHidden(): + continue + w.setValue(max(0, int(w.slider.value()-over_population/num_tribes))) + + @QtCore.pyqtSlot() + def on_start_button_clicked(self): + self.pause_button.setChecked(False) + self._step = 0 + self.current_step.setText(f'{self._step} steps') + self._size = (int(self.height_box.value()), int(self.width_box.value())) + + pattern = None + num_pop = 0 + fill = [] + pattern_size = self.object_size.value() + if 2*pattern_size >= max(self._size): + pattern_size = int(np.floor(max(self._size[0]-1, self._size[1]-1) / 2)) + + idx = self.object_combobox.currentIndex() + if idx == 0: + for w in self.random_widgets: + if w.isVisible(): + num_pop += 1 + fill.append(w.slider.value()/100) + else: + pattern = [None, circle, square, diamond, plus][idx](pattern_size) + + self.game = GameOfLife(self._size, pattern=pattern, fill=fill, num_pop=num_pop, + rules=(self.birth_line.text(), self.survival_line.text())) + self.draw() + self.view.fitInView(self.item, QtCore.Qt.KeepAspectRatio) + + self.timer.start() + + def tick(self): + self.game.tick() + self.draw() + + self._step += 1 + self.current_step.setText(f'{self._step} steps') + self.cover_label.setText('\n'.join([f'Color {i+1}: {f*100:.2f} %' for i, f in enumerate(self.game.fill)])) + + @QtCore.pyqtSlot() + def on_faster_button_clicked(self): + self._speed = min(self._speed+1, len(QGameOfLife.SPEEDS)-1) + new_speed = QGameOfLife.SPEEDS[self._speed] + self.timer.setInterval(int(1000/new_speed)) + self.velocity_label.setText(f'{new_speed:.1f} steps/s') + + @QtCore.pyqtSlot() + def on_slower_button_clicked(self): + self._speed = max(self._speed-1, 0) + new_speed = QGameOfLife.SPEEDS[self._speed] + self.timer.setInterval(int(1000/new_speed)) + self.velocity_label.setText(f'{new_speed:.1f} steps/s') + + @QtCore.pyqtSlot() + def on_pause_button_clicked(self): + if self.pause_button.isChecked(): + self.timer.stop() + else: + self.timer.start() + + @QtCore.pyqtSlot(QtWidgets.QAbstractButton) + def on_buttonGroup_buttonClicked(self, button): + self._shading = [self.radioButton, self.vanish_shadow, self.full_shadow].index(button) + + def draw(self): + bitmap = self.game.draw(shade=self._shading) + h, w, c = bitmap.shape + image = QtGui.QImage(bitmap.tobytes(), w, h, w*c, QtGui.QImage.Format_RGB888) + self.scene.removeItem(self.item) + pixmap = QtGui.QPixmap.fromImage(image) + self.item = self.scene.addPixmap(pixmap) + + @QtCore.pyqtSlot(int) + def on_hide_button_stateChanged(self, state: int): + self.option_frame.setVisible(not state) + self.view.fitInView(self.scene.sceneRect(), QtCore.Qt.KeepAspectRatio) + + def resizeEvent(self, evt): + super().resizeEvent(evt) + self.view.fitInView(self.item, QtCore.Qt.KeepAspectRatio) + + def showEvent(self, evt): + super().showEvent(evt) + self.view.fitInView(self.scene.sceneRect(), QtCore.Qt.KeepAspectRatio) + + +class QSliderText(QtWidgets.QWidget): + def __init__(self, value: int, parent=None): + super().__init__(parent=parent) + layout = QtWidgets.QHBoxLayout() + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(3) + + self.slider = QtWidgets.QSlider(self) + self.slider.setOrientation(QtCore.Qt.Horizontal) + self.slider.setMaximum(100) + self.slider.setTickPosition(self.slider.TicksBothSides) + self.slider.setTickInterval(5) + + self.value = QtWidgets.QLabel(self) + + self.slider.valueChanged.connect(lambda x: self.value.setText(f'{x} %')) + + layout.addWidget(self.slider) + layout.addWidget(self.value) + + self.setLayout(layout) + + self.setValue(value) + + def setValue(self, value: int): + self.slider.setValue(value) + self.value.setText(f'{value} %') + + +if __name__ == "__main__": + application = QtWidgets.QApplication(sys.argv) + qGameOfLife = QGameOfLife() + qGameOfLife.show() + sys.exit(application.exec()) diff --git a/nmreval/gui_qt/lib/namespace.py b/nmreval/gui_qt/lib/namespace.py new file mode 100644 index 0000000..9229176 --- /dev/null +++ b/nmreval/gui_qt/lib/namespace.py @@ -0,0 +1,211 @@ +import inspect +import re +from collections import namedtuple + +import numpy as np + +from ... import models +from ...configs import config_paths +from ...lib.importer import find_models, import_ +from ...utils import constants as constants +from ...utils.text import convert +from ..Qt import QtWidgets, QtCore +from .._py.namespace_widget import Ui_Form + + +class Namespace: + def __init__(self, fitfuncs=False, const=False, basic=False): + self.namespace = {} + self.groupings = {} + self.top_levels = {} + + if basic: + self.add_namespace({'x': (None, 'x values'), 'y': (None, 'x values'), 'y_err': (None, 'y error values'), + 'fit': (None, 'dictionary of fit parameter', 'fit["PIKA"]'), 'np': (np, 'numpy module')}, + parents=('Basic', 'General')) + + self.add_namespace({'sin': (np.sin, 'Sine', 'sin(PIKA)'), 'cos': (np.cos, 'Cosine', 'cos(PIKA)'), + 'tan': (np.tan, 'Tangens', 'tan(PIKA)'), 'ln': (np.log, 'Natural Logarithm', 'ln(PIKA)'), + 'log': (np.log10, 'Logarithm (base 10)', 'log(PIKA)'), + 'exp': (np.exp, 'Exponential', 'exp(PIKA)'), 'sqrt': (np.sqrt, 'Root', 'sqrt(PIKA)'), + 'lin_range': (np.linspace, 'N evenly spaced over interval [start, stop]', + 'lin_range(start, stop, N)'), + 'log_range': (np.geomspace, 'N evenly spaced (log-scale) over interval [start, stop]', + 'lin_range(start, stop, N)')}, + parents=('Basic', 'Functions')) + + self.add_namespace({'max': (np.max, 'Maximum value', 'max(PIKA)'), + 'min': (np.min, 'Minimum value', 'min(PIKA)'), + 'argmax': (np.argmax, 'Index of maximum value', 'argmax(PIKA)'), + 'argmin': (np.argmax, 'Index of minimum value', 'argmin(PIKA)')}, + parents=('Basic', 'Values')) + + if const: + self.add_namespace({'e': (constants.e, 'e / As'), 'eps0': (constants.epsilon0, 'epsilon0 / As/Vm'), + 'Eu': (constants.Eu,), 'h': (constants.h, 'h / eVs'), + 'hbar': (constants.hbar, 'hbar / eVs'), 'kB': (constants.kB, 'kB / eV/K'), + 'mu0': (constants.mu0, 'mu0 / Vs/Am'), 'NA': (constants.NA, 'NA / 1/mol'), + 'pi': (constants.pi,), 'R': (constants.R, 'R / eV')}, + parents=('Constants', 'Maybe useful')) + + self.add_namespace({f'gamma["{k}"]': (v, k, f'gamma["{k}"]') for k, v in constants.gamma.items()}, + parents=('Constants', 'Magnetogyric ratios (in 1/(sT))')) + + if fitfuncs: + self.make_dict_from_fitmodule(models) + try: + usermodels = import_(config_paths() / 'usermodels.py') + self.make_dict_from_fitmodule(usermodels, parent='User-defined') + except FileNotFoundError: + pass + + def __str__(self): + ret = '\n'.join([f'{k}: {v}' for k, v in self.groupings.items()]) + return ret + + def make_dict_from_fitmodule(self, module, parent='Fit function'): + fitfunc_dict = {} + for funcs in find_models(module): + name = funcs.name + if funcs.type not in fitfunc_dict: + fitfunc_dict[funcs.type] = {} + + func_list = fitfunc_dict[funcs.type] + + func_args = 'x, ' + ', '.join(convert(p, old='latex', new='str', brackets=False) for p in funcs.params) + + # keywords arguments need names in function + sig = inspect.signature(funcs.func) + for p in sig.parameters.values(): + if p.default != p.empty: + func_args += ', ' + str(p) + + func_list[f"{funcs.__name__}"] = (funcs.func, name, f"{funcs.__name__}({func_args})") + + for k, v in fitfunc_dict.items(): + self.add_namespace(v, parents=(parent, k)) + + def add_namespace(self, namespace, parents): + if parents[0] in self.top_levels: + if parents[1] not in self.top_levels[parents[0]]: + self.top_levels[parents[0]].append(parents[1]) + else: + self.top_levels[parents[0]] = [parents[1]] + if (parents[0], parents[1]) not in self.groupings: + self.groupings[(parents[0], parents[1])] = list(namespace.keys()) + else: + self.groupings[(parents[0], parents[1])].extend(list(namespace.keys())) + + self.namespace.update(namespace) + + def flatten(self): + ret_dic = {} + graph = namedtuple('graphs', ['s']) + sets = namedtuple('sets', ['x', 'y', 'y_err', 'value', 'fit'], defaults=(None,)) + + gs = re.compile(r'g\[(\d+)].s\[(\d+)].(x|y(?:_err)*|value|fit)') + + for k, v in self.namespace.items(): + m = gs.match(k) + if m: + if 'g' not in ret_dic: + ret_dic['g'] = {} + + g_num, s_num, pos = m.groups() + if int(g_num) not in ret_dic['g']: + ret_dic['g'][int(g_num)] = graph({}) + + gg = ret_dic['g'][int(g_num)] + if int(s_num) not in gg.s: + gg.s[int(s_num)] = sets('', '', '', '') + + ss = gg.s[int(s_num)] + if pos == 'fit': + if ss.fit is None: + gg.s[int(s_num)] = ss._replace(**{pos: {}}) + ss = gg.s[int(s_num)] + ss.fit[k[m.end()+2:-2]] = v[0] + + else: + ret_dic['g'][int(g_num)].s[int(s_num)] = ss._replace(**{pos: v[0]}) + + else: + ret_dic[k] = v[0] + + return ret_dic + + +class QNamespaceWidget(QtWidgets.QWidget, Ui_Form): + selected = QtCore.pyqtSignal(str) + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.setupUi(self) + self.namespace = None + + def make_namespace(self): + self.set_namespace(Namespace(fitfuncs=True, const=True, basic=True)) + + @QtCore.pyqtSlot(int, name='on_groups_comboBox_currentIndexChanged') + def show_subgroup(self, idx: int): + name = self.groups_comboBox.itemText(idx) + + self.subgroups_comboBox.blockSignals(True) + self.subgroups_comboBox.clear() + for item in self.namespace.top_levels[name]: + self.subgroups_comboBox.addItem(item) + self.subgroups_comboBox.blockSignals(False) + + self.show_namespace(0) + + @QtCore.pyqtSlot(int, name='on_subgroups_comboBox_currentIndexChanged') + def show_namespace(self, idx: int): + subspace = self.namespace.groupings[(self.groups_comboBox.currentText(), self.subgroups_comboBox.itemText(idx))] + + self.namespace_table.clear() + self.namespace_table.setRowCount(0) + + for entry in subspace: + key_item = QtWidgets.QTableWidgetItem(entry) + key_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + + vals = self.namespace.namespace[entry] + + if len(vals) < 3: + alias = entry + else: + alias = vals[2] + + if len(vals) < 2: + display = entry + else: + display = vals[1] + + value_item = QtWidgets.QTableWidgetItem(display) + value_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + + key_item.setData(QtCore.Qt.UserRole, alias) + value_item.setData(QtCore.Qt.UserRole, alias) + + row = self.namespace_table.rowCount() + self.namespace_table.setRowCount(row+1) + self.namespace_table.setItem(row, 0, key_item) + self.namespace_table.setItem(row, 1, value_item) + + self.namespace_table.resizeColumnsToContents() + + def set_namespace(self, namespace): + self.namespace = namespace + + self.groups_comboBox.blockSignals(True) + self.groups_comboBox.clear() + for k in self.namespace.top_levels.keys(): + self.groups_comboBox.addItem(k) + self.groups_comboBox.blockSignals(False) + + self.show_subgroup(0) + + @QtCore.pyqtSlot(QtWidgets.QTableWidgetItem, name='on_namespace_table_itemDoubleClicked') + def item_selected(self, item: QtWidgets.QTableWidgetItem): + self.selected.emit(item.data(QtCore.Qt.UserRole)) diff --git a/nmreval/gui_qt/lib/pg_objects.py b/nmreval/gui_qt/lib/pg_objects.py new file mode 100644 index 0000000..7fa9851 --- /dev/null +++ b/nmreval/gui_qt/lib/pg_objects.py @@ -0,0 +1,435 @@ +import numpy as np +from pyqtgraph import ( + InfiniteLine, + ErrorBarItem, + LinearRegionItem, mkBrush, + mkColor, mkPen, + PlotDataItem +) + +from ...lib.colors import BaseColor, Colors +from ...lib.lines import LineStyle +from ...lib.symbols import SymbolStyle + +from ..Qt import QtCore, QtGui + +""" +Subclasses of pyqtgraph items, mostly to take care of log-scaling. +pyqtgraph looks for function "setLogMode" for logarithmic axes, so needs to be implemented. +""" + + +class LogInfiniteLine(InfiniteLine): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.logmode = [False, False] + + def setLogMode(self, xmode, ymode): + """ + Does only work for vertical and horizontal lines + """ + if self.logmode == [xmode, ymode]: + return + + new_p = list(self.p[:]) + if (self.angle == 90) and (self.logmode[0] != xmode): + if xmode: + new_p[0] = np.log10(new_p[0]+np.finfo(float).eps) + else: + new_p[0] = 10**new_p[0] + + if (self.angle == 0) and (self.logmode[1] != ymode): + if ymode: + new_p[1] = np.log10(new_p[1]+np.finfo(float).eps) + else: + new_p[1] = 10**new_p[1] + + self.logmode = [xmode, ymode] + + if np.all(np.isfinite(new_p)): + self.setPos(new_p) + else: + self.setPos(self.p) + self.sigPositionChanged.emit(self) + + def setValue(self, v): + if isinstance(v, QtCore.QPointF): + v = [v.x(), v.y()] + + with np.errstate(divide='ignore'): + if isinstance(v, (list, tuple)): + for i in [0, 1]: + if self.logmode[i]: + v[i] = np.log10(v[i]+np.finfo(float).eps) + else: + if self.angle == 90: + if self.logmode[0]: + v = [np.log10(v+np.finfo(float).eps), 0] + else: + v = [v, 0] + elif self.angle == 0: + if self.logmode[1]: + v = [0, np.log10(v+np.finfo(float).eps)] + else: + v = [0, v] + else: + raise ValueError('LogInfiniteLine: Diagonal lines need two values') + + self.setPos(v) + + def value(self): + p = self.getPos() + if self.angle == 0: + return 10**p[1] if self.logmode[1] else p[1] + elif self.angle == 90: + return 10**p[0] if self.logmode[0] else p[0] + else: + if self.logmode[0]: + p[0] = 10**p[0] + if self.logmode[1]: + p[1] = 10**p[1] + return p + + +class ErrorBars(ErrorBarItem): + def __init__(self, **opts): + self.log = [False, False] + + opts['xData'] = opts.get('x', None) + opts['yData'] = opts.get('y', None) + opts['topData'] = opts.get('top', None) + opts['bottomData'] = opts.get('bottom', None) + + super().__init__(**opts) + + def setLogMode(self, x_mode, y_mode): + if self.log == [x_mode, y_mode]: + return + + self._make_log_scale(x_mode, y_mode) + + self.log[0] = x_mode + self.log[1] = y_mode + + super().setData() + + def setData(self, **opts): + self.opts.update(opts) + + self.opts['xData'] = opts.get('x', self.opts['xData']) + self.opts['yData'] = opts.get('y', self.opts['yData']) + self.opts['topData'] = opts.get('top', self.opts['topData']) + self.opts['bottomData'] = opts.get('bottom', self.opts['bottomData']) + + if any(self.log): + self._make_log_scale(*self.log) + + super().setData() + + def _make_log_scale(self, x_mode, y_mode): + _x = self.opts['xData'] + _xmask = np.logical_not(np.isnan(_x)) + + if x_mode: + with np.errstate(all='ignore'): + _x = np.log10(_x) + _xmask = np.logical_not(np.isnan(_x)) + + _y = self.opts['yData'] + _ymask = np.ones(_y.size, dtype=bool) + _top = self.opts['topData'] + _bottom = self.opts['bottomData'] + + if y_mode: + with np.errstate(all='ignore'): + logtop = np.log10(self.opts['topData']+_y) + logbottom = np.log10(_y-self.opts['bottomData']) + + _y = np.log10(_y) + _ymask = np.logical_not(np.isnan(_y)) + + logbottom[logbottom == -np.inf] = _y[logbottom == -np.inf] + _bottom = np.nan_to_num(np.maximum(_y-logbottom, 0)) + logtop[logtop == -np.inf] = _y[logtop == -np.inf] + _top = np.nan_to_num(np.maximum(logtop-_y, 0)) + + _mask = np.logical_and(_xmask, _ymask) + + self.opts['x'] = _x[_mask] + self.opts['y'] = _y[_mask] + self.opts['top'] = _top[_mask] + self.opts['bottom'] = _bottom[_mask] + + +class PlotItem(PlotDataItem): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.opts['linecolor'] = Colors.Black + self.opts['symbolcolor'] = Colors.Black + + if self.opts['pen'] is not None: + pen = self.opts['pen'] + if isinstance(pen, tuple): + self.opts['linecolor'] = pen + else: + c = pen.color() + self.opts['linecolor'] = c.red(), c.green(), c.blue() + + if self.symbol != SymbolStyle.No: + c = self.opts['symbolBrush'].color() + self.opts['symbolcolor'] = c.red(), c.green(), c.blue() + + def __getitem__(self, item): + return self.opts.get(item, None) + + @property + def symbol(self): + return SymbolStyle.from_str(self.opts['symbol']) + + @property + def symbolcolor(self): + sc = self.opts['symbolcolor'] + if isinstance(sc, tuple): + return Colors(sc) + elif isinstance(sc, str): + return Colors.from_str(sc) + else: + return sc + + @property + def symbolsize(self): + return self.opts['symbolSize'] + + @property + def linestyle(self) -> LineStyle: + pen = self.opts['pen'] + if pen is None: + return LineStyle.No + else: + return LineStyle(pen.style()) + + @property + def linewidth(self) -> float: + pen = self.opts['pen'] + if pen is None: + return 1. + else: + return pen.widthF() + + @property + def linecolor(self) -> Colors: + lc = self.opts['linecolor'] + if isinstance(lc, tuple): + return Colors(lc) + elif isinstance(lc, str): + return Colors.from_str(lc) + else: + return lc + + def updateItems(self): + """ + We override this function so that curves with nan/inf values can be displayed. + Newer versions close this bug differently (https://github.com/pyqtgraph/pyqtgraph/pull/1058) + but this works somewhat. + """ + + curveArgs = {} + for k, v in [('pen', 'pen'), ('shadowPen', 'shadowPen'), ('fillLevel', 'fillLevel'), + ('fillOutline', 'fillOutline'), ('fillBrush', 'brush'), ('antialias', 'antialias'), + ('connect', 'connect'), ('stepMode', 'stepMode')]: + curveArgs[v] = self.opts[k] + + scatterArgs = {} + for k, v in [('symbolPen', 'pen'), ('symbolBrush', 'brush'), ('symbol', 'symbol'), ('symbolSize', 'size'), + ('data', 'data'), ('pxMode', 'pxMode'), ('antialias', 'antialias')]: + if k in self.opts: + scatterArgs[v] = self.opts[k] + + x, y = self.getData() + if x is None: + x = [] + if y is None: + y = [] + # scatterArgs['mask'] = self.dataMask + + if curveArgs['pen'] is not None or (curveArgs['brush'] is not None and curveArgs['fillLevel'] is not None): + is_finite = np.isfinite(x) & np.isfinite(y) + all_finite = np.all(is_finite) + if not all_finite: + # remove all bad values + x = x[is_finite] + y = y[is_finite] + self.curve.setData(x=x, y=y, **curveArgs) + self.curve.show() + else: + self.curve.hide() + + if scatterArgs['symbol'] is not None: + if self.opts.get('stepMode', False) is True: + x = 0.5 * (x[:-1] + x[1:]) + self.scatter.setData(x=x, y=y, **scatterArgs) + self.scatter.show() + else: + self.scatter.hide() + + def set_symbol(self, symbol=None, size=None, color=None): + if symbol is not None: + if isinstance(symbol, int): + self.setSymbol(SymbolStyle(symbol).to_str()) + elif isinstance(symbol, SymbolStyle): + self.setSymbol(symbol.to_str()) + else: + self.setSymbol(symbol) + + if color is not None: + self.set_color(color, symbol=True) + + if size is not None: + self.setSymbolSize(size) + + def set_color(self, color, symbol=False, line=False): + if isinstance(color, BaseColor): + color = color.rgb() + elif isinstance(color, QtGui.QColor): + color = color.getRgb()[:3] + + if symbol: + self.setSymbolBrush(mkBrush(color)) + self.setSymbolPen(mkPen(color=color)) + self.opts['symbolcolor'] = color + + if line: + pen = self.opts['pen'] + self.opts['linecolor'] = color + if pen is not None: + pen.setColor(mkColor(color)) + self.opts['pen'] = pen + self.updateItems() + + def set_line(self, style=None, width=None, color=None): + pen = self.opts['pen'] + if pen is None: + pen = mkPen(style=QtCore.Qt.NoPen) + + if width is not None: + pen.setWidthF(width) + + if style is not None: + if isinstance(style, LineStyle): + style = style.value + + pen.setStyle(style) + + self.opts['pen'] = pen + self.updateItems() + + if color is not None: + self.set_color(color, symbol=False, line=True) + + def get_data_opts(self) -> dict: + x, y = self.xData, self.yData + if (x is None) or (len(x) == 0): + return {} + + opts = self.opts + item_dic = { + 'x': x, 'y': y, + 'name': opts['name'], + 'symbolsize': opts['symbolSize'] + } + + if opts['symbol'] is None: + item_dic['symbol'] = SymbolStyle.No + item_dic['symbolcolor'] = Colors.Black + else: + item_dic['symbol'] = SymbolStyle.from_str(opts['symbol']) + item_dic['symbolcolor'] = opts['symbolcolor'] + + pen = opts['pen'] + + if pen is not None: + item_dic['linestyle'] = LineStyle(pen.style()) + item_dic['linecolor'] = opts['linecolor'] + item_dic['linewidth'] = pen.widthF() + else: + item_dic['linestyle'] = LineStyle.No + item_dic['linecolor'] = item_dic['symbolcolor'] + item_dic['linewidth'] = 0.0 + + return item_dic + + +class RegionItem(LinearRegionItem): + def __init__(self, *args, **kwargs): + self.mode = kwargs.pop('mode', 'half') + + super().__init__(*args, **kwargs) + + self.logmode = False + self.first = True + + def setLogMode(self, xmode, _): + if self.logmode == xmode: + return + + if xmode: + new_region = [np.log10(self.lines[0].value()), np.log10(self.lines[1].value())] + + if np.isnan(new_region[1]): + new_region[1] = self.lines[1].value() + + if np.isnan(new_region[0]): + new_region[0] = new_region[1]/10. + + else: + new_region = [10**self.lines[0].value(), 10**self.lines[1].value()] + + self.logmode = xmode + self.setRegion(new_region) + + def dataBounds(self, axis, frac=1.0, orthoRange=None): + if axis == self._orientation_axis[self.orientation]: + r = self.getRegion() + if self.logmode: + r = np.log10(r[0]), np.log10(r[1]) + return r + else: + return None + + def getRegion(self): + region = super().getRegion() + if self.logmode: + return 10**region[0], 10**region[1] + else: + return region + + def boundingRect(self): + # overwrite to draw correct rect in logmode + + br = self.viewRect() # bounds of containing ViewBox mapped to local coords. + + rng = self.getRegion() + if self.logmode: + rng = np.log10(rng[0]), np.log10(rng[1]) + + if self.orientation in ('vertical', LinearRegionItem.Vertical): + br.setLeft(rng[0]) + br.setRight(rng[1]) + length = br.height() + br.setBottom(br.top() + length * self.span[1]) + br.setTop(br.top() + length * self.span[0]) + else: + br.setTop(rng[0]) + br.setBottom(rng[1]) + length = br.width() + br.setRight(br.left() + length * self.span[1]) + br.setLeft(br.left() + length * self.span[0]) + + br = br.normalized() + + if self._bounds != br: + self._bounds = br + self.prepareGeometryChange() + + return br diff --git a/nmreval/gui_qt/lib/randpok.py b/nmreval/gui_qt/lib/randpok.py new file mode 100644 index 0000000..55de7de --- /dev/null +++ b/nmreval/gui_qt/lib/randpok.py @@ -0,0 +1,119 @@ +import sys +import os.path +import json +import urllib.request +import webbrowser +import random + +from ..Qt import QtGui, QtCore, QtWidgets +from .._py.pokemon import Ui_Dialog + +random.seed() + + +class QPokemon(QtWidgets.QDialog, Ui_Dialog): + def __init__(self, number=None, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + self._js = json.load(open(os.path.join(path_to_module, 'utils', 'pokemon.json'), 'r'), encoding='UTF-8') + self._id = 0 + + if number is not None and number in range(1, len(self._js)+1): + poke_nr = f'{number:03d}' + self._id = number + else: + poke_nr = f'{random.randint(1, len(self._js)):03d}' + self._id = int(poke_nr) + + self._pokemon = None + self.show_pokemon(poke_nr) + self.label_15.linkActivated.connect(lambda x: webbrowser.open(x)) + + self.buttonBox.clicked.connect(self.randomize) + self.next_button.clicked.connect(self.show_next) + self.prev_button.clicked.connect(self.show_prev) + + def show_pokemon(self, nr): + self._pokemon = self._js[nr] + self.setWindowTitle('Pokémon: ' + self._pokemon['Deutsch']) + + for i in range(self.tabWidget.count(), -1, -1): + print('i', self.tabWidget.count(), i) + try: + self.tabWidget.widget(i).deleteLater() + except AttributeError: + pass + + for n, img in self._pokemon['Bilder']: + w = QtWidgets.QWidget() + vl = QtWidgets.QVBoxLayout() + l = QtWidgets.QLabel(self) + l.setAlignment(QtCore.Qt.AlignHCenter) + pixmap = QtGui.QPixmap() + + try: + pixmap.loadFromData(urllib.request.urlopen(img, timeout=0.5).read()) + except IOError: + l.setText(n) + else: + sc_pixmap = pixmap.scaled(256, 256, QtCore.Qt.KeepAspectRatio) + l.setPixmap(sc_pixmap) + + vl.addWidget(l) + w.setLayout(vl) + self.tabWidget.addTab(w, n) + + if len(self._pokemon['Bilder']) <= 1: + self.tabWidget.tabBar().setVisible(False) + else: + self.tabWidget.tabBar().setVisible(True) + self.tabWidget.adjustSize() + + self.name.clear() + keys = ['National-Dex', 'Kategorie', 'Typ', 'Größe', 'Gewicht', 'Farbe', 'Link'] + label_list = [self.pokedex_nr, self.category, self.poketype, self.weight, self.height, self.color, self.info] + for (k, label) in zip(keys, label_list): + v = self._pokemon[k] + if isinstance(v, list): + v = os.path.join('', *v) + + if k == 'Link': + v = '{}'.format(v, v) + + label.setText(v) + + for k in ['Deutsch', 'Japanisch', 'Englisch', 'Französisch']: + v = self._pokemon[k] + self.name.addItem(k + ': ' + v) + + self.adjustSize() + + def randomize(self, idd): + if idd.text() == 'Retry': + new_number = f'{random.randint(1, len(self._js)):03d}' + self._id = int(new_number) + self.show_pokemon(new_number) + else: + self.close() + + def show_next(self): + new_number = self._id + 1 + if new_number > len(self._js): + new_number = 1 + self._id = new_number + self.show_pokemon(f'{new_number:03d}') + + def show_prev(self): + new_number = self._id - 1 + if new_number == 0: + new_number = len(self._js) + self._id = new_number + self.show_pokemon(f'{new_number:03d}') + + +if __name__ == '__main__': + app = QtWidgets.QApplication(sys.argv) + w = QPokemon(number=807) + w.show() + + sys.exit(app.exec()) diff --git a/nmreval/gui_qt/lib/stuff.py b/nmreval/gui_qt/lib/stuff.py new file mode 100644 index 0000000..59a1207 --- /dev/null +++ b/nmreval/gui_qt/lib/stuff.py @@ -0,0 +1,502 @@ +import random +import sys +import numpy as np + +from nmreval.gui_qt.Qt import QtWidgets, QtCore, QtGui + + +__all__ = ['Game'] + + +class Game(QtWidgets.QDialog): + def __init__(self, mode, parent=None): + super().__init__(parent=parent) + + layout = QtWidgets.QVBoxLayout() + layout.setContentsMargins(3, 3, 3, 3) + + self.label = QtWidgets.QLabel(self) + layout.addWidget(self.label) + + self.startbutton = QtWidgets.QPushButton('Start', self) + self.startbutton.clicked.connect(self.start) + layout.addWidget(self.startbutton) + + if mode == 'tetris': + self._setup_tetris() + else: + self._setup_snake() + + layout.addWidget(self.board) + self.setStyleSheet(""" + Board { + border: 5px solid black; + } + QPushButton { + font-weight: bold; + } + """) + + self.setLayout(layout) + + self.board.new_status.connect(self.new_message) + + def _setup_tetris(self): + self.board = TetrisBoard(self) + self.setGeometry(200, 100, 276, 546+self.startbutton.height()+self.label.height()) + self.setWindowTitle('Totally not Tetris') + + def _setup_snake(self): + self.board = SnakeBoard(self) + self.setGeometry(200, 100, 406, 406+self.startbutton.height()+self.label.height()) + self.setWindowTitle('Snakey') + + def start(self): + + self.board.start() + + @QtCore.pyqtSlot(str) + def new_message(self, msg: str): + self.label.setText(msg) + + +class Board(QtWidgets.QFrame): + new_status = QtCore.pyqtSignal(str) + + SPEED = 1000 + WIDTH = 10 + HEIGHT = 10 + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.timer = QtCore.QTimer(self) + self.timer.timeout.connect(self.next_move) + + self.score = 0 + self._speed = self.SPEED + self._ispaused = False + self._isdead = True + + self.setFrameStyle(QtWidgets.QFrame.Box | QtWidgets.QFrame.Raised) + self.setLineWidth(3) + + self.setFocusPolicy(QtCore.Qt.StrongFocus) + self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) + + def _init_game(self): + raise NotImplementedError + + @property + def cellwidth(self): + return int(self.contentsRect().width() // self.WIDTH) + + # square height + @property + def cellheight(self): + return int(self.contentsRect().height() // self.HEIGHT) + + def start(self): + if self._isdead: + self._init_game() + self.new_status.emit(f'Score: {self.score}') + self.timer.start(self._speed) + self._isdead = False + self.setFocus() + + def stop(self, msg): + self.new_status.emit(f'Score {self.score} // ' + msg) + self._isdead = True + self.timer.stop() + + def pause(self): + if self._ispaused and not self._isdead: + self.new_status.emit(f'Score {self.score}') + self.timer.start(self._speed) + else: + self.new_status.emit(f'Score {self.score} // Paused') + self.timer.stop() + + self._ispaused = not self._ispaused + + def next_move(self): + raise NotImplementedError + + def draw_square(self, painter, x, y, color): + color = QtGui.QColor(color) + painter.fillRect(x+1, y+1, self.cellwidth-2, self.cellheight-2, color) + + def draw_circle(self, painter, x, y, color): + painter.save() + + color = QtGui.QColor(color) + painter.setPen(QtGui.QPen(color)) + painter.setBrush(QtGui.QBrush(color)) + painter.drawEllipse(x+1, y+1, self.cellwidth, self.cellheight) + + painter.restore() + + def keyPressEvent(self, evt): + if evt.key() == QtCore.Qt.Key_P: + self.pause() + else: + super().keyPressEvent(evt) + + +class SnakeBoard(Board): + SPEED = 100 + WIDTH = 30 + HEIGHT = 30 + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.snake = [[int(SnakeBoard.WIDTH//2), int(SnakeBoard.HEIGHT//2)], + [int(SnakeBoard.WIDTH//2)+1, int(SnakeBoard.HEIGHT//2)]] + self.current_x_head, self.current_y_head = self.snake[0] + self.direction = 'l' + + self.food = None + self.grow_snake = False + + def _init_game(self): + self.snake = [[int(SnakeBoard.WIDTH//2), int(SnakeBoard.HEIGHT//2)], + [int(SnakeBoard.WIDTH//2)+1, int(SnakeBoard.HEIGHT//2)]] + self.current_x_head, self.current_y_head = self.snake[0] + self.direction = 'l' + + self.food = None + self.grow_snake = False + self.new_food() + + def next_move(self): + self.snake_move() + self.got_food() + self.check_death() + self.update() + + def snake_move(self): + if self.direction == 'l': + self.current_x_head -= 1 + elif self.direction == 'r': + self.current_x_head += 1 + + # y increases top to bottom + elif self.direction == 'u': + self.current_y_head -= 1 + elif self.direction == 'd': + self.current_y_head += 1 + + head = [self.current_x_head, self.current_y_head] + self.snake.insert(0, head) + + if not self.grow_snake: + self.snake.pop() + else: + self.new_status.emit(f'Score: {self.score}') + self.grow_snake = False + + def got_food(self): + head = self.snake[0] + if self.food == head: + self.new_food() + self.grow_snake = True + self.score += 1 + + def new_food(self): + x = random.randint(3, SnakeBoard.WIDTH-3) + y = random.randint(3, SnakeBoard.HEIGHT-3) + + while [x, y] == self.snake[0]: + x = random.randint(3, SnakeBoard.WIDTH-3) + y = random.randint(3, SnakeBoard.HEIGHT-3) + + self.food = [x, y] + + def check_death(self): + rip_message = '' + is_dead = False + if (self.current_x_head < 1) or (self.current_x_head > SnakeBoard.WIDTH-2) or \ + (self.current_y_head < 1) or (self.current_y_head > SnakeBoard.HEIGHT-2): + rip_message = 'Snake found wall :(' + is_dead = True + + head = self.snake[0] + for snake_i in self.snake[1:]: + if snake_i == head: + rip_message = 'Snake bit itself :(' + is_dead = True + break + + if is_dead: + self.stop(rip_message) + + def keyPressEvent(self, event): + key = event.key() + if key in (QtCore.Qt.Key_Left, QtCore.Qt.Key_A): + if self.direction != 'r': + self.direction = 'l' + + elif key in (QtCore.Qt.Key_Right, QtCore.Qt.Key_D): + if self.direction != 'l': + self.direction = 'r' + + elif key in (QtCore.Qt.Key_Down, QtCore.Qt.Key_S): + if self.direction != 'u': + self.direction = 'd' + + elif key in (QtCore.Qt.Key_Up, QtCore.Qt.Key_W): + if self.direction != 'd': + self.direction = 'u' + + else: + return super().keyPressEvent(event) + + def paintEvent(self, event): + painter = QtGui.QPainter(self) + + rect = self.contentsRect() + boardtop = rect.bottom() - SnakeBoard.HEIGHT * self.cellheight + boardleft = rect.left() + + for pos in self.snake: + self.draw_circle(painter, + int(boardleft+pos[0]*self.cellwidth), + int(boardtop+pos[1]*self.cellheight), + 'blue') + if self.food is not None: + self.draw_square(painter, + int(boardleft+self.food[0]*self.cellwidth), + int(boardtop+self.food[1]*self.cellheight), + 'orange') + + +class TetrisBoard(Board): + WIDTH = 10 + HEIGHT = 20 + SPEED = 300 + + def __init__(self, parent=None): + super().__init__(parent=parent) + + self._shapes = { + 1: ZShape, + 2: SShape, + 3: Line, + 4: TShape, + 5: Square, + 6: MirrorL + } + + self._init_game() + + def _init_game(self): + self.curr_x = 0 + self.curr_y = 0 + self.curr_piece = None + self.board = np.zeros((TetrisBoard.WIDTH, TetrisBoard.HEIGHT + 2), dtype=int) + + def next_move(self): + if self.curr_piece is None: + self.make_new_piece() + else: + self.move_down() + + def try_move(self, piece, x, y): + if piece is None: + return False + + if x+piece.x.min() < 0 or x+piece.x.max() >= TetrisBoard.WIDTH: + return False + + if y-piece.y.max() < 0 or y-piece.y.min() >= TetrisBoard.HEIGHT+2: + return False + + if np.any(self.board[piece.x+x, y-piece.y]) != 0: + return False + + if piece != self.curr_piece: + self.curr_piece = piece + + self.curr_x = x + self.curr_y = y + + self.update() + + return True + + def make_new_piece(self): + new_piece = self._shapes[random.randint(1, len(self._shapes))]() + + startx = TetrisBoard.WIDTH//2 + starty = TetrisBoard.HEIGHT+2 - 1 + new_piece.y.min() + if not self.try_move(new_piece, startx, starty): + self.stop('Game over :(') + + def move_down(self): + if not self.try_move(self.curr_piece, self.curr_x, self.curr_y-1): + self.final_destination_reached() + + def drop_to_bottom(self): + new_y = self.curr_y + + while new_y > 0: + if not self.try_move(self.curr_piece, self.curr_x, new_y-1): + break + new_y -= 1 + + self.final_destination_reached() + + def final_destination_reached(self): + x = self.curr_x+self.curr_piece.x + y = self.curr_y-self.curr_piece.y + self.board[x, y] = next(k for k, v in self._shapes.items() if isinstance(self.curr_piece, v)) + + self.remove_lines() + + self.curr_piece = None + self.make_new_piece() + + def remove_lines(self): + full_rows = np.where(np.all(self.board, axis=0))[0] + num_rows = len(full_rows) + + if num_rows: + temp = np.zeros_like(self.board) + temp[:, :temp.shape[1]-num_rows] = np.delete(self.board, full_rows, axis=1) + self.board = temp + + self.score += num_rows + self.new_status.emit(f'Lines: {self.score}') + + if self.score % 10 == 0: + self._speed += 0.9 + self.timer.setInterval(int(self._speed)) + + self.update() + + def keyPressEvent(self, event): + key = event.key() + + if self.curr_piece is None: + return super().keyPressEvent(event) + + if key == QtCore.Qt.Key_Left: + self.try_move(self.curr_piece, self.curr_x-1, self.curr_y) + + elif key == QtCore.Qt.Key_Right: + self.try_move(self.curr_piece, self.curr_x+1, self.curr_y) + + elif key == QtCore.Qt.Key_Down: + if not self.try_move(self.curr_piece.rotate(), self.curr_x, self.curr_y): + self.curr_piece.rotate(clockwise=False) + + elif key == QtCore.Qt.Key_Up: + if not self.try_move(self.curr_piece.rotate(clockwise=False), self.curr_x, self.curr_y): + self.curr_piece.rotate() + + elif key == QtCore.Qt.Key_Space: + self.drop_to_bottom() + + else: + super().keyPressEvent(event) + + def paintEvent(self, event): + painter = QtGui.QPainter(self) + rect = self.contentsRect() + board_top = rect.bottom() - TetrisBoard.HEIGHT*self.cellheight + + for i in range(TetrisBoard.WIDTH): + for j in range(TetrisBoard.HEIGHT): + shape = self.board[i, j] + + if shape: + color = self._shapes[shape].color + self.draw_square(painter, + rect.left() + i*self.cellwidth, + board_top + (TetrisBoard.HEIGHT-j-1)*self.cellheight, color) + + if self.curr_piece is not None: + x = self.curr_x + self.curr_piece.x + y = self.curr_y - self.curr_piece.y + + for i in range(4): + if TetrisBoard.HEIGHT < y[i]+1: + continue + + self.draw_square(painter, rect.left() + x[i] * self.cellwidth, + board_top + (TetrisBoard.HEIGHT-y[i]-1) * self.cellheight, + self.curr_piece.color) + + +class Tetromino: + SHAPE = np.array([[0], [0]]) + color = None + + def __init__(self): + self.shape = self.SHAPE + + def rotate(self, clockwise: bool = True): + if clockwise: + self.shape = np.vstack((-self.shape[1], self.shape[0])) + else: + self.shape = np.vstack((self.shape[1], -self.shape[0])) + + return self + + @property + def x(self): + return self.shape[0] + + @property + def y(self): + return self.shape[1] + + +class ZShape(Tetromino): + SHAPE = np.array([[0, 0, -1, -1], + [-1, 0, 0, 1]]) + color = 'green' + + +class SShape(Tetromino): + SHAPE = np.array([[0, 0, 1, 1], + [-1, 0, 0, 1]]) + color = 'purple' + + +class Line(Tetromino): + SHAPE = np.array([[0, 0, 0, 0], + [-1, 0, 1, 2]]) + color = 'red' + + +class TShape(Tetromino): + SHAPE = np.array([[-1, 0, 1, 0], + [0, 0, 0, 1]]) + color = 'orange' + + +class Square(Tetromino): + SHAPE = np.array([[0, 1, 0, 1], + [0, 0, 1, 1]]) + color = 'yellow' + + +class LShape(Tetromino): + SHAPE = np.array([[-1, 0, 0, 0], + [1, -1, 0, 1]]) + color = 'blue' + + +class MirrorL(Tetromino): + SHAPE = np.array([[1, 0, 0, 0], + [-1, -1, 0, 1]]) + color = 'lightGray' + + +if __name__ == '__main__': + app = QtWidgets.QApplication([]) + tetris = Game('snake') + tetris.show() + sys.exit(app.exec_()) diff --git a/nmreval/gui_qt/lib/styles.py b/nmreval/gui_qt/lib/styles.py new file mode 100644 index 0000000..d453f50 --- /dev/null +++ b/nmreval/gui_qt/lib/styles.py @@ -0,0 +1,102 @@ +from . import HAS_IMPORTLIB_RESOURCE +from ..Qt import QtGui, QtWidgets + + +class DarkPalette(QtGui.QPalette): + def __init__(self): + super().__init__() + + self.setColor(QtGui.QPalette.Base, QtGui.QColor(42, 42, 42)) + self.setColor(QtGui.QPalette.AlternateBase, QtGui.QColor(66, 66, 66)) + self.setColor(QtGui.QPalette.Window, QtGui.QColor(93, 93, 93)) + self.setColor(QtGui.QPalette.ToolTipBase, QtGui.QColor(93, 93, 93)) + self.setColor(QtGui.QPalette.Button, QtGui.QColor(93, 93, 93)) + + self.setColor(QtGui.QPalette.WindowText, QtGui.QColor(220, 220, 220)) + self.setColor(QtGui.QPalette.ToolTipText, QtGui.QColor(220, 220, 220)) + self.setColor(QtGui.QPalette.Text, QtGui.QColor(220, 220, 220)) + self.setColor(QtGui.QPalette.BrightText, QtGui.QColor(220, 220, 220)) + self.setColor(QtGui.QPalette.ButtonText, QtGui.QColor(220, 220, 220)) + self.setColor(QtGui.QPalette.HighlightedText, QtGui.QColor(220, 220, 220)) + + self.setColor(QtGui.QPalette.Shadow, QtGui.QColor(20, 20, 20)) + self.setColor(QtGui.QPalette.Dark, QtGui.QColor(35, 35, 35)) + + self.setColor(QtGui.QPalette.Highlight, QtGui.QColor(42, 130, 218)) + self.setColor(QtGui.QPalette.Link, QtGui.QColor(220, 220, 220)) + self.setColor(QtGui.QPalette.LinkVisited, QtGui.QColor(108, 180, 218)) + + # disabled + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Base, QtGui.QColor(80, 80, 80)) + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Window, QtGui.QColor(80, 80, 80)) + + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Text, QtGui.QColor(127, 127, 127)) + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, QtGui.QColor(127, 127, 127)) + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.HighlightedText, QtGui.QColor(127, 127, 127)) + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, QtGui.QColor(127, 127, 127)) + + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Highlight, QtGui.QColor(80, 80, 80)) + + +class LightPalette(QtGui.QPalette): + def __init__(self): + super().__init__() + + self.setColor(QtGui.QPalette.Base, QtGui.QColor(237, 237, 237)) + self.setColor(QtGui.QPalette.AlternateBase, QtGui.QColor(225, 225, 225)) + self.setColor(QtGui.QPalette.Window, QtGui.QColor(240, 240, 240)) + self.setColor(QtGui.QPalette.ToolTipBase, QtGui.QColor(240, 240, 240)) + self.setColor(QtGui.QPalette.Button, QtGui.QColor(240, 240, 240)) + + self.setColor(QtGui.QPalette.WindowText, QtGui.QColor(0, 0, 0)) + self.setColor(QtGui.QPalette.Text, QtGui.QColor(0, 0, 0)) + self.setColor(QtGui.QPalette.BrightText, QtGui.QColor(0, 0, 0)) + self.setColor(QtGui.QPalette.ButtonText, QtGui.QColor(0, 0, 0)) + self.setColor(QtGui.QPalette.ToolTipText, QtGui.QColor(0, 0, 0)) + self.setColor(QtGui.QPalette.HighlightedText, QtGui.QColor(0, 0, 0)) + + self.setColor(QtGui.QPalette.Shadow, QtGui.QColor(20, 20, 20)) + self.setColor(QtGui.QPalette.Dark, QtGui.QColor(225, 225, 225)) + + self.setColor(QtGui.QPalette.Highlight, QtGui.QColor(218, 66, 42)) + self.setColor(QtGui.QPalette.Link, QtGui.QColor(0, 162, 232)) + self.setColor(QtGui.QPalette.LinkVisited, QtGui.QColor(222, 222, 222)) + + # disabled + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Base, QtGui.QColor(115, 115, 115)) + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Window, QtGui.QColor(115, 115, 115)) + + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, QtGui.QColor(115, 115, 115)) + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Text, QtGui.QColor(115, 115, 115)) + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, QtGui.QColor(115, 115, 115)) + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.HighlightedText, QtGui.QColor(115, 115, 115)) + + self.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Highlight, QtGui.QColor(190, 190, 190)) + + +class MyProxyStyle(QtWidgets.QProxyStyle): + def __init__(self, color): + super().__init__() + + if color == 'dark': + self._palette = DarkPalette() + else: + self._palette = LightPalette() + + def polish(self, obj): + if isinstance(obj, QtGui.QPalette): + return self._palette + + elif isinstance(obj, QtWidgets.QApplication): + if HAS_IMPORTLIB_RESOURCE: + from importlib.resources import path + with path('resources.icons', 'style.qss') as fp: + with fp.open('r') as f: + obj.setStyleSheet(f.read()) + else: + from pkg_resources import resource_filename + with open(resource_filename('resources.icons', 'style.qss'), 'r') as f: + obj.setStyleSheet(f.read()) + + else: + return super().polish(obj) diff --git a/nmreval/gui_qt/lib/tables.py b/nmreval/gui_qt/lib/tables.py new file mode 100644 index 0000000..15195c4 --- /dev/null +++ b/nmreval/gui_qt/lib/tables.py @@ -0,0 +1,31 @@ +from ..Qt import QtWidgets, QtGui, QtCore + + +class TreeWidget(QtWidgets.QTreeWidget): + def keyPressEvent(self, evt: QtGui.QKeyEvent): + if evt.key() == QtCore.Qt.Key_Space: + sets = [] + from_parent = [] + + for idx in self.selectedIndexes(): + if idx.column() != 0: + continue + item = self.itemFromIndex(idx) + + if item.parent() is None: + is_selected = item.checkState(0) + self.blockSignals(True) + for i in range(item.childCount()): + child = item.child(i) + # child.setCheckState(0, is_selected) + from_parent.append(child) + self.blockSignals(False) + item.setCheckState(0, QtCore.Qt.Unchecked if is_selected == QtCore.Qt.Checked else QtCore.Qt.Checked) + else: + sets.append(item) + for it in sets: + if it in from_parent: + continue + it.setCheckState(0, QtCore.Qt.Unchecked if it.checkState(0) == QtCore.Qt.Checked else QtCore.Qt.Checked) + else: + super().keyPressEvent(evt) \ No newline at end of file diff --git a/nmreval/gui_qt/lib/undos.py b/nmreval/gui_qt/lib/undos.py new file mode 100644 index 0000000..d2231af --- /dev/null +++ b/nmreval/gui_qt/lib/undos.py @@ -0,0 +1,245 @@ +import copy + +from numpy import argsort + +from ..Qt import QtWidgets, QtCore +from ..data.container import FitContainer +from ..graphs.graphwindow import QGraphWindow + + +class ApodizationCommand(QtWidgets.QUndoCommand): + def __init__(self, data, apod_values: list, apod_func: object): + super().__init__('Apodization') + + self.__data = data + self.__y = copy.deepcopy(data.data.y) + self.__apod_func = apod_func + self.__apod_values = apod_values + + def undo(self): + # doing a copy (again) to ensure two different objects + self.__data.y = copy.deepcopy(self.__y) + + def redo(self): + self.__data.apply('ap', (self.__apod_values, self.__apod_func)) + + +class CutCommand(QtWidgets.QUndoCommand): + def __init__(self, data, *limits): + super().__init__('Apodization') + + self.__data = data + self.__data_data = copy.deepcopy(data.data) + self.__limits = limits + + def undo(self): + # doing a copy (again) to ensure two different objects + self.__data.data = copy.deepcopy(self.__data_data) + + def redo(self): + self.__data.apply('cut', self.__limits) + + +class PhaseCommand(QtWidgets.QUndoCommand): + def __init__(self, data, ph0: float, ph1: float, pvt: float): + super().__init__('Phase correction') + + self.__phase = (ph0, ph1, pvt) + self.__data = data + + def undo(self): + self.__data.apply('ph', (-self.__phase[0], -self.__phase[1], self.__phase[2])) + + def redo(self): + self.__data.apply('ph', self.__phase) + + +class ShiftCommand(QtWidgets.QUndoCommand): + def __init__(self, data, value, mode): + super().__init__('Fourier') + + self.__data = data + self.__original = copy.deepcopy(self.__data.data) + self.__args = (value, mode) + + def undo(self): + self.__data.data = copy.deepcopy(self.__original) + + def redo(self): + self.__data.apply('ls', self.__args) + + +class NormCommand(QtWidgets.QUndoCommand): + def __init__(self, data, mode): + super().__init__('Normalize') + + self.__data = data + self.__mode = mode + self.__scale = 1. + + def undo(self): + self.__data.y *= self.__scale + self.__data.y_err *= self.__scale + + def redo(self): + max_value = self.__data.y.max() + self.__data.apply('norm', (self.__mode,)) + self.__scale = max_value / self.__data.y.max() + + +class CenterCommand(QtWidgets.QUndoCommand): + def __init__(self, data): + super().__init__('Normalize') + + self.__data = data + self.__offset = 0. + + def undo(self): + _x = self.__data.data.x + _x += self.__offset + self.__data.x = _x + + def redo(self): + x0 = self.__data.x[0] + self.__data.apply('center', ()) + self.__offset = x0 - self.__data.x[0] + + +class ZerofillCommand(QtWidgets.QUndoCommand): + def __init__(self, data): + super().__init__('Zero filling') + + self.__data = data + + def undo(self): + self.__data.apply('zf', (-1,)) + + def redo(self): + self.__data.apply('zf', (1,)) + + +class BaselineCommand(QtWidgets.QUndoCommand): + def __init__(self, data): + super().__init__('Baseline correction') + + self.__baseline = None + self.__data = data + + def undo(self): + self.__data.y += self.__baseline + + def redo(self): + y_prev = self.__data.y[-1] + self.__data.apply('bl', tuple()) + self.__baseline = y_prev - self.__data.y[-1] + + +class BaselineSplineCommand(QtWidgets.QUndoCommand): + def __init__(self, data, baseline): + super().__init__('Baseline correction') + + self.__baseline = baseline + self.__data = data + + def undo(self): + self.__data.apply('bls', (-self.__baseline,)) + + def redo(self): + self.__data.apply('bls', (self.__baseline,)) + + +class FourierCommand(QtWidgets.QUndoCommand): + def __init__(self, data): + super().__init__('Fourier') + + self.__data = data + self.__original = copy.deepcopy(self.__data.data) + + def undo(self): + self.__data.data = copy.deepcopy(self.__original) + + def redo(self): + self.__data.apply('ft', tuple()) + + +class SortCommand(QtWidgets.QUndoCommand): + def __init__(self, data): + super().__init__('Sort') + + self.__data = data + self.__sort = None + + def undo(self): + self.__data.unsort(self.__sort) + + def redo(self): + self.__sort = argsort(argsort(self.__data.data.x)) + self.__data.apply('sort', tuple()) + + +class DeleteGraphCommand(QtWidgets.QUndoCommand): + def __init__(self, container: dict, key: str, + signal1: QtCore.pyqtSignal, signal2: QtCore.pyqtSignal): + super().__init__('Delete graph') + # Deletion of GraphWindow is more complicated because C++ object is destroyed + + self.__container = container + _value = self.__container[key] + self.__value = self.__container[key].get_state() + self.__key = key + self.__signal_add = signal1 + self.__signal_remove = signal2 + + def redo(self): + self.__signal_remove.emit(self.__key) + del self.__container[self.__key] + + def undo(self): + q = QGraphWindow().set_state(self.__value) + self.__container[self.__key] = q + self.__signal_add.emit(self.__key) + + +class DeleteCommand(QtWidgets.QUndoCommand): + def __init__(self, container, key, signal1, signal2): + super().__init__('Delete data') + + self.__container = container + self.__value = self.__container[key] + self.__key = key + self.__signal_add = signal1 + self.__signal_remove = signal2 + + def redo(self): + self.__signal_remove.emit(self.__key) + if isinstance(self.__value, FitContainer): + try: + self.__container[self.__value.fitted_key]._fits.remove(self.__key) + except KeyError: + pass + del self.__container[self.__key] + + def undo(self): + self.__container[self.__key] = self.__value + if isinstance(self.__value, FitContainer): + try: + self.__container[self.__value.fitted_key]._fits.append(self.__key) + except KeyError: + pass + + self.__signal_add.emit([self.__key], self.__value.graph) + + +class EvalCommand(QtWidgets.QUndoCommand): + def __init__(self, container: dict, key: str, new_data, title: str): + super().__init__(title) + self.__container = container + self.__value = copy.deepcopy(self.__container[key].data) + self.__replacement = new_data + self.__key = key + + def redo(self): + self.__container[self.__key].data = self.__replacement + + def undo(self): + self.__container[self.__key].data = self.__value diff --git a/nmreval/gui_qt/lib/usermodeleditor.py b/nmreval/gui_qt/lib/usermodeleditor.py new file mode 100644 index 0000000..ab02c45 --- /dev/null +++ b/nmreval/gui_qt/lib/usermodeleditor.py @@ -0,0 +1,143 @@ +from __future__ import annotations + +from pathlib import Path + +from ..Qt import QtWidgets, QtCore, QtGui +from ..lib.codeeditor import CodeEditor + + +class QUsermodelEditor(QtWidgets.QMainWindow): + modelsChanged = QtCore.pyqtSignal() + + def __init__(self, fname: str | Path = None, parent=None): + super().__init__(parent=parent) + + self._init_gui() + + self.fname = None + self._dir = None + if fname is not None: + self.read_file(fname) + + def _init_gui(self): + self.centralwidget = QtWidgets.QWidget(self) + + layout = QtWidgets.QVBoxLayout(self.centralwidget) + layout.setContentsMargins(3, 3, 3, 3) + layout.setSpacing(3) + + self.edit_field = CodeEditor(self.centralwidget) + font = QtGui.QFont('default') + font.setStyleHint(font.Monospace) + font.setPointSize(10) + self.edit_field.setFont(font) + + layout.addWidget(self.edit_field) + self.setCentralWidget(self.centralwidget) + + self.statusbar = QtWidgets.QStatusBar(self) + self.setStatusBar(self.statusbar) + + self.menubar = self.menuBar() + + self.menuFile = QtWidgets.QMenu('File', self.menubar) + self.menubar.addMenu(self.menuFile) + + self.menuFile.addAction('Open...', self.open_file, QtGui.QKeySequence.Open) + self.menuFile.addAction('Save', self.overwrite_file, QtGui.QKeySequence.Save) + self.menuFile.addAction('Save as...', self.save_file, QtGui.QKeySequence('Ctrl+Shift+S')) + self.menuFile.addSeparator() + self.menuFile.addAction('Close', self.close, QtGui.QKeySequence.Quit) + + self.resize(800, 600) + self.setGeometry(QtWidgets.QStyle.alignedRect( + QtCore.Qt.LeftToRight, QtCore.Qt.AlignCenter, + self.size(), QtWidgets.qApp.desktop().availableGeometry() + )) + + @property + def is_modified(self): + return self.edit_field.document().isModified() + + @is_modified.setter + def is_modified(self, val: bool): + self.edit_field.document().setModified(val) + + @QtCore.pyqtSlot() + def open_file(self): + overwrite = self.changes_saved + + if overwrite: + fname, _ = QtWidgets.QFileDialog.getOpenFileName(directory=str(self._dir)) + if fname: + self.read_file(fname) + + def read_file(self, fname: str | Path): + self.set_fname_opts(fname) + + with self.fname.open('r') as f: + self.edit_field.setPlainText(f.read()) + + def set_fname_opts(self, fname: str | Path): + self.fname = Path(fname) + self._dir = self.fname.parent + self.setWindowTitle('Edit ' + str(fname)) + + @property + def changes_saved(self) -> bool: + if not self.is_modified: + return True + + ret = QtWidgets.QMessageBox.question(self, 'Time to think', + '

The document was modified.

\n' + '

Do you want to save changes?

', + QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | + QtWidgets.QMessageBox.Cancel) + if ret == QtWidgets.QMessageBox.Yes: + self.save_file() + + if ret == QtWidgets.QMessageBox.No: + self.is_modified = False + + return not self.is_modified + + @QtCore.pyqtSlot() + def save_file(self): + outfile, _ = QtWidgets.QFileDialog().getSaveFileName(parent=self, caption='Save file', directory=str(self._dir)) + + if outfile: + with open(outfile, 'w') as f: + f.write(self.edit_field.toPlainText()) + + self.set_fname_opts(outfile) + + self.is_modified = False + + return self.is_modified + + @QtCore.pyqtSlot() + def overwrite_file(self): + if self.fname is not None: + with self.fname.open('w') as f: + f.write(self.edit_field.toPlainText()) + + self.modelsChanged.emit() + + self.is_modified = False + + def closeEvent(self, evt: QtGui.QCloseEvent): + if not self.changes_saved: + evt.ignore() + else: + super().closeEvent(evt) + + +if __name__ == '__main__': + import sys + app = QtWidgets.QApplication([]) + + win = QUsermodelEditor('/autohome/dominik/.nmreval/myfitmodels.py') + win.show() + + sys.exit(app.exec()) + diff --git a/nmreval/gui_qt/lib/utils.py b/nmreval/gui_qt/lib/utils.py new file mode 100644 index 0000000..adba102 --- /dev/null +++ b/nmreval/gui_qt/lib/utils.py @@ -0,0 +1,93 @@ +from math import inf +from contextlib import contextmanager +from numpy import linspace +from scipy.interpolate import interp1d + +from ..Qt import QtGui, QtWidgets + + +@contextmanager +def busy_cursor(): + try: + cursor = QtGui.QCursor(QtGui.QPixmap('/autohome/dominik/Downloads/slowbro.gif')) + QtWidgets.QApplication.setOverrideCursor(cursor) + yield + + finally: + QtWidgets.QApplication.restoreOverrideCursor() + + +class SciSpinBox(QtWidgets.QDoubleSpinBox): + def __init__(self, parent=None): + super().__init__(parent=parent) + + self.validator = QtGui.QDoubleValidator(self) + + self.setMinimum(-inf) + self.setMaximum(inf) + self.setDecimals(1000) + self.precision = 0.001 + + self._prev_value = float(self.lineEdit().text()) + + def valueFromText(self, text: str) -> float: + try: + self._prev_value = float(self.cleanText()) + except ValueError: + pass + return self._prev_value + + def textFromValue(self, value: float) -> str: + if value == 0: + return '0' + else: + return f'{value:.3e}' + + def stepBy(self, step: int): + self._prev_value = self.value() + + new_value = self._prev_value + if new_value != 0.0: + new_value *= 10**(step/19.) + else: + new_value = 0.001 + + self.setValue(new_value) + self.lineEdit().setText(f'{new_value:.3e}') + + def validate(self, text, pos): + return self.validator.validate(text, pos) + + +class RdBuCMap: + # taken from Excel sheet from colorbrewer.org + _rdbu = [ + (103, 0, 31), + (178, 24, 43), + (214, 96, 77), + (244, 165, 130), + (253, 219, 199), + (247, 247, 247), + (209, 229, 240), + (146, 197, 222), + (67, 147, 195), + (33, 102, 172), + (5, 48, 97) + ] + + def __init__(self, vmin=-1., vmax=1.): + self.min = vmin + self.max = vmax + + self.spline = [interp1d(linspace(self.max, self.min, num=11), [rgb[i] for rgb in RdBuCMap._rdbu]) + for i in range(3)] + + def color(self, val: float): + if val > self.max: + col = QtGui.QColor.fromRgb(*RdBuCMap._rdbu[0]) + elif val < self.min: + col = QtGui.QColor.fromRgb(*RdBuCMap._rdbu[-1]) + else: + col = QtGui.QColor.fromRgb(*(float(self.spline[i](val)) for i in range(3))) + + return col diff --git a/nmreval/gui_qt/main/__init__.py b/nmreval/gui_qt/main/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nmreval/gui_qt/main/mainwindow.py b/nmreval/gui_qt/main/mainwindow.py new file mode 100644 index 0000000..2747138 --- /dev/null +++ b/nmreval/gui_qt/main/mainwindow.py @@ -0,0 +1,922 @@ +import pathlib +from pathlib import Path +from typing import List, Tuple + +from numpy import geomspace, linspace +from pyqtgraph import ViewBox, PlotDataItem + +from .management import UpperManagement +from ..Qt import QtCore, QtGui, QtPrintSupport, QtWidgets +from ..data.shift_graphs import QShift +from ..data.signaledit import QApodDialog, QBaselineDialog, QPhasedialog +from ..fit.result import QFitResult +from ..graphs.graphwindow import QGraphWindow +from ..graphs.movedialog import QMover +from ..io.fcbatchreader import QFCReader +from ..io.filedialog import OpenFileDialog, SaveDirectoryDialog +from ..lib import get_icon, make_action_icons +from ..lib.pg_objects import RegionItem +from ..math.evaluation import QEvalDialog +from ..math.interpol import InterpolDialog +from ..math.mean_dialog import QMeanTimes +from ..math.smooth import QSmooth +from ..nmr.coupling_calc import QCoupCalcDialog +from ..nmr.t1_from_tau import QRelaxCalc +from .._py.basewindow import Ui_BaseWindow +from ...configs import * + + +class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow): + closeSignal = QtCore.pyqtSignal() + openpoints = QtCore.pyqtSignal(dict) + save_ses_sig = QtCore.pyqtSignal(str) + rest_ses_sig = QtCore.pyqtSignal(str) + + def __init__(self, parents=None, path=None): + super().__init__(parent=parents) + + if path is None: + self.path = Path.home() + else: + self.path = Path(path) + + self.read_state() + + self.management = UpperManagement(self) + + self.fitlimitvalues = [None, None] + self.fitpreview = [] + self._fit_plot_id = None + self.savefitdialog = None + self.eval = None + self.editor = None + + self.movedialog = QMover(self) + + self.current_graph_widget = None + self.current_plotitem = None + self._block_window_change = False + + self.fname = None + self.tim = QtCore.QTimer() + + self.settings = QtCore.QSettings('NMREVal', 'settings') + self._init_gui() + self._init_signals() + + def _init_gui(self): + self.setupUi(self) + make_action_icons(self) + self.setWindowIcon(get_icon('logo')) + + self.norm_toolbutton = QtWidgets.QToolButton(self) + self.norm_toolbutton.setMenu(self.menuNormalize) + self.norm_toolbutton.setPopupMode(self.norm_toolbutton.InstantPopup) + self.norm_toolbutton.setIcon(get_icon('normal')) + self.toolbar_edit.addWidget(self.norm_toolbutton) + + self.fitlim_button = QtWidgets.QToolButton(self) + self.fitlim_button.setMenu(self.menuLimits) + self.fitlim_button.setPopupMode(self.fitlim_button.InstantPopup) + self.fitlim_button.setIcon(get_icon('fit_region')) + self.toolBar_fit.addWidget(self.fitlim_button) + + self.area.dragEnterEvent = self.dragEnterEvent + + while self.tabWidget.count() > 2: + self.tabWidget.removeTab(self.tabWidget.count()-1) + + # Prevent closing "data" and "values" + for i in [0, 1]: + self.tabWidget.tabBar().tabButton(i, QtWidgets.QTabBar.ButtonPosition.RightSide).resize(0, 0) + + self.setAcceptDrops(True) + + self.mousepos = QtWidgets.QLabel('') + self.status = QtWidgets.QLabel('') + self.statusBar.addWidget(self.status) + self.statusBar.addWidget(self.mousepos) + + self.fitregion = RegionItem() + self._values_plot = PlotDataItem(x=[], y=[], symbolSize=30, symbol='x', + pen=None, symbolPen='#d526b5', symbolBrush='#d526b5') + + self._fit_plot_id = None + + self.setGeometry(QtWidgets.QStyle.alignedRect(QtCore.Qt.LeftToRight, QtCore.Qt.AlignCenter, + self.size(), QtWidgets.qApp.desktop().availableGeometry())) + + self.datawidget.management = self.management + + self.ac_group = QtWidgets.QActionGroup(self) + self.ac_group.addAction(self.action_lm_fit) + self.ac_group.addAction(self.action_nm_fit) + self.ac_group.addAction(self.action_odr_fit) + + self.ac_group2 = QtWidgets.QActionGroup(self) + self.ac_group2.addAction(self.action_no_range) + self.ac_group2.addAction(self.action_x_range) + self.ac_group2.addAction(self.action_custom_range) + + def _init_signals(self): + self.actionRedo = self.management.undostack.createRedoAction(self) + icon = QtGui.QIcon.fromTheme("edit-redo") + self.actionRedo.setIcon(icon) + self.actionRedo.setShortcuts(QtGui.QKeySequence.Redo) + self.menuData.insertAction(self.action_new_set, self.actionRedo) + + self.actionUndo = self.management.undostack.createUndoAction(self) + self.actionUndo.setShortcuts(QtGui.QKeySequence.Undo) + icon = QtGui.QIcon.fromTheme("edit-undo") + self.actionUndo.setIcon(icon) + self.menuData.insertAction(self.actionRedo, self.actionUndo) + + # # self.actionSave.triggered.connect(lambda: self.management.save('/autohome/dominik/nmreval/testdata/test.nmr', '')) + # self.actionSave.triggered.connect(self.save) + self.action_save_fit_parameter.triggered.connect(self.save_fit_parameter) + self.ac_group2.triggered.connect(self.change_fit_limits) + + self.t1action.triggered.connect(lambda: self._show_tab('t1_temp')) + self.action_edit.triggered.connect(lambda: self._show_tab('signal')) + self.actionPick_position.triggered.connect(lambda: self._show_tab('pick')) + self.actionIntegrate.triggered.connect(lambda: self._show_tab('integrate')) + self.action_FitWidget.triggered.connect(lambda: self._show_tab('fit')) + + self.action_new_set.triggered.connect(self.management.create_empty) + + self.datawidget.keyChanged.connect(self.management.change_keys) + self.datawidget.tree.deleteItem.connect(self.management.delete_sets) + self.datawidget.tree.moveItem.connect(self.management.move_sets) + self.datawidget.tree.copyItem.connect(self.management.copy_sets) + self.datawidget.graph_toolButton.clicked.connect(self.new_graph) + self.datawidget.empty_toolButton.clicked.connect(self.management.create_empty) + self.datawidget.func_toolButton.clicked.connect(self.make_data_from_function) + self.datawidget.tree.stateChanged.connect(self.management.change_visibility) + self.datawidget.startShowProperty.connect(self.management.get_properties) + self.datawidget.propertyChanged.connect(self.management.update_property) + self.datawidget.tree.saveFits.connect(self.save_fit_parameter) + + self.management.newData.connect(self.show_new_data) + self.management.newGraph.connect(self.new_graph) + self.management.dataChanged.connect(self.update_data) + self.management.deleteData.connect(self.delete_data) + self.management.deleteGraph.connect(self.remove_graph) + self.management.restoreGraph.connect(self.set_graph) + self.management.properties_collected.connect(self.datawidget.set_properties) + self.management.unset_state.connect(lambda x: self.datawidget.uncheck_sets(x)) + self.management.fitFinished.connect(self.show_fit_results) + + self.fit_dialog._management = self.management + self.fit_dialog.preview_emit.connect(self.show_fit_preview) + self.fit_dialog.fitStartSig.connect(self.start_fit) + self.fit_dialog.abortFit.connect(lambda : self.management.stopFit.emit()) + + self.movedialog.moveData.connect(self.move_sets) + self.movedialog.copyData.connect(self.management.copy_sets) + + self.ptsselectwidget.points_selected.connect(self.management.extract_points) + + self.t1tauwidget.newData.connect(self.management.add_new_data) + + self.editsignalwidget.do_something.connect(self.management.apply) + self.editsignalwidget.preview_triggered.connect(self.do_preview) + + self.action_sort_pts.triggered.connect(lambda: self.management.apply('sort', ())) + self.action_calc_eps_derivative.triggered.connect(self.management.bds_deriv) + self.action_magnitude.triggered.connect(self.management.calc_magn) + self.actionCenterMax.triggered.connect(lambda: self.management.apply('center', ())) + + self.valuewidget.requestData.connect(self.show_data_values) + self.valuewidget.itemChanged.connect(self.management.set_values) + self.valuewidget.itemDeleted.connect(self.management.remove_values) + self.valuewidget.itemAdded.connect(self.management.append) + self.valuewidget.maskSignal.connect(self.management.mask_value) + self.valuewidget.values_selected.connect(self.plot_selected_values) + + self.actionMaximize.triggered.connect(lambda: self.current_graph_widget.showMaximized()) + self.actionNext_window.triggered.connect(lambda: self.area.activateNextSubWindow()) + self.actionPrevious.triggered.connect(lambda: self.area.activatePreviousSubWindow()) + + self.closeSignal.connect(self.close) + + self.action_norm_max.triggered.connect(lambda: self.management.apply('norm', ('max',))) + self.action_norm_max_abs.triggered.connect(lambda: self.management.apply('norm', ('maxabs',))) + self.action_norm_first.triggered.connect(lambda: self.management.apply('norm', ('first',))) + self.action_norm_last.triggered.connect(lambda: self.management.apply('norm', ('last',))) + self.action_norm_area.triggered.connect(lambda: self.management.apply('norm', ('area',))) + self.action_cut.triggered.connect(lambda: self.management.cut()) + + self.actionConcatenate_sets.triggered.connect(lambda : self.management.cat()) + + @QtCore.pyqtSlot(name='on_action_open_triggered') + def open(self): + filedialog = OpenFileDialog(directory=self.path, caption='Open files', + filters='All files (*.*);;' + 'Program session (*.nmr);;' + 'HDF files (*.h5);;' + 'Text files (*.txt *.dat);;' + 'Novocontrol Alpha (*.EPS);;' + 'TecMag files (*.tnt);;' + 'Grace files (*.agr)') + + filedialog.set_graphs(self.management.graphs.list()) + + filedialog.exec() + fname = filedialog.selectedFiles() + + if fname: + self.path = Path(fname[0]).parent + self.management.load_files(fname, new_plot=filedialog.add_to_graph) + + @QtCore.pyqtSlot(name='on_actionOpen_FC_triggered') + def read_fc(self): + reader = QFCReader(path=self.path, parent=self) + reader.data_read.connect(self.management.add_new_data) + reader.exec() + + del reader + + @QtCore.pyqtSlot(name='on_actionPrint_triggered') + def print(self): + QtPrintSupport.QPrintDialog().exec() + + @QtCore.pyqtSlot(name='on_actionExportData_triggered') + @QtCore.pyqtSlot(name='on_actionSave_triggered') + def save(self): + save_dialog = SaveDirectoryDialog( + directory=str(self.path), parent=self, + ) + + mode = save_dialog.exec() + if mode == QtWidgets.QDialog.Accepted: + path = save_dialog.selectedFiles() + selected_filter = save_dialog.selectedNameFilter() + + if path: + self.management.save(path[0], selected_filter) + + @QtCore.pyqtSlot() + @QtCore.pyqtSlot(list) + def save_fit_parameter(self, fit_sets: List[str] = None): + fname, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'Save fit parameter', directory=str(self.path), + filter='All files(*, *);;Text files(*.dat *.txt)') + + if fname: + self.management.save_fit_parameter(fname, fit_sets=fit_sets) + + @QtCore.pyqtSlot(name='on_actionExportGraphic_triggered') + def export_graphic(self): + self.current_graph_widget.export() + + @QtCore.pyqtSlot(name='on_actionNew_window_triggered') + def new_graph(self): + w = QGraphWindow() + self.management.graphs[w.id] = w + self.set_graph(w.id) + + if self.eval is not None: + self.eval.set_graphs(self.management.graphs.list()) + + return w.id + + @QtCore.pyqtSlot(list, str) + def show_new_data(self, sets: list, graph: str): + if len(sets) == 0: + return + + if graph == '': + graph = self.new_graph() + + self.management.plots_to_graph(sets, graph) + + for idd in sets: + new_item = self.management[idd] + self.datawidget.blockSignals(True) + self.datawidget.add_item(new_item.id, new_item.name, graph) + self.datawidget.blockSignals(False) + + if graph == self.fit_dialog.connected_figure: + self.fit_dialog.load(self.management.graphs.active(graph)) + + @QtCore.pyqtSlot(name='on_actionDelete_window_triggered') + def delete_windows(self): + self.management.delete_sets() + + @QtCore.pyqtSlot(str) + def remove_graph(self, gid: str): + print(gid, self.current_graph_widget) + self.datawidget.remove_item(gid) + w = None + for w in self.area.subWindowList(): + wdgt = w.widget() + if wdgt.id == gid: + wdgt.disconnect() + if wdgt == self.current_graph_widget: + if self.ptsselectwidget.connected_figure == gid: + self.ptsselectwidget.connected_figure = None + self.tabWidget.removeTab(self.tabWidget.indexOf(self.ptsselectwidget)) + + if self.t1tauwidget.connected_figure == gid: + self.t1tauwidget.connected_figure = None + self.tabWidget.removeTab(self.tabWidget.indexOf(self.t1tauwidget)) + + if self.fit_dialog.connected_figure == gid: + self.fit_dialog.connected_figure = None + for item in self.fit_dialog.preview_lines: + self.current_graph_widget.remove_external(item) + + if self.valuewidget.graph_shown == gid: + self.tabWidget.setCurrentIndex(0) + + self.current_graph_widget = None + self.management.current_graph = '' + self.current_plotitem = None + + break + + if w is not None: + w.close() + + if self.current_graph_widget is None: + self.area.activateNextSubWindow() + + @QtCore.pyqtSlot(str) + def set_graph(self, key: str): + w = self.management.graphs[key] + + subwindow = self.area.addSubWindow(w) + subwindow.setOption(QtWidgets.QMdiSubWindow.RubberBandMove, True) + subwindow.setOption(QtWidgets.QMdiSubWindow.RubberBandResize, True) + subwindow.setMinimumHeight(400) + subwindow.setMinimumWidth(600) + + self.datawidget.blockSignals(True) + self.datawidget.tree.blockSignals(True) + self.datawidget.add_graph(w.id, w.title) + self.datawidget.tree.blockSignals(False) + self.datawidget.blockSignals(False) + + w.mousePositionChanged.connect(self.mousemoved) + w.aboutToClose.connect(self.delete_windows) + w.positionClicked.connect(self.point_selected) + w.show() + + graph_list = self.management.graphs.list() + self.t1tauwidget.set_graphs(graph_list) + self.ptsselectwidget.set_graphs(graph_list) + + @QtCore.pyqtSlot(QtWidgets.QMdiSubWindow, name='on_area_subWindowActivated') + def change_window(self, wd): + """ Called every time focus moves from or to a subwindow. Returns None if current focus is not on a subwindow""" + if wd is not None: + if self.current_graph_widget is not None: + self.current_graph_widget.closable = True + + if self.ptsselectwidget.isVisible(): + self._select_ptswidget(False, False, False) + + if self.fit_dialog.isVisible(): + self._select_fitwidget(False, False) + + self.current_graph_widget = wd.widget() + self.management.current_graph = wd.widget().id + self.current_plotitem = self.current_graph_widget.graphic + + pick = False + block = False + if self.ptsselectwidget.isVisible(): + pick, block = self._select_ptswidget(True, pick, block) + if self.fit_dialog.isVisible(): + block = self._select_fitwidget(True, block) + + self._set_pick_block(pick, block) + + self.datawidget.tree.blockSignals(True) + self.datawidget.tree.highlight(self.management.current_graph) + self.datawidget.tree.blockSignals(False) + + @QtCore.pyqtSlot(name='on_actionCascade_windows_triggered') + @QtCore.pyqtSlot(name='on_actionTile_triggered') + def change_window_size(self): + if self.sender() == self.actionCascade_windows: + self.area.cascadeSubWindows() + elif self.sender() == self.actionTile: + self.area.tileSubWindows() + + @QtCore.pyqtSlot(name='on_actionChange_datatypes_triggered') + def type_change_dialog(self): + from ..data.conversion import ConversionDialog + + dialog = ConversionDialog(self) + dialog.set_graphs(self.management.graphs.tree()) + dialog.convertSets.connect(self.management.convert_sets) + + _ = dialog.exec() + + dialog.disconnect() + + def _set_pick_block(self, pick: bool, block: bool): + self.current_graph_widget.enable_picking(pick) + self.current_graph_widget.closable = not block + + @QtCore.pyqtSlot(int, name='on_tabWidget_currentChanged') + def toggle_tabs(self, idx: int): + widget = self.tabWidget.widget(idx) + if self.current_graph_widget is None: + if self.tabWidget.currentIndex() > 1: + self.tabWidget.removeTab(self.tabWidget.indexOf(widget)) + self.tabWidget.setCurrentIndex(0) + return + + if self.current_graph_widget is not None: + self.current_graph_widget.enable_picking(False) + + pick_required, block_window = self._select_ptswidget(widget == self.ptsselectwidget, False, False) + self._select_valuewidget(widget == self.valuewidget) + pick_required, block_window = self._select_t1tauwidget(widget == self.t1tauwidget, pick_required, block_window) + block_window = self._select_fitwidget(widget == self.fit_dialog, block_window) + + self._set_pick_block(pick_required, block_window) + + def _select_ptswidget(self, onoff: bool, pick_required: bool, block_window: bool) -> Tuple[bool, bool]: + if self.current_graph_widget is None: + return pick_required, block_window + + if onoff: # point selection + for line in self.ptsselectwidget.pts_lines: + self.current_graph_widget.add_external(line) + self.ptsselectwidget.point_removed.connect(self.current_graph_widget.remove_external) + self.ptsselectwidget.connected_figure = self.management.current_graph + pick_required = True + else: + if self.ptsselectwidget.connected_figure: + g = self.management.graphs[self.ptsselectwidget.connected_figure] + for line in self.ptsselectwidget.pts_lines: + g.remove_external(line) + # self.ptsselectwidget.clear() + + return pick_required, block_window + + @QtCore.pyqtSlot(int, name='on_tabWidget_tabCloseRequested') + def close_tab(self, idx: int): + if idx == 0: + pass + else: + self.tabWidget.setCurrentIndex(0) + self.tabWidget.removeTab(idx) + + def _show_tab(self, mode: str): + widget, name = { + 't1_temp': (self.t1tauwidget, 'T1 mininmon'), + 'signal': (self.editsignalwidget, 'Signals'), + 'pick': (self.ptsselectwidget, 'Pick points'), + 'fit': (self.fit_dialog, 'Fit') + }[mode] + + for idx in range(self.tabWidget.count()): + if self.tabWidget.widget(idx) == widget: + self.tabWidget.setCurrentIndex(idx) + return + + self.tabWidget.addTab(widget, name) + self.tabWidget.setCurrentIndex(self.tabWidget.count()-1) + + def _select_valuewidget(self, onoff: bool): + if onoff: # Values + self.valuewidget(self.management.graphs.tree()) + self.valuewidget.connected_figure = self.management.current_graph + if self.valuewidget.graph_shown is not None: + self.management.graphs[self.valuewidget.graph_shown].add_external(self._values_plot) + else: + if self.valuewidget.graph_shown is not None: + self.management.graphs[self.valuewidget.graph_shown].remove_external(self._values_plot) + + def _select_integralwidget(self, onoff: bool, pick_required: bool): + if self.current_graph_widget is None: + return pick_required + + if onoff: + self.integralwidget(self.current_graph_widget.title, + self.management.graphs.current_sets(self.management.current_graph)) + self.integralwidget.item_deleted.connect(self.current_graph_widget.remove_external) + self.integralwidget.connected_figure = self.management.current_graph + pick_required = True + else: + if self.integralwidget.connected_figure: + g = self.management.graphs[self.integralwidget.connected_figure] + for line in self.integralwidget.lines: + g.remove_external(line[0]) + g.remove_external(line[1]) + self.integralwidget.clear() + + return pick_required + + def _select_t1tauwidget(self, onoff: bool, pick_required: bool, block_window: bool): + if onoff: # tau from t1 + if self.current_graph_widget is None: + return + + idx = self.tabWidget.indexOf(self.t1tauwidget) + if len(self.current_graph_widget) != 1: + QtWidgets.QMessageBox.information(self, 'Too many datasets', + 'Only one T1 curve can be evaluated at once') + self.tabWidget.removeTab(idx) + self.tabWidget.setCurrentIndex(0) + return + + self.tabWidget.setTabText(idx, 'T1 min (%s)' % {self.current_graph_widget.title}) + + self.t1tauwidget.set_graphs(self.management.graphs.list()) + self.t1tauwidget.set_data(*self.management.get_data(self.current_graph_widget.active[0], xy_only=True), + name=self.management[self.current_graph_widget.active[0]].name) + self.t1tauwidget.connected_figure = self.management.current_graph + self.current_graph_widget.add_external(self.t1tauwidget.min_pos) + self.current_graph_widget.add_external(self.t1tauwidget.parabola) + pick_required = True + block_window = True + else: + if self.t1tauwidget.connected_figure: + g = self.management.graphs[self.t1tauwidget.connected_figure] + g.remove_external(self.t1tauwidget.min_pos) + g.remove_external(self.t1tauwidget.parabola) + + return pick_required, block_window + + @QtCore.pyqtSlot(str) + def get_data(self, key: str): + self.sender().set_data(self.management[key]) + + @QtCore.pyqtSlot(name='on_actionCalculateT1_triggered') + def show_t1calc_dialog(self): + dialog = QRelaxCalc(self) + dialog.set_graphs(self.management.graphs.tree(key_only=True)) + dialog.newData.connect(self.management.calc_relaxation) + dialog.show() + + @QtCore.pyqtSlot(name='on_actionSkip_points_triggered') + def skip_pts_dialog(self): + from ..math.skipping import QSkipDialog + + dial = QSkipDialog(self) + dial.exec() + + self.management.skip_points(**dial.get_arguments()) + + @QtCore.pyqtSlot(str, name='on_action_coup_calc_triggered') + def coupling_dialog(self): + dialog = QCoupCalcDialog(self) + dialog.show() + + @QtCore.pyqtSlot(name='on_action_mean_t1_triggered') + def mean_dialog(self): + gnames = self.management.graphs.tree(key_only=True) + dialog = QMeanTimes(gnames, parent=self) + dialog.newValues.connect(self.management.calc_mean) + dialog.show() + + @QtCore.pyqtSlot(name='on_actionRunning_values_triggered') + def smooth_dialog(self): + dialog = QSmooth(parent=self) + dialog.newValues.connect(self.management.smooth_data) + dialog.show() + + @QtCore.pyqtSlot(name='on_actionInterpolation_triggered') + def interpol_dialog(self): + if self.current_graph_widget is None: + return + + gnames = self.management.graphs.tree() + dialog = InterpolDialog(parent=self) + dialog.set_data(gnames, self.current_graph_widget.id) + dialog.new_data.connect(self.management.interpolate_data) + dialog.show() + + @QtCore.pyqtSlot(name='on_action_calc_triggered') + def open_eval_dialog(self): + if self.eval is None: + self.eval = QEvalDialog(parent=self) + self.eval.do_eval.connect(self.management.eval_expression) + self.eval.do_calc.connect(self.management.create_from_function) + + self.eval.set_mode('e') + self.eval.set_namespace(self.management.get_namespace()) + self.eval.add_data(self.management.active_sets) + self.eval.set_graphs(self.management.graphs.list()) + + self.eval.exec() + + @QtCore.pyqtSlot(name='on_actionAddlines_triggered') + def make_data_from_function(self): + if self.eval is None: + self.eval = QEvalDialog(parent=self) + self.eval.do_eval.connect(self.management.eval_expression) + self.eval.do_calc.connect(self.management.create_from_function) + + self.eval.set_mode('c') + self.eval.set_namespace(self.management.get_namespace()) + self.eval.set_graphs(self.management.graphs.list()) + + self.eval.exec() + + @QtCore.pyqtSlot(name='on_actionDerivation_triggered') + @QtCore.pyqtSlot(name='on_actionIntegration_triggered') + @QtCore.pyqtSlot(name='on_actionFilon_triggered') + def int_diff_ft(self): + sets = self.management.active_sets + mode = {self.actionIntegration: 'int', + self.actionDerivation: 'diff', + self.actionFilon: 'logft'}[self.sender()] + + if sets: + from ..math.integrate_derive import QDeriveIntegrate + + dialog = QDeriveIntegrate(mode) + dialog.add_graphs(self.management.graphs.list()) + dialog.set_sets(sets) + + res = dialog.exec() + + if res: + options = dialog.get_options() + mode = options['mode'] + if mode in ['i', 'd']: + self.management.integrate(**options) + elif mode == 'l': + self.management.logft(**options) + else: + raise ValueError('Unknown mode %s, not `i`, `d`, `l`.' % str(mode)) + + @QtCore.pyqtSlot(str) + def update_data(self, sid: str): + if self.valuewidget.shown_set == sid: + self.show_data_values(sid) + + self.datawidget.set_name(sid, self.management[sid].name) + + @QtCore.pyqtSlot(str) + def delete_data(self, sid): + print('remove', sid) + if self.valuewidget.shown_set == sid: + self.tabWidget.setCurrentIndex(0) + + self.datawidget.remove_item(sid) + + @QtCore.pyqtSlot(name='on_actionBaseline_triggered') + def baseline_dialog(self): + if not self.current_graph_widget: + return + + if len(self.current_graph_widget) != 1: + QtWidgets.QMessageBox.information(self, 'Invalid number of sets', + 'Baseline correction can only applied to one set at a time.') + return + + for sid in self.current_graph_widget.active: + data_mode = self.management[sid].mode + if data_mode in ['spectrum']: + editor = QBaselineDialog(self) + editor.add_data(*self.management.get_data(sid, xy_only=True)) + editor.finished.connect(self.management.apply) + editor.exec() + + @QtCore.pyqtSlot(str) + def do_preview(self, mode): + if mode == 'ap': + dialog = QApodDialog(parent=self) + elif mode == 'ph': + dialog = QPhasedialog(parent=self) + else: + raise ValueError('Unknown preview mode %s' % str(mode)) + + for sid in self.current_graph_widget.active: + data_mode = self.management[sid].mode + tobeadded = False + if (data_mode == 'fid') or (data_mode == 'spectrum' and mode == 'ph'): + tobeadded = True + + if tobeadded: + dialog.add_data(*self.management.get_data(sid, xy_only=True)) + + if dialog.exec() == QtWidgets.QDialog.Accepted: + self.management.apply(mode, dialog.get_value()) + + @QtCore.pyqtSlot(name='on_actionMove_between_plots_triggered') + def move_sets_dialog(self): + gnames = self.management.graphs.tree() + self.movedialog.setup(gnames) + self.movedialog.exec() + + @QtCore.pyqtSlot(list, str, str) + def move_sets(self, sets, dest, src): + self.management.move_sets(sets, dest, src) + for s in sets: + self.datawidget.tree.move_sets(s, dest, src) + + @QtCore.pyqtSlot(str) + def show_data_values(self, sid: str): + if sid == '': + return + + data, mask = self.management.get_data(sid) + self.valuewidget.set_data(data, mask) + + def plot_selected_values(self, gid: str, x: list, y: list): + self._values_plot.setData(x=x, y=y) + if gid != self.valuewidget.connected_figure: + self.management.graphs[self.valuewidget.connected_figure].remove_external(self._values_plot) + self.management.graphs[gid].add_external(self._values_plot) + self.valuewidget.connected_figure = gid + + @QtCore.pyqtSlot(object, str) + def item_to_graph(self, item, graph_id): + self.management.graphs[graph_id].add_external(item) + + @QtCore.pyqtSlot(object, str) + def item_from_graph(self, item, graph_id): + self.management.graphs[graph_id].remove_external(item) + + def closeEvent(self, evt): + # self._write_settings() + self.close() + + @QtCore.pyqtSlot(int) + def request_data(self, idx): + idd = self.datawidget.get_indexes(idx=idx-1) + try: + x = self.management[idd].x + y = self.management[idd].y + ret_val = (x, y) + except KeyError: + ret_val = None + + self.sender().receive_data(ret_val) + + return ret_val + + @QtCore.pyqtSlot(tuple, bool) + def point_selected(self, pos, double): + w = self.tabWidget.currentWidget() + if w == self.ptsselectwidget: + line = self.ptsselectwidget.add(pos, double) + self.current_graph_widget.add_external(line) + + elif w == self.t1tauwidget: + self.t1tauwidget.t1min_picked(pos) + + def _select_fitwidget(self, onoff: bool, block_window: bool): + if self.current_graph_widget is not None: + print('select', self.current_graph_widget.id) + if onoff: + if self.management.active_sets: + self.fit_dialog.connected_figure = self.management.current_graph + self.fit_dialog.load(self.management.active_sets) + for item in self.fit_dialog.preview_lines: + self.current_graph_widget.add_external(item) + if self.action_custom_range.isChecked(): + self.current_graph_widget.add_external(self.fitregion) + + block_window = True + else: + for item in self.fit_dialog.preview_lines: + self.current_graph_widget.remove_external(item) + self.current_graph_widget.remove_external(self.fitregion) + + return block_window + + @QtCore.pyqtSlot(QtWidgets.QAction) + def change_fit_limits(self, action: QtWidgets.QAction): + if action == self.action_custom_range and self.fit_dialog.isVisible(): + self.current_graph_widget.add_external(self.fitregion) + else: + self.current_graph_widget.remove_external(self.fitregion) + + def start_fit(self, parameter, links, fit_options): + fit_options['limits'] = { + self.action_no_range: 'none', + self.action_x_range: 'x', + self.action_custom_range: self.fitregion.getRegion() + }[self.ac_group2.checkedAction()] + + fit_options['fit_mode'] = { + self.action_lm_fit: 'lsq', + self.action_nm_fit: 'nm', + self.action_odr_fit: 'odr' + }[self.ac_group.checkedAction()] + + self.fit_dialog.fit_button.setEnabled(False) + self.management.start_fit(parameter, links, fit_options) + + @QtCore.pyqtSlot(dict, int, bool) + def show_fit_preview(self, funcs: dict, num: int, show: bool): + if self.fit_dialog.connected_figure is None: + return + + g = self.management.graphs[self.fit_dialog.connected_figure] + for item in self.fit_dialog.preview_lines: + g.remove_external(item) + + if show: + x_lim, _ = g.ranges + space = geomspace if g.log[0] else linspace + x = space(1.01*x_lim[0], 0.99*x_lim[1], num=num) + + self.fit_dialog.make_previews(x, funcs) + + for item in self.fit_dialog.preview_lines: + g.add_external(item) + + self.raise_() + + @QtCore.pyqtSlot(list) + def show_fit_results(self, results: list): + self.fit_dialog.fit_button.setEnabled(True) + if results: + res_dialog = QFitResult(results, self.management, parent=self) + res_dialog.add_graphs(self.management.graphs.list()) + res_dialog.closed.connect(self.management.make_fits) + res_dialog.redoFit.connect(self.management.redo_fits) + res_dialog.show() + + @QtCore.pyqtSlot(name='on_actionFunction_editor_triggered') + def edit_models(self): + if self.editor is None: + from ..lib.usermodeleditor import QUsermodelEditor + + self.editor = QUsermodelEditor(config_paths() / 'usermodels.py', parent=self) + self.editor.modelsChanged.connect(self.update_fitmodels) + self.editor.setWindowModality(QtCore.Qt.ApplicationModal) + self.editor.show() + + @QtCore.pyqtSlot(name='on_actionShift_triggered') + def shift_dialog(self): + s = QShift(self) + s.set_graphs(self.management.graphs.list()) + for key, name in self.management.active_sets: + data = self.management.data[key] + s.add_item(key, name, data.x, data.y) + s.valuesChanged.connect(self.management.shift_scale) + s.show() + + def update_fitmodels(self): + pass + + @staticmethod + @QtCore.pyqtSlot(name='on_actionDocumentation_triggered') + def open_doc(): + docpath = '/autohome/dominik/auswerteprogramm3/doc/_build/html/index.html' + import webbrowser + webbrowser.open(docpath) + + def dropEvent(self, evt): + if evt.mimeData().hasUrls(): + files = [str(url.toLocalFile()) for url in evt.mimeData().urls()] + self.management.load_files(files) + + def dragEnterEvent(self, evt): + evt.accept() + + @QtCore.pyqtSlot(bool, name='on_actionMouse_behaviour_toggled') + def change_mouse_mode(self, is_checked): + if is_checked: + self.current_plotitem.plotItem.vb.setMouseMode(ViewBox.RectMode) + else: + self.current_plotitem.plotItem.vb.setMouseMode(ViewBox.PanMode) + + def mousemoved(self, xpos, ypos): + self.mousepos.setText('x={:.3g}; y={:.3g}'.format(xpos, ypos)) + + @QtCore.pyqtSlot(name='on_actionSnake_triggered') + @QtCore.pyqtSlot(name='on_actionTetris_triggered') + @QtCore.pyqtSlot(name='on_actionLife_triggered') + def spannung_spiel_und_spass(self): + + if self.sender() == self.actionLife: + from ..lib.gol import QGameOfLife + game = QGameOfLife(parent=self) + game.setWindowModality(QtCore.Qt.NonModal) + game.show() + + else: + from ..lib.stuff import Game + if self.sender() == self.actionSnake: + gtype = 'snake' + else: + gtype = 'tetris' + + game = Game(gtype, parent=self) + game.show() + + @QtCore.pyqtSlot(name='on_actionConfiguration_triggered') + def open_configuration(self): + from ..lib.configurations import GeneralConfiguration + dialog = GeneralConfiguration(self) + dialog.show() + + def close(self): + write_state({'recent_path': str(self.path)}) + + super().close() + + def read_state(self): + opts = read_state() + self.path = pathlib.Path(opts.get('recent_path', Path.home())) diff --git a/nmreval/gui_qt/main/management.py b/nmreval/gui_qt/main/management.py new file mode 100644 index 0000000..5968933 --- /dev/null +++ b/nmreval/gui_qt/main/management.py @@ -0,0 +1,1074 @@ +import pathlib +import re +import uuid +from typing import List + +from ...fit import data as fit_d +from ...fit.model import Model +from ...fit.result import FitResult +from ...fit.minimizer import FitRoutine +from ...math.interpol import interpolate +from ...math.logfourier import logft +from ...math.smooth import smooth +from ...nmr.relaxation import Relaxation + +from ..lib.undos import * +from ..data.container import * +from ..io.filereaders import QFileReader +from ..lib.utils import busy_cursor + + +class GraphSignals(QtCore.QObject): + valueChanged = QtCore.pyqtSignal() + + +class GraphDict(OrderedDict): + def __init__(self, data): + super().__init__() + + self._data = data + self.signals = GraphSignals() + self.valueChanged = self.signals.valueChanged + + def __setitem__(self, key, value): + super().__setitem__(key, value) + self.valueChanged.emit() + + def __delitem__(self, key): + super().__delitem__(key) + self.valueChanged.emit() + + def tree(self, key_only=False): + ret_val = OrderedDict() + for k, g in self.items(): + if key_only: + ret_val[k] = (g.title, [(s, self._data[s].name) for s in g.sets]) + else: + ret_val[(k, g.title)] = [(s, self._data[s].name) for s in g.sets] + + return ret_val + + def list(self): + return [(k, v.title) for k, v in self.items()] + + def active(self, key: str): + if key: + return [(self._data[i].id, self._data[i].name) for i in self[key]] + else: + return [] + + def current_sets(self, key: str): + if key: + return [(self._data[i].id, self._data[i].name) for i in self[key].sets] + else: + return [] + + +class UpperManagement(QtCore.QObject): + newGraph = QtCore.pyqtSignal() + restoreGraph = QtCore.pyqtSignal(str) + deleteGraph = QtCore.pyqtSignal(str) + newData = QtCore.pyqtSignal(list, str) + deleteData = QtCore.pyqtSignal(str) + dataChanged = QtCore.pyqtSignal(str) + fitFinished = QtCore.pyqtSignal(list) + stopFit = QtCore.pyqtSignal() + properties_collected = QtCore.pyqtSignal(dict) + unset_state = QtCore.pyqtSignal(list) + + + _colors = cycle(Colors) + + _actions = { + 'ls': (ShiftCommand, 'Left shift'), + 'cut': (CutCommand, 'Cut'), + 'ap': (ApodizationCommand, 'Apodization'), + 'zf': (ZerofillCommand, 'Zerofill'), + 'ph': (PhaseCommand, 'Phase'), + 'bl': (BaselineCommand, 'Baseline'), + 'bls': (BaselineSplineCommand, 'Baseline'), + 'ft': (FourierCommand, 'Fourier'), + 'ft_pake': 'FT (de-paked)', + 'sort': (SortCommand, 'Sort'), + 'norm': (NormCommand, 'Normalize'), + 'center': (CenterCommand, 'Center on max') + } + + def __init__(self, window): + super().__init__() + + self._fit_active = False + self.fit_thread = None + self.fit_worker = None + + self.counter = 0 + self.data = OrderedDict() + self.window = window + self.current_graph = '' + self.graphs = GraphDict(self.data) + self.namespace = None + self.undostack = QtWidgets.QUndoStack() + self.deleteData.connect(self.plot_from_graph) + + def __setitem__(self, key: str, value, **kwargs): + if isinstance(value, ExperimentContainer): + item = value + item.id = key + elif isinstance(value, FitResult): + item = FitContainer(key, value, manager=self, **kwargs) + elif isinstance(value, Signal): + item = SignalContainer(key, value, manager=self, **kwargs) + else: + item = PointContainer(key, value, manager=self, **kwargs) + + item.dataChanged.connect(lambda x: self.dataChanged.emit(x)) + + self.data[key] = item + + def __getitem__(self, item): + return self.data[item] + + def __contains__(self, item): + return item in self.data + + def __iter__(self): + for k, v in self.data.items(): + yield k, v + + @property + def active_sets(self): + return self.graphs.active(self.current_graph) + + def add(self, data, **kwargs): + _id = str(uuid.uuid4()) + self.__setitem__(_id, data, **kwargs) + + return _id + + def load_files(self, fname: List[str], new_plot: str = None): + ret_dic = QFileReader(manager=self).readfiles(fname) + self.add_new_data(ret_dic, new_plot) + + def _load_session(self, sets: dict, graphs: dict): + sid = self._load_sets(sets) + + for g in graphs: + _ = g.pop('id') + graph = QGraphWindow.set_state(g) + self.graphs[graph.id] = graph + self.restoreGraph.emit(graph.id) + + children = [sid[c] for c in g['children']] + active = [sid[c] for c in g['active']] + inactive = [k for k in children if k not in active] + + self.newData.emit(children, graph.id) + + graph.active = active + graph.listWidget.blockSignals(True) + for i, l in enumerate(g['in_legend']): + graph.listWidget.item(i).setCheckState(l) + graph.listWidget.blockSignals(False) + + # set unchecked in tree and hide/show in plot + self.unset_state.emit(inactive) + self.change_visibility(active, inactive) + + def _load_sets(self, sets: dict) -> dict: + sid = {} + for _id, (data, opts) in sets.items(): + if isinstance(data, FitResult): + # for fits, _id belongs to the fitted data, not the fit + src_id = data.idx + if src_id in sid: + new_id = self.add(data, src=sid[src_id]) + self.data[sid[src_id]]._fits.append(new_id) + else: + new_id = self.add(data) + else: + new_id = self.add(data) + + sid[_id] = new_id + + for m in ['real', 'imag']: + if m in opts: + self.data[new_id].setSymbol(**opts[m][0], mode=m) + self.data[new_id].setLine(**opts[m][1], mode=m) + + return sid + + def add_new_data(self, data: list, gid: str): + sid = [] + for d in data: + if isinstance(d, tuple): + if len(d) == 2: + self._load_session(d[0], graphs=d[1]) + else: + sid.extend(list(self._load_sets(d[0]).values())) + else: + sid.append(self.add(d)) + + if sid: + gid = '' if not gid else gid + + self.newData.emit(sid, gid) + + def plots_to_graph(self, plotkeys: list, gid: str): + self.graphs[gid].add(plotkeys, [self.data[k].plots for k in plotkeys]) + for k in plotkeys: + self.data[k].graph = gid + + @QtCore.pyqtSlot(str) + def plot_from_graph(self, key: str): + self.graphs[self.data[key].graph].remove(key) + + @QtCore.pyqtSlot(list, str, str) + def move_sets(self, sets: list, dest: str, src, pos: int = -1): + if isinstance(src, str): + src = [src]*len(sets) + + for graph_id, set_id in zip(src, sets): + # move all plots to the same graph + if graph_id != dest: + self.graphs[graph_id].remove(set_id) + self.plots_to_graph([set_id], dest) + + # move to correct position + self.graphs[dest].move_sets(sets, pos) + + @QtCore.pyqtSlot() + @QtCore.pyqtSlot(list, str) + def copy_sets(self, sets: list = None, src: str = None): + if sets is None: + sets = self.graphs[self.current_graph].active[:] + + if src is None: + src = self.current_graph + + new_ids = [] + for s in sets: + copy_of_s = self.data[s].copy(full=True) + copy_of_s.id = str(uuid.uuid4()) + new_ids.append(copy_of_s.id) + self.data[copy_of_s.id] = copy_of_s + + self.newData.emit(new_ids, src) + + return new_ids + + @QtCore.pyqtSlot(list) + @QtCore.pyqtSlot(str) + def delete_sets(self, rm_sets: list = None): + rm_graphs = [] + print(rm_sets) + + if rm_sets is None: + rm_sets = self.graphs[self.current_graph].sets + [self.current_graph] + + self.undostack.beginMacro('Delete') + + for k in rm_sets[::-1]: + if k in self.data: + cmd = DeleteCommand(self.data, k, self.newData, self.deleteData) + self.undostack.push(cmd) + else: + rm_graphs.append(k) + + for k in rm_graphs: + cmd = DeleteGraphCommand(self.graphs, k, self.restoreGraph, self.deleteGraph) + self.undostack.push(cmd) + + self.undostack.endMacro() + + @QtCore.pyqtSlot() + def cat(self, src_sets=None): + joined = None + group_set = set() + name_set = set() + value_set = set() + + if src_sets is None: + src_sets = self.graphs[self.current_graph].active + for sid in src_sets: + data_i = self.data[sid] + if joined is None: + joined = data_i.copy() + else: + joined.append(data_i.x, data_i.y, data_i.y_err) + + name_set.add(data_i.name) + group_set.add(data_i.group) + value_set.add(data_i.value) + + if joined is not None: + joined.group = '/'.join(group_set) + joined.name = '/'.join(name_set) + + if len(value_set) == 1: + joined.value = value_set.pop() + else: + joined.value = 0.0 + + self.newData.emit([self.add(joined)], self.current_graph) + + def get_data(self, sid: str, xy_only=False): + """ + Return data for a given id. + Return value is tuple of [x, y, y_err] and mask if xy_only is False, [x, y] if true. + """ + d = self.data[sid] + if xy_only: + return [d.x, d.y] + + return [d.data.x, d.data.y, d.data.y_err], d.data.mask.data + + def change_visibility(self, selected: list, deselected: list): + """Change status of list of ids after status change in datawidget""" + + for s in selected: + self.graphs[self.data[s].graph].show_item([s]) + + for d in deselected: + self.graphs[self.data[d].graph].hide_item([d]) + + @QtCore.pyqtSlot(str, str) + def change_keys(self, identifier: str, name: str): + if identifier in self.data: + d = self.data[identifier] + d.name = name + self.graphs[d.graph].update_legend(identifier, name) + elif identifier in self.graphs: + self.graphs[identifier].title = name + else: + raise KeyError('Unknown ID ' + str(identifier)) + + @QtCore.pyqtSlot(str, tuple) + def apply(self, func: str, arguments: tuple): + # undos, names displayed by undo action + cmd, cmd_text = self._actions[func] + + self.undostack.beginMacro(cmd_text) + for sid in self.graphs[self.current_graph]: + single_undo = cmd(self.data[sid], *arguments) + self.undostack.push(single_undo) + self.undostack.endMacro() + + def cut(self): + xlim, _ = self.graphs[self.current_graph].ranges + self.apply('cut', xlim) + + @QtCore.pyqtSlot() + def unmask(self): + for d in self.data.values(): + d.mask = np.ones_like(d.mask, dtype=bool) + + def start_fit(self, parameter: dict, links: list, fit_options: dict): + if self._fit_active: + return + + self.__fit_options = (parameter, links, fit_options) + + fitter = FitRoutine() + models = {} + fit_limits = fit_options['limits'] + fit_mode = fit_options['fit_mode'] + we = fit_options['we'] + + for model_id, model_p in parameter.items(): + m = Model(model_p['func']) + models[model_id] = m + + m_complex = model_p['complex'] + m.set_complex(m_complex) + + for set_id, set_params in model_p['parameter'].items(): + data_i = self.data[set_id] + if we == 'Deltay': + we = data_i.y_err**2 + + if m_complex is None or m_complex == 'real': + _y = data_i.y.real + elif m_complex == 'imag' and np.iscomplexobj(self.data[set_id].y): + _y = data_i.y.imag + else: + _y = data_i.y + + _x = data_i.x + + if fit_limits == 'none': + inside = slice(None) + elif fit_limits == 'x': + x_lim, _ = self.graphs[self.current_graph].ranges + inside = np.where((_x >= x_lim[0]) & (_x <= x_lim[1])) + else: + inside = np.where((_x >= fit_limits[0]) & (_x <= fit_limits[1])) + + if isinstance(we, str): + d = fit_d.Data(_x[inside], _y[inside], we=we, idx=set_id) + else: + d = fit_d.Data(_x[inside], _y[inside], we=we[inside], idx=set_id) + + d.set_model(m) + d.set_parameter(set_params[0], var=model_p['var'], + lb=model_p['lb'], ub=model_p['ub'], + fun_kwargs=set_params[1]) + + fitter.add_data(d) + + model_globs = model_p['glob'] + if model_globs: + m.set_global_parameter(**model_p['glob']) + + for links_i in links: + fitter.set_link_parameter((models[links_i[0]], links_i[1]), + (models[links_i[2]], links_i[3])) + + with busy_cursor(): + self.fit_worker = FitWorker(fitter, fit_mode) + self.fit_thread = QtCore.QThread() + self.fit_worker.moveToThread(self.fit_thread) + + self.fit_thread.started.connect(self.fit_worker.run) + self.fit_worker.finished.connect(self.end_fit) + self.fit_worker.finished.connect(self.fit_thread.quit) + self.fit_worker.finished.connect(self.fit_worker.deleteLater) + self.fit_thread.finished.connect(self.fit_thread.deleteLater) + + self.stopFit.connect(lambda: self.fit_worker.fitter.abort()) + + self.fit_thread.start() + + @QtCore.pyqtSlot(list, bool) + def end_fit(self, result: list, success: bool): + print('FIT FINISHED') + if success: + self.fitFinished.emit(result) + else: + QtWidgets.QMessageBox.warning(QtWidgets.QWidget(), 'Fit failed', + 'Fit kaput with exception: \n' + "\n".join(result[0])) + self.fitFinished.emit([]) + self._fit_active = False + + @QtCore.pyqtSlot(dict) + def redo_fits(self, res: dict): + models = self.__fit_options[0] + for single_model, model_args in models.items(): + parameter = model_args['parameter'] + + for set_id, set_parameter in parameter.items(): + new_values = [v.value for v in res[set_id].parameter.values()] + parameter[set_id] = (new_values, set_parameter[1]) + self.start_fit(*self.__fit_options) + + @QtCore.pyqtSlot(dict, list) + def make_fits(self, res: dict, opts: list): + f_id_list = [] + gid = '' + + subplots = opts.pop(-1) + param_graph = opts.pop(-1) + tobedeleted = [] + for i, (k, fit) in enumerate(res.items()): + reject, delete_prev = opts[i] + if reject: + continue + + data_k = self.data[k] + if delete_prev: + tobedeleted.extend([f.id for f in data_k.get_fits()]) + data_k.set_fits([]) + + syms = data_k.plot_real.symbol + if syms == SymbolStyle.No: + color = data_k.plot_real.linecolor + else: + color = data_k.plot_real.symbolcolor + + fit.value = data_k.value + fit.group = data_k.group + + f_id = self.add(fit, color=color, src=k) + + if subplots: + print('subplots') + + f_id_list.append(f_id) + data_k.set_fits(f_id) + gid = data_k.graph + + self.delete_sets(tobedeleted) + + if f_id_list: + self.newData.emit(f_id_list, gid) + self.make_fit_parameter(f_id_list, graph_id=param_graph) + + def make_fit_parameter(self, fit_sets: List[str], graph_id: str = None): + fit_dict = self._collect_fit_parameter(fit_sets) + + if fit_dict: + p_id_list = [] + for v in fit_dict.values(): + xy = np.array(v[0]).T + p_id_list.append(self.add(Points(x=xy[0], y=xy[1], y_err=xy[2], name=v[1]))) + + if not graph_id: + graph_id = '' + + self.newData.emit(p_id_list, graph_id) + + def save_fit_parameter(self, fname: str, fit_sets: List[str] = None): + if fit_sets is None: + fit_sets = [s for (s, _) in self.active_sets] + + for set_id in fit_sets: + data = self.data[set_id] + if data.mode != 'fit': + continue + + data.data.save_parameter(fname) + + def _collect_fit_parameter(self, fit_sets: List[str]) -> dict: + fit_dict = {} + + for set_id in fit_sets: + data = self.data[set_id] + if data.mode != 'fit': + continue + + for key, pvalue in data.parameter.items(): + name = pvalue.full_name + fit_key = key + data.model_name + + if fit_key not in fit_dict: + fit_dict[fit_key] = [[], name] + + err = 0 if pvalue.error is None else pvalue.error + + fit_dict[fit_key][0].append([data.value, pvalue.value, err]) + + return fit_dict + + @QtCore.pyqtSlot(dict, str) + def extract_points(self, params: dict, gid: str): + xy_mode = params.pop('xy') + _active = self.graphs[self.current_graph].active + + new_datasets = {} + for sid in _active: + data_i = self.data[sid] + if data_i.group not in new_datasets: + new_datasets[data_i.group] = [], [] + new_x_axis, _temp = new_datasets[data_i.group] + + new_x_axis.append(data_i.value) + _temp.append(data_i.points(params)) + + key_list = [] + for label, (new_x_axis, _temp) in new_datasets.items(): + _temp = np.array(_temp) # (number of sets, number of picks, (x, y, y_err)) + num_pts = _temp.shape[1] + + for i in range(num_pts): + if xy_mode[0]: + key = self.add(Points(x=new_x_axis, y=_temp[:, i, 0], name=label)) + key_list.append(key) + + if xy_mode[1]: + key = self.add(Points(x=new_x_axis, y=_temp[:, i, 1], y_err=_temp[:, i, 2], name=label)) + key_list.append(key) + + self.newData.emit(key_list, gid) + + @QtCore.pyqtSlot(list) + def get_properties(self, sid: list) -> dict: + props = {} + for key in sid: + if key not in self.data: + continue + + props = self.data[key].get_properties() + + self.properties_collected.emit(props) + + return props + + @QtCore.pyqtSlot(list, str, str, object) + def update_property(self, sid: list, key1: str, key2: str, value: Any): + for s in sid: + self.data[s].update_property(key1, key2, value) + + def create_empty(self): + import numpy.random as random + dat = Points(x=np.arange(10), y=np.arange(10) + random.rand(10)-0.5, y_err=random.rand(10), + name='Das Sein und das Nichts') + idd = self.add(dat) + self.newData.emit([idd], self.current_graph) + + @QtCore.pyqtSlot(tuple, dict, str) + def calc_mean(self, dist_params, conversion, graph): + dist, args = dist_params + parameter = [] + + x = None + name = 'tau (%s)' % {conversion["to_"]} + value = 0. + for i, p in enumerate(args): + if isinstance(p, float): + parameter.append(p) + else: + if x is None: + x = self.data[p].x + if i == 0: + name = self.data[p].name + value = self.data[p].value + parameter.append(self.data[p].y) + + if x is None: + x = 0 + + key = self.add(Points(x, dist.convert(*parameter, **conversion), name=name, value=value)) + self.newData.emit([key], graph) + self.sender().update_graphs(self.graphs.tree(key_only=True)) + + @QtCore.pyqtSlot(list, str, bool, bool, tuple, str) + def interpolate_data(self, data_ids, mode, xlog, ylog, new_axis, dest_graph): + if len(new_axis) == 4: + start, end, steps, loggy = new_axis + if loggy: + new_x = np.logspace(np.log10(start), np.log10(end), steps) + else: + new_x = np.linspace(start, end, steps) + else: + new_x = self.data[new_axis[0]].x + + new_key = [] + for ids in data_ids: + k = self.add(interpolate(self.data[ids], new_x, xlog=xlog, ylog=ylog, kind=mode, extrapolate=True)) + new_key.append(k) + + self.newData.emit(new_key, dest_graph) + + @QtCore.pyqtSlot(int, dict) + def smooth_data(self, npoints, param_kwargs): + _active = self.graphs[self.current_graph].active + new_data = [] + for sid in _active: + try: + key = self.add(smooth(self.data[sid], npoints, **param_kwargs)) + new_data.append(key) + except Exception as e: + QtWidgets.QMessageBox().warning(self.window, + 'Smoothing failed!', + f'Smoothing failed for {self.data[sid].name} with exception:\n{e.args}') + if new_data: + self.newData.emit(new_data, self.current_graph) + + @QtCore.pyqtSlot() + def update_color(self): + UpperManagement._colors = cycle(Colors) + for i in self.active: + self.data[i].color = next(UpperManagement._colors) + + @QtCore.pyqtSlot(dict, tuple) + def shift_scale(self, values: dict, options: tuple): + copy_data, value_plot = options + + sid_list = [] + shift_y = [] + shift_x = [] + for k, v in values.items(): + d_k = self.data[k] + + if copy_data is None: + d_k.x = d_k.x*v[1][0] + v[0][0] + d_k.y = d_k.y*v[1][1] + v[0][1] + else: + new_data = d_k.copy(full=True) + new_data.update({'shift': v[0], 'scale': v[1]}) + new_data.data.x = new_data.x*v[1][0] + v[0][0] + new_data.y = new_data.y*v[1][1] + v[0][1] + + sid = self.add(new_data) + sid_list.append(sid) + + shift_x.append(d_k.value) + shift_y.append(v[0]+v[1]) + + self.newData.emit(sid_list, copy_data) + + if value_plot is not None: + sid_list = [] + shift_y = np.array(shift_y) + for i, (mode, default) in enumerate([('x shift', 0.), ('y shift', 0.), + ('x scale', 1.), ('y scale', 1.), ]): + if np.all(shift_y[:, i] == default): + continue + data = Points(shift_x, shift_y[:, i], name=mode) + sid_list.append(self.add(data)) + + self.newData.emit(sid_list, value_plot) + + @QtCore.pyqtSlot(list) + def convert_sets(self, src: list): + new_graph = {} + + error_list = [] + + for sets in src: + # merge: sets (real, imag, graph, type) + # normal: sets (source set, graph, type) + + graph_id = sets[-2] + new_type = [Points, FID, Spectrum, BDS][sets[-1]] + + if len(sets) == 4: + real_set, imag_set = sets[0], sets[1] + if real_set != '': + data = self.data[real_set] + new_data = new_type(data.x, data.y.real) + if imag_set != '': + imag_data = self.data[imag_set] + if len(imag_data) == len(data): + new_data.y.imag = imag_data.y.real + else: + error_list.append(f'Lengths mismatch of {data.name} ({len(data)}) and {imag_data.name} ({len(imag_data)})') + continue + + else: + data = self.data[imag_set] + new_data = new_type(data.x, np.zeros(data.x.size)) + new_data.y.imag = data.y.real + + else: + data = self.data[sets[0]] + if isinstance(data.data, new_type): + error_list.append(f'{data.name} is alreade of type {new_type.__name__}') + continue + + new_data = new_type(data.x, np.zeros(data.x.size)) + new_data.y.real = data.y.real + + new_data.update(data.opts) + new_id = self.add(data.change_type(new_data)) + if graph_id not in new_graph: + new_graph[graph_id] = [] + + new_graph[graph_id].append(new_id) + + for g, s in new_graph.items(): + self.newData.emit(s, g) + + if error_list: + err_string = "\n- ".join(error_list) + _ = QtWidgets.QMessageBox.information(QtWidgets.QWidget(), 'Something was skipped', + f'Some conversions were skipped:\n{err_string}') + + def get_namespace(self): + from ..lib.namespace import Namespace + self.namespace = Namespace(basic=True, const=True, fitfuncs=True) + + for i, g in enumerate(self.graphs.values()): + for j, sid in enumerate(g.sets): + sets = self.data[sid] + self.namespace.add_namespace(sets.get_namespace(i, j), parents=('Data', f'{sets.name} ({g.title})')) + + return self.namespace + + @QtCore.pyqtSlot(list, list, bool) + def eval_expression(self, cmds: list, set_ids: list, overwrite: bool): + ns = self.namespace.flatten() + + if overwrite: + self.undostack.beginMacro('Evaluate expression') + + failures = [] + for sid in set_ids: + data_i = self.data[sid] + try: + # use a copy of original namespace + new_data = data_i.eval_expression(cmds, dict(ns)) + if overwrite: + cmd = EvalCommand(self.data, sid, new_data, 'Evaluate expression') + self.undostack.push(cmd) + else: + new_id = self.copy_sets(sets=[sid]) + self.data[new_id[0]].data = new_data + except Exception as e: + failures.append((data_i, e)) + print(str(data_i) + ' failed with Exception: ' + ''.join(e.args)) + continue + + if overwrite: + self.undostack.endMacro() + + if failures: + err_msg = QtWidgets.QMessageBox(parent=self.sender()) + err_msg.setText('One or more errors occured during evaluation.') + err_msg.setDetailedText('\n'.join(f'{d.name} failed with error: {err.args}' for d, err in failures)) + err_msg.exec() + + self.sender().success = not failures + + self.sender().add_data(self.active_sets) + + @QtCore.pyqtSlot(list, dict) + def create_from_function(self, cmds: list, opts: dict): + ns = dict(self.namespace.flatten()) + + dtype = [Points, FID, Spectrum, BDS][opts.pop('dtype')] + + try: + for c in cmds: + exec(c, globals(), ns) + + name = opts.pop('name') + value = opts.pop('val') + graph = opts.pop('graph') + + data = dtype(x=ns['x'], y=ns['y'], y_err=ns['y_err'], name=name, value=value) + s_id = self.add(data, **opts) + self.sender().success = True + self.newData.emit([s_id], graph) + + except Exception as err: + print('Creation failed with error: ' + ', '.join(err.args)) + err_msg = QtWidgets.QMessageBox(parent=self.sender()) + err_msg.setText('One or more errors occured during evaluation.') + err_msg.setDetailedText('Creation failed with error: ' + ', '.join(err.args)) + err_msg.exec() + + self.sender().success = False + + def show_statistics(self, mode): + x, y, = [], [] + + for i, _ in self.active_sets: + _temp = self.data[i] + try: + x.append(float(_temp.name)) + except ValueError: + x.append(i) + y.append(_temp.statistic(mode)) + + @QtCore.pyqtSlot() + def calc_magn(self): + new_id = [] + for k, _ in self.active_sets: + dataset = self.data[k] + if isinstance(dataset, SignalContainer): + new_value = dataset.copy(full=True) + new_value.data = dataset.data.magnitude() + new_id.append(self.add(new_value)) + + self.newData.emit(new_id, '') + + @QtCore.pyqtSlot() + def center(self): + new_id = [] + for k, _ in self.active_sets: + new_value = self.data[k].copy(full=True) + new_value.x -= new_value.x[np.argmax(new_value.y.real)] + new_id.append(self.add(new_value)) + + self.newData.emit(new_id, '') + + def integrate(self, **kwargs): + new_sets = [] + log = kwargs['log'] + limits = kwargs.get('limits') + mode = kwargs['mode'] + + for set_id in kwargs['sets']: + data_i = self.data[set_id] + if mode == 'i': + new_data = data_i.data.integrate(log=log, limits=limits) + elif mode == 'd': + new_data = data_i.data.diff(log=log) + else: + raise ValueError(f'Unknown mode {mode}.') + + new_container = data_i.copy(full=True) + new_container.data = new_data + + new_sets.append(self.add(new_container)) + + self.newData.emit(new_sets, kwargs['graph']) + + def bds_deriv(self): + new_sets = [] + + for (set_id, _) in self.active_sets: + data_i = self.data[set_id] + diff = data_i.data.diff(log=True) + new_data = Points(x=diff.x, y=-np.pi/2*diff.y.real) + new_data.update(data_i.data.meta) + + new_sets.append(self.add(new_data, color=data_i.plot_imag.linecolor)) + + self.newData.emit(new_sets, '') + + def logft(self, **kwargs): + new_sets = [] + ft_mode = kwargs['ft_mode'] + + for set_id in kwargs['sets']: + data_i = self.data[set_id] + if ft_mode in ['cos', 'sin']: + new_data = Points(*logft(data_i.x, data_i.y, mode=ft_mode)) + else: + new_data = Signal(*logft(data_i.x, data_i.y, mode=ft_mode)) + + new_sets.append(self.add(new_data, color=data_i['color'], symbol=data_i['symbol'], line=data_i['line'])) + self.data[new_sets[-1]].update(data_i.data.meta) + + self.newData.emit(new_sets, kwargs['graph']) + + def skip_points(self, offset: int, step: int, invert: bool = False, copy: bool = False): + for k, _ in self.active_sets: + src = self.data[k] + if invert: + mask = np.mod(np.arange(offset, src.x.size+offset), step) != 0 + else: + mask = np.mod(np.arange(offset, src.x.size+offset), step) == 0 + + if copy: + data = src.copy() + temp = data.mask.copy() + temp[temp] = mask + + data.remove(np.where(~temp)) + data.mask = np.ones(data.x.shape) + + idd = self.add(data) + self.newData.emit([idd], self.current_graph) + else: + src.mask[src.mask] = mask + src.mask = src.mask + + @QtCore.pyqtSlot(dict) + def calc_relaxation(self, opts: dict): + params = opts['pts'] + if len(params) == 4: + if params[3]: + _x = x1 = np.geomspace(params[0], params[1], num=params[2]) + else: + _x = x1 = np.linspace(params[0], params[1], num=params[2]) + + if opts['axis1'] in ['t', 'invt1000']: + t_p = opts['t_param'] + if len(t_p) == 2: + from ...models import Arrhenius as Func + else: + from ...models import VFT as Func + + _x = Func.func(x1, *t_p, invt=opts['axis1']) + + else: + if params[1]: + x1 = self.data[params[0]].x + _x = self.data[params[0]].y.real + else: + _x = x1 = self.data[params[0]].x + + x2 = opts['val2'] + + sd = opts['spec_dens'] + sd_param = [self.data[p].y.real if isinstance(p, str) else p for p in opts['sd_param'][0]] + sd.convert(_x, *sd_param, from_=opts['tau_type'], to_='raw') + + relax = Relaxation() + relax.distribution(sd, parameter=sd_param, keywords=opts['sd_param'][1]) + + cp_param = [self.data[p].y.real if isinstance(p, str) else p for p in opts['cp_param'][0]] + relax.coupling(opts['coup'], parameter=cp_param, keywords=opts['cp_param'][1]) + + if opts['out'] == 't1': + y = relax.t1(x2, _x) + else: + y = relax.t2(x2, _x) + + pts = Points(x1, y, name=sd.name) + pts.meta.update(opts) + + # we do not want class instances + pts.meta['coup'] = opts['coup'].name + pts.meta['spec_dens'] = sd.name + + self.newData.emit([self.add(pts)], opts['graph']) + self.sender().update_graphs(self.graphs.list()) + + def mask_value(self, idx: str, m: list): + self.data[idx].mask = m + + def remove_values(self, idx: str, m: list): + self.data[idx].remove(m) + + def set_values(self, idx: str, pos: tuple, value): + self.data[idx].setvalues(pos, value) + + def append(self, idx: str): + self.data[idx].add([0.0, 0.0, 0.0]) + + def save(self, outpath: str, extension: str, strip_spaces=False): + path = pathlib.Path(outpath) + suffix = path.suffix + + if not suffix: + m = re.match(r'[\w\s]*\(\*(\.\w+)\)', extension) + if m: + suffix = m.group(1) + path = path.with_suffix(suffix) + else: + raise ValueError('No file extension detected') + + if suffix == '.nmr': + from ...io.sessionwriter import NMRWriter + NMRWriter(self.graphs, self.data).export(path) + + return + + real_outnames = [] + for set_id, set_name in self.active_sets: + full_name = path.stem + if '