fixes in grace export and work on fit dialog

This commit is contained in:
dominik 2022-04-12 18:45:30 +02:00
parent 74dacd0180
commit 4a18965580
26 changed files with 355 additions and 499 deletions

View File

@ -1,27 +0,0 @@
{{ objname | escape | underline}}
Import as {{ fullname }}
.. currentmodule:: {{ module }}
.. autoclass:: {{ objname }}
{% block methods %}
{% if methods %}
.. rubric:: {{ _('Methods') }}
.. autosummary::
:toctree:
{% for item in methods %}
{%- if not item.startswith('_') %}
~{{ name }}.{{ item }}
{%- endif %}
{%- endfor %}
{% endif %}
{% endblock %}
.. minigallery:: {{module}}.{{objname}}
:add-heading:

View File

@ -1,14 +1,27 @@
:mod:`{{ module | escape }}`.{{ objname }} {{ fullname | escape | underline}}
{{ underline }}==================
.. currentmodule:: {{ module }} .. currentmodule:: {{ module }}
.. autoclass:: {{ objname }} .. autoclass:: {{ objname }}
:members:
:inherited-members:
.. include:: {{ fullname }}.examples {% block methods %}
.. raw:: html {% if methods %}
.. rubric:: {{ _('Methods') }}
<div class="clearer"></div> {% for item in methods %}
.. automethod:: {{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
{% block attributes %}
{% if attributes %}
.. rubric:: {{ _('Attributes') }}
.. autosummary::
{% for item in attributes %}
~{{ name }}.{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}

View File

@ -1,33 +0,0 @@
{{ fullname | escape | underline}}
.. currentmodule:: {{ module }}
.. autoclass:: {{ objname }}
{%- block methods %}
{% if methods %}
.. rubric:: {{ _('Methods') }}
{%- for item in methods %}
{% if not item.startswith('_') %}
.. automethod:: {{ item }}
{%- endif %}
{%- endfor %}
{%- endif %}
{% endblock %}
{%- block attributes %}
{%- if attributes %}
.. rubric:: {{ _('Attributes') }}
{% for item in attributes %}
.. autoattribute:: {{ item }}
{%- endfor %}
{% endif %}
{% endblock -%}
.. include:: {{ fullname }}.examples
.. raw:: html
<div class="clearer"></div>

View File

@ -1,4 +1,5 @@
.. automodule:: nmreval.distributions .. automodule:: nmreval.distributions
:no-members: :members:
:no-inherited-members: :inherited-members:
:no-special-members: :undoc-members:

View File

@ -1,4 +1,2 @@
.. automodule:: nmreval.models .. automodule:: nmreval.models
:no-members: :members:
:no-inherited-members:
:no-special-members:

View File

@ -39,7 +39,6 @@ version = release
extensions = [ extensions = [
'sphinx.ext.autodoc', 'sphinx.ext.autodoc',
'sphinx.ext.autosummary', 'sphinx.ext.autosummary',
'sphinx.ext.inheritance_diagram',
'sphinx.ext.napoleon', 'sphinx.ext.napoleon',
'sphinx.ext.viewcode', 'sphinx.ext.viewcode',
'sphinx.ext.intersphinx', 'sphinx.ext.intersphinx',
@ -55,14 +54,13 @@ intersphinx_mapping = {
'matplotlib': ('https://matplotlib.org/stable', None), 'matplotlib': ('https://matplotlib.org/stable', None),
} }
# autodoc options # # autodoc options
autodoc_typehints = 'none' autodoc_typehints = 'none'
autodoc_class_signature = 'separated' autodoc_class_signature = 'separated'
autoclass_content = 'class' autoclass_content = 'class'
autodoc_member_order = 'groupwise' autodoc_member_order = 'groupwise'
# autodoc_default_options = {'members': False, 'inherited-members': False} #
# # autosummay options
# autosummay options
autosummary_generate = True autosummary_generate = True
# spinx-gallery # spinx-gallery

View File

@ -13,7 +13,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object): class Ui_Form(object):
def setupUi(self, Form): def setupUi(self, Form):
Form.setObjectName("Form") Form.setObjectName("Form")
Form.resize(314, 232) Form.resize(382, 375)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
@ -23,14 +23,14 @@ class Ui_Form(object):
self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setSpacing(3) self.gridLayout.setSpacing(3)
self.gridLayout.setObjectName("gridLayout") self.gridLayout.setObjectName("gridLayout")
self.widget = ExpandableWidget(Form) self.typecomboBox = QtWidgets.QComboBox(Form)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth()) sizePolicy.setHeightForWidth(self.typecomboBox.sizePolicy().hasHeightForWidth())
self.widget.setSizePolicy(sizePolicy) self.typecomboBox.setSizePolicy(sizePolicy)
self.widget.setObjectName("widget") self.typecomboBox.setObjectName("typecomboBox")
self.gridLayout.addWidget(self.widget, 4, 0, 1, 2) self.gridLayout.addWidget(self.typecomboBox, 0, 0, 1, 2)
self.complex_widget = QtWidgets.QWidget(Form) self.complex_widget = QtWidgets.QWidget(Form)
self.complex_widget.setObjectName("complex_widget") self.complex_widget.setObjectName("complex_widget")
self.gridLayout_2 = QtWidgets.QGridLayout(self.complex_widget) self.gridLayout_2 = QtWidgets.QGridLayout(self.complex_widget)
@ -53,7 +53,15 @@ class Ui_Form(object):
self.label.setSizePolicy(sizePolicy) self.label.setSizePolicy(sizePolicy)
self.label.setObjectName("label") self.label.setObjectName("label")
self.gridLayout_2.addWidget(self.label, 0, 0, 1, 2) self.gridLayout_2.addWidget(self.label, 0, 0, 1, 2)
self.gridLayout.addWidget(self.complex_widget, 5, 0, 1, 2) self.gridLayout.addWidget(self.complex_widget, 6, 0, 1, 2)
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.use_function_button = QtWidgets.QToolButton(Form) self.use_function_button = QtWidgets.QToolButton(Form)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
@ -65,31 +73,6 @@ class Ui_Form(object):
self.use_function_button.setArrowType(QtCore.Qt.RightArrow) self.use_function_button.setArrowType(QtCore.Qt.RightArrow)
self.use_function_button.setObjectName("use_function_button") self.use_function_button.setObjectName("use_function_button")
self.gridLayout.addWidget(self.use_function_button, 3, 1, 1, 1) 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 = QtWidgets.QComboBox(Form)
self.operator_combobox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) self.operator_combobox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
self.operator_combobox.setFrame(True) self.operator_combobox.setFrame(True)
@ -99,9 +82,19 @@ class Ui_Form(object):
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.gridLayout.addWidget(self.operator_combobox, 3, 0, 1, 1)
self.use_combobox = QtWidgets.QComboBox(Form) self.functree = FitModelTree(Form)
self.use_combobox.setObjectName("use_combobox") self.functree.setObjectName("functree")
self.gridLayout.addWidget(self.use_combobox, 6, 0, 1, 2) self.functree.headerItem().setText(0, "1")
self.gridLayout.addWidget(self.functree, 5, 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.retranslateUi(Form) self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form) QtCore.QMetaObject.connectSlotsByName(Form)
@ -115,9 +108,9 @@ class Ui_Form(object):
self.complex_comboBox.setItemText(2, _translate("Form", "Imaginary")) self.complex_comboBox.setItemText(2, _translate("Form", "Imaginary"))
self.label.setText(_translate("Form", "Complex function found")) self.label.setText(_translate("Form", "Complex function found"))
self.use_function_button.setText(_translate("Form", "Use")) 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(0, _translate("Form", "Add"))
self.operator_combobox.setItemText(1, _translate("Form", "Multiply")) self.operator_combobox.setItemText(1, _translate("Form", "Multiply"))
self.operator_combobox.setItemText(2, _translate("Form", "Subtract")) self.operator_combobox.setItemText(2, _translate("Form", "Subtract"))
self.operator_combobox.setItemText(3, _translate("Form", "Divide by")) self.operator_combobox.setItemText(3, _translate("Form", "Divide by"))
from ..lib.expandablewidget import ExpandableWidget self.fitequation.setText(_translate("Form", "Equation"))
from ..fit.fit_forms import FitModelTree

View File

@ -15,7 +15,7 @@ from ...lib.symbols import SymbolStyle, symbolcycle
from ...data.nmr import Spectrum, FID from ...data.nmr import Spectrum, FID
from ..Qt import QtCore from ..Qt import QtCore
from ..io.exporters import pgitem_to_dic from ..io.exporters import GraceExporter
from ..lib.decorators import plot_update from ..lib.decorators import plot_update
from ..lib.pg_objects import ErrorBars, PlotItem from ..lib.pg_objects import ErrorBars, PlotItem
@ -33,6 +33,7 @@ class ExperimentContainer(QtCore.QObject):
self._fits = [] self._fits = []
self._data = data self._data = data
self._manager = kwargs.get('manager') self._manager = kwargs.get('manager')
self.graph = ''
self.mode = 'point' self.mode = 'point'
self.plot_real = None self.plot_real = None
@ -374,10 +375,12 @@ class ExperimentContainer(QtCore.QObject):
def save(self, fname): def save(self, fname):
ext = fname.suffix ext = fname.suffix
if ext == '.agr': if ext == '.agr':
real_dic = pgitem_to_dic(self.plot_real) dic = self._manager.graphs[self.graph].get_state()
from ..io.exporters import GraceExporter dic['items'] = [self.plot_real.get_data_opts()]
if self.plot_imag is not None:
dic['items'].append(self.plot_imag.get_data_opts())
GraceExporter(real_dic).export(fname) GraceExporter(dic).export(fname)
elif ext in ['.dat', '.txt']: elif ext in ['.dat', '.txt']:
self._data.savetxt(fname, err=True) self._data.savetxt(fname, err=True)

View File

@ -409,6 +409,9 @@ class FitTableWidget(QtWidgets.QTableWidget):
while self.rowCount(): while self.rowCount():
self.removeRow(0) self.removeRow(0)
self.setColumnCount(2)
self.hideColumn(1)
for (sid, name) in set_ids: for (sid, name) in set_ids:
item = QtWidgets.QTableWidgetItem(name) item = QtWidgets.QTableWidgetItem(name)
item.setCheckState(QtCore.Qt.Checked) item.setCheckState(QtCore.Qt.Checked)
@ -419,7 +422,7 @@ class FitTableWidget(QtWidgets.QTableWidget):
item2 = QtWidgets.QTableWidgetItem('') item2 = QtWidgets.QTableWidgetItem('')
self.setItem(row, 1, item2) self.setItem(row, 1, item2)
cb = QtWidgets.QComboBox() cb = QtWidgets.QComboBox(parent=self)
cb.addItem('Default') cb.addItem('Default')
self.setCellWidget(row, 1, cb) self.setCellWidget(row, 1, cb)

View File

@ -1,7 +1,6 @@
from itertools import cycle, count from itertools import cycle, count
from typing import List, Tuple, Union from typing import List, Tuple, Union
from .fit_forms import FitModelTree
from ..lib import get_icon from ..lib import get_icon
from .._py.fitfunctionwidget import Ui_Form from .._py.fitfunctionwidget import Ui_Form
from ..Qt import QtWidgets, QtCore, QtGui from ..Qt import QtWidgets, QtCore, QtGui
@ -26,9 +25,6 @@ class QFunctionWidget(QtWidgets.QWidget, Ui_Form):
super().__init__(parent=parent) super().__init__(parent=parent)
self.setupUi(self) self.setupUi(self)
self.functree = FitModelTree()
self.widget.setText('Model structure')
self.widget.addWidget(self.functree)
self._types = [] self._types = []
self.functions = find_models(models) self.functions = find_models(models)
@ -57,8 +53,14 @@ class QFunctionWidget(QtWidgets.QWidget, Ui_Form):
for i, op_icon in enumerate(self.op_names): for i, op_icon in enumerate(self.op_names):
self.operator_combobox.setItemIcon(i, get_icon(op_icon)) self.operator_combobox.setItemIcon(i, get_icon(op_icon))
def __len__(self): def __len__(self) -> int:
return self.use_combobox.count() num = 0
iterator = QtWidgets.QTreeWidgetItemIterator(self.functree)
while iterator.value():
num += 1
iterator += 1
return num
@QtCore.pyqtSlot(int, name='on_typecomboBox_currentIndexChanged') @QtCore.pyqtSlot(int, name='on_typecomboBox_currentIndexChanged')
def change_group(self, idx: int): def change_group(self, idx: int):
@ -114,11 +116,6 @@ class QFunctionWidget(QtWidgets.QWidget, Ui_Form):
qcolor = QtGui.QColor(color) qcolor = QtGui.QColor(color)
self.functree.add_function(idx, cnt, op, name, qcolor, **kwargs) 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] f = self.functions[idx]
if hasattr(f, 'iscomplex') and f.iscomplex: if hasattr(f, 'iscomplex') and f.iscomplex:
self.iscomplex = True self.iscomplex = True
@ -138,17 +135,11 @@ class QFunctionWidget(QtWidgets.QWidget, Ui_Form):
iterator += 1 iterator += 1
self.complex_widget.setVisible(self.iscomplex) 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) self.itemRemoved.emit(idx)
@QtCore.pyqtSlot(int, name='on_use_combobox_currentIndexChanged') @QtCore.pyqtSlot(QtWidgets.QTreeWidgetItem, int, name='on_functree_itemClicked')
def show_parameter(self, idx: int): def show_parameter(self, item: QtWidgets.QTreeWidgetItem, _: int):
if self.use_combobox.count(): self.showFunction.emit(item.data(0, self.functree.counterRole))
self.showFunction.emit(self.use_combobox.itemData(idx, QtCore.Qt.UserRole))
def get_selected(self): def get_selected(self):
function_nr, idx = self.functree.get_selected() function_nr, idx = self.functree.get_selected()
@ -217,9 +208,5 @@ class QFunctionWidget(QtWidgets.QWidget, Ui_Form):
self.functree.clear() self.functree.clear()
self.functree.blockSignals(False) 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_comboBox.setCurrentIndex(0)
self.complex_widget.hide() self.complex_widget.hide()

View File

@ -511,9 +511,11 @@ class QGraphWindow(QtWidgets.QGraphicsView, Ui_GraphWindow):
item = self.real_plots[sid] item = self.real_plots[sid]
other_item = self.imag_plots[sid] other_item = self.imag_plots[sid]
# should legend be visible? is either real part or imaginary part shown? # should legend be visible? is either real part or imaginary part shown?
if self.listWidget.item(i).checkState() and \ if self.listWidget.item(i).checkState():
(item in self.graphic.items() or other_item in self.graphic.items()): if item in self.graphic.items():
self.legend.addItem(item, convert(item.opts.get('name', ''), old='tex', new='html')) self.legend.addItem(item, convert(item.opts.get('name', ''), old='tex', new='html'))
elif other_item in self.graphic.items():
self.legend.addItem(other_item, convert(other_item.opts.get('name', ''), old='tex', new='html'))
def export_dialog(self): def export_dialog(self):
filters = 'All files (*.*);;AGR (*.agr);;SVG (*.svg);;PDF (*.pdf)' filters = 'All files (*.*);;AGR (*.agr);;SVG (*.svg);;PDF (*.pdf)'
@ -580,12 +582,21 @@ class QGraphWindow(QtWidgets.QGraphicsView, Ui_GraphWindow):
self.set_color(foreground=fg_color, background=bg_color) self.set_color(foreground=fg_color, background=bg_color)
def export_graphics(self): def export_graphics(self) -> dict:
dic = self.get_state() dic = self.get_state()
dic['items'] = [] dic['items'] = []
in_legend = []
for item in self.curves(): for item in self.curves():
item_dic = item[0].get_data_opts() plot_item = item[0]
legend_shown = False
for sample, _ in self.legend.items:
if sample.item is plot_item:
legend_shown = True
break
in_legend.append(legend_shown)
item_dic = plot_item.get_data_opts()
if len(item) == 2: if len(item) == 2:
# plot can show errorbars # plot can show errorbars
item_dic['yerr'] = item[1].opts['topData'] item_dic['yerr'] = item[1].opts['topData']
@ -593,6 +604,8 @@ class QGraphWindow(QtWidgets.QGraphicsView, Ui_GraphWindow):
if item_dic: if item_dic:
dic['items'].append(item_dic) dic['items'].append(item_dic)
dic['in_legend'] = in_legend
return dic return dic
def get_state(self) -> dict: def get_state(self) -> dict:

View File

@ -1,9 +1,8 @@
from __future__ import annotations
from numpy import c_ from numpy import c_
from ...io.graceeditor import GraceEditor 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 ...utils.text import convert
from ..Qt import QtGui, QtCore, QtPrintSupport from ..Qt import QtGui, QtCore, QtPrintSupport
@ -14,7 +13,7 @@ class GraceExporter:
self.__agr = None self.__agr = None
self.__opts = kwargs self.__opts = kwargs
def export(self, outfile: str, mode: (int, str) = 'w'): def export(self, outfile: str, mode: int | str = 'w'):
if mode == 'w': if mode == 'w':
self.__agr = GraceEditor() self.__agr = GraceEditor()
else: else:
@ -27,7 +26,7 @@ class GraceExporter:
new_g.set_log(x=self.__opts['log'][0], y=self.__opts['log'][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_onoff('legend', self.__opts['legend'])
new_g.set_property(**{'title': '"' + convert(self.__opts['labels'][2], old="html", new="agr") + '"', new_g.set_property(**{'title': f'"{convert(self.__opts["labels"][2], old="html", new="agr")}"',
'legend loctype': 'view', 'legend loctype': 'view',
'legend': ', '.join(str(i) for i in new_g.world_to_view(self.__opts['legend_pos']))}) 'legend': ', '.join(str(i) for i in new_g.world_to_view(self.__opts['legend_pos']))})
@ -43,7 +42,7 @@ class GraceExporter:
colors = self.__agr.colors colors = self.__agr.colors
new_colors = [] new_colors = []
for item in self.__opts['items']: for plot_label, item in zip(self.__opts['in_legend'], self.__opts['items']):
new_s = self.__agr.new_set(g_idx) new_s = self.__agr.new_set(g_idx)
sc = item['symbolcolor'] sc = item['symbolcolor']
@ -75,7 +74,12 @@ class GraceExporter:
new_s.set_line(**{'color': c_num, 'linewidth': item['linewidth'], new_s.set_line(**{'color': c_num, 'linewidth': item['linewidth'],
'linestyle': item['linestyle'].to_agr()}) 'linestyle': item['linestyle'].to_agr()})
new_s.set_property(comment='"' + item['name'] + '"', legend='"' + item['name'] + '"')
if plot_label:
new_s.set_property(comment=f'"{item["name"]}"',
legend=f'"{convert(item["name"], old="tex", new="agr")}"')
else:
new_s.set_property(comment=f'"{item["name"]}"')
data = self.__agr.dataset(g_idx, new_s.idx) data = self.__agr.dataset(g_idx, new_s.idx)
if 'yerr' in item: if 'yerr' in item:
@ -108,36 +112,3 @@ class PDFPrintExporter:
painter = QtGui.QPainter(printer) painter = QtGui.QPainter(printer)
self.graphic.render(painter) self.graphic.render(painter)
painter.end() 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], normed=True)
pen = opts['pen']
if pen is not None:
item_dic['linestyle'] = LineStyle(pen.style())
item_dic['linecolor'] = Colors.from_rgb(*pen.color().getRgbF()[:3], normed=True)
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

View File

@ -35,8 +35,6 @@ def diamond(a):
y = a-x y = a-x
pxl.extend([[x, y], [-x, y], [x, -y], [-x, -y]]) pxl.extend([[x, y], [-x, y], [x, -y], [-x, -y]])
print(np.array(pxl).shape)
return np.array(pxl) return np.array(pxl)
@ -100,7 +98,6 @@ class GameOfLife:
self.fill = np.zeros(self.populations) self.fill = np.zeros(self.populations)
self._populate(fill, pattern) self._populate(fill, pattern)
print(rules)
if isinstance(rules, str): if isinstance(rules, str):
try: try:
b_rule, s_rule = predefined_rules[rules] b_rule, s_rule = predefined_rules[rules]

View File

@ -165,8 +165,8 @@ class PlotItem(PlotDataItem):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.opts['linecolor'] = Colors.Black self.opts['linecolor'] = (0, 0, 0)
self.opts['symbolcolor'] = Colors.Black self.opts['symbolcolor'] = (0, 0, 0)
if self.opts['pen'] is not None: if self.opts['pen'] is not None:
pen = self.opts['pen'] pen = self.opts['pen']
@ -251,7 +251,6 @@ class PlotItem(PlotDataItem):
x = [] x = []
if y is None: if y is None:
y = [] y = []
# scatterArgs['mask'] = self.dataMask
if curveArgs['pen'] is not None or (curveArgs['brush'] is not None and curveArgs['fillLevel'] is not None): 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) is_finite = np.isfinite(x) & np.isfinite(y)
@ -347,7 +346,6 @@ class PlotItem(PlotDataItem):
item_dic['symbolcolor'] = opts['symbolcolor'] item_dic['symbolcolor'] = opts['symbolcolor']
pen = opts['pen'] pen = opts['pen']
if pen is not None: if pen is not None:
item_dic['linestyle'] = LineStyle(pen.style()) item_dic['linestyle'] = LineStyle(pen.style())
item_dic['linecolor'] = opts['linecolor'] item_dic['linecolor'] = opts['linecolor']

View File

@ -180,7 +180,6 @@ class SnakeBoard(Board):
self.update() self.update()
def snake_move(self): def snake_move(self):
print(self.next_direction)
if self.next_direction: if self.next_direction:
turn = self.next_direction.pop() turn = self.next_direction.pop()
if self.direction != self._direction_pairs[turn]: if self.direction != self._direction_pairs[turn]:

View File

@ -463,10 +463,16 @@ class GraceGraph(GraceProperties):
def set_log(self, x=None, y=None): def set_log(self, x=None, y=None):
kwargs = {} kwargs = {}
if x is not None: for ax, label in [(x, 'x'), (y, 'y')]:
kwargs['xaxes scale'] = 'Logarithmic' if x else 'Normal' if ax is not None:
if y is not None: if ax:
kwargs['yaxes scale'] = 'Logarithmic' if y else 'Normal' kwargs[label + 'axes scale'] = 'Logarithmic'
kwargs[label + 'axis ticklabel format'] = 'power'
kwargs[label + 'axis ticklabel prec'] = '0'
else:
kwargs[label + 'axes scale'] = 'Normal'
kwargs[label + 'axis ticklabel format'] = 'general'
kwargs[label + 'axis ticklabel prec'] = '5'
for i, line in enumerate(self): for i, line in enumerate(self):
m = self._RE_ENTRY.match(line) m = self._RE_ENTRY.match(line)

View File

@ -1,14 +1,14 @@
""" """
============= =====================================
Fit functions Fit functions (:mod:`nmreval.models`)
============= =====================================
.. currentmodule:: nmreval.models .. currentmodule:: nmreval.models
.. autosummary:: .. autosummary::
:toctree: generated :toctree: generated
:nosignatures: :nosignatures:
:template: autosummary/class_with_attributes.rst :recursive:
Constant Constant
Linear Linear

View File

@ -3,7 +3,7 @@
Basic functions Basic functions
*************** ***************
Simple basic functions Simple functions
""" """
import numpy as np import numpy as np
@ -27,7 +27,7 @@ class Constant:
Constant Constant
.. math:: .. math::
y = c \cdot x y = c
Args: Args:
x (array-like): Input values x (array-like): Input values
@ -135,22 +135,7 @@ class Parabola:
class PowerLawCross: class PowerLawCross:
""" """
Crossover between to power laws at position :math:`x_0` Crossover between power laws
.. math::
y \\propto
\\begin{cases}
x^{b_1}, & x \le x_0 \\\\
x^{b_2}, & x > x_0
\\end{cases}
Args:
x (array_like): Input values
c (float): Prefactor
b1 (float): Exponent of first power law
b2 (float): Exponent of second power law
x0 (float): x position of crossover
""" """
type = 'Basic' type = 'Basic'
name = 'Crossing Power Laws' name = 'Crossing Power Laws'
@ -158,6 +143,23 @@ class PowerLawCross:
@staticmethod @staticmethod
def func(x, c, b1, b2, x0): def func(x, c, b1, b2, x0):
"""
Crossover between to power laws at position :math:`x_0`
.. math::
y \\propto
\\begin{cases}
x^{b_1}, & x \le x_0 \\\\
x^{b_2}, & x > x_0
\\end{cases}
Args:
x (array_like): Input values
c (float): Prefactor
b1 (float): Exponent of first power law
b2 (float): Exponent of second power law
x0 (float): x position of crossover
"""
mas = np.nonzero(x > x0) mas = np.nonzero(x > x0)
ret_val = c * x**b1 ret_val = c * x**b1
c2 = c * x0**(b1-b2) c2 = c * x0**(b1-b2)
@ -167,19 +169,8 @@ class PowerLawCross:
class Sine: class Sine:
""" """
Sine function Wavy sine function
.. math::
y = C\sin(a x - \phi)
Args:
x (array_like): Input values
c (float): Prefactor
a (float): frequency
phi (float): shift
""" """
type = 'Basic' type = 'Basic'
name = 'Sine' name = 'Sine'
equation = r'C*sin(a*x-\phi)' equation = r'C*sin(a*x-\phi)'
@ -187,6 +178,19 @@ class Sine:
@staticmethod @staticmethod
def func(x, c: float, a: float, phi: float): def func(x, c: float, a: float, phi: float):
"""
Calculate sine function
.. math::
y = C\sin(a x - \phi)
Args:
x (array_like): Input values
c (float): Prefactor
a (float): frequency
phi (float): shift
"""
return c*np.sin(a*x-phi) return c*np.sin(a*x-phi)

View File

@ -116,15 +116,16 @@ class Peschier:
name = 'Diffusion + Cross-Relaxation' name = 'Diffusion + Cross-Relaxation'
type = 'Diffusion' type = 'Diffusion'
equation = r'Diffusion with cross-relax f(ast) \rightarrow s(low)' equation = r'Diffusion with cross-relax f(ast) \rightarrow s(low)'
params = ['M_{0}', 'D', 'T_{1,f}', 'T_{1,s}', 'k_{f}', 'k_{s}', 't_{ev}', 'g'] params = ['M_{0}', 'D', 'T_{1,f}', 'T_{1,s}', 'k', 'p_{f}', 't_{ev}', 'g']
bounds = [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None)] bounds = [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None)]
choices = [(r'\gamma', 'nucleus', gamma)] choices = [(r'\gamma', 'nucleus', gamma)]
@staticmethod @staticmethod
def func(x, m0, d, t1f, t1s, kf, ks, tp, g, nucleus=2.67522128e8): def func(x, m0, d, t1f, t1s, k, pf, tp, g, nucleus: float = 2.67522128e8):
q = nucleus*g*tp q = nucleus*g*tp
r1s, r1f = 1 / t1s, 1 / t1f r1s, r1f = 1 / t1s, 1 / t1f
kf, ks = pf*k, (1-pf)*k
a_plus = 0.5 * (d*q*q + kf + ks + r1f + r1s + np.sqrt((d*q*q + kf + r1f - ks - r1s)**2 + 4*kf*ks)) a_plus = 0.5 * (d*q*q + kf + ks + r1f + r1s + np.sqrt((d*q*q + kf + r1f - ks - r1s)**2 + 4*kf*ks))
a_minu = 0.5 * (d*q*q + kf + ks + r1f + r1s - np.sqrt((d*q*q + kf + r1f - ks - r1s)**2 + 4*kf*ks)) a_minu = 0.5 * (d*q*q + kf + ks + r1f + r1s - np.sqrt((d*q*q + kf + r1f - ks - r1s)**2 + 4*kf*ks))

View File

@ -119,20 +119,3 @@ class SatRecMLF:
if kind == 'inv': if kind == 'inv':
a = 2 a = 2
return dm * (1 - a * mlf(-(x/t1)**alpha, alpha)) + m0 return dm * (1 - a * mlf(-(x/t1)**alpha, alpha)) + m0
class PeschierHomogeneous:
name = 'Cross-Relaxation (g=0)'
type = 'Relaxation'
equation = r'Cross-Relaxation f(ast) \rightarrow s(low) (m_{s}(0)=0)'
params = ['M_{0}', 'k_{s}', 'k_{f}', 'T_{1,s}', 'T_{1,f}']
bounds = [(0, None), (0, None), (0, None), (0, None), (0, None)]
@staticmethod
def func(x, m, ks, kf, t1s, t1f):
r1f, r1s = 1/t1f, 1/t1s
a_plus = 0.5*((kf + ks + r1f + r1s) + np.sqrt((kf + r1f - ks - r1s)**2 + 4*kf*ks))
a_minu = 0.5*((kf + ks + r1f + r1s) - np.sqrt((kf + r1f - ks - r1s)**2 + 4*kf*ks))
return m*((a_plus - ks - r1s) / (a_plus - a_minu) * np.exp(-a_plus * x) -
(a_minu - ks - r1s) / (a_plus - a_minu) * np.exp(-a_minu * x))

View File

@ -1,3 +0,0 @@
from ..configs import config_paths
print(config_paths() / 'usermodels.py')

53
pyproject.toml Normal file
View File

@ -0,0 +1,53 @@
[metadata]
name = nmreval
version = 0.1
description = Evaluation of data
long_description = file: README.md
author = Dominik Demuth
author_email = dominik.demuth@physik.tu-darmstadt.de
install_requires = [
'numpy',
'scipy',
'matplotlib',
'bsddb3',
'pyqtgraph',
'pyqt',
'h5py',
]
keywords = ['nmr', 'physics', 'science']
classifiers = [
'Development Status :: 3 - Alpha',
'Intended Audience :: End Users/Desktop',
'Intended Audience :: Science/Research',
'Topic :: Scientific/Engineering :: Physics',
'Topic :: Scientific/Engineering :: Visualization',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3 :: only',
]
license = {text = "BSD 3-Clause License"}
[tool.setuptools]
include_package_data = true
[tool.setuptools.packages]
find = {}
scripts = bin/evaluate.py
[tool.setuptools.packages.find]
include =[
'nmreval*',
'resources*',
]
[tool.setuptools.package_data]
* = *.txt, *.npz, *.png, *.json

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>314</width> <width>382</width>
<height>232</height> <height>375</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -35,17 +35,17 @@
<property name="spacing"> <property name="spacing">
<number>3</number> <number>3</number>
</property> </property>
<item row="4" column="0" colspan="2"> <item row="0" column="0" colspan="2">
<widget class="ExpandableWidget" name="widget" native="true"> <widget class="QComboBox" name="typecomboBox">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Maximum"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0" colspan="2"> <item row="6" column="0" colspan="2">
<widget class="QWidget" name="complex_widget" native="true"> <widget class="QWidget" name="complex_widget" native="true">
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin"> <property name="leftMargin">
@ -102,6 +102,16 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="1" column="0" colspan="2">
<widget class="QComboBox" name="fitcomboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="1"> <item row="3" column="1">
<widget class="QToolButton" name="use_function_button"> <widget class="QToolButton" name="use_function_button">
<property name="sizePolicy"> <property name="sizePolicy">
@ -124,42 +134,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0" colspan="2">
<widget class="QComboBox" name="fitcomboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QComboBox" name="typecomboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="fitequation">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Equation</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QComboBox" name="operator_combobox"> <widget class="QComboBox" name="operator_combobox">
<property name="sizeAdjustPolicy"> <property name="sizeAdjustPolicy">
@ -190,17 +164,38 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="6" column="0" colspan="2"> <item row="5" column="0" colspan="2">
<widget class="QComboBox" name="use_combobox"/> <widget class="FitModelTree" name="functree">
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="fitequation">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Equation</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>
<class>ExpandableWidget</class> <class>FitModelTree</class>
<extends>QWidget</extends> <extends>QTreeWidget</extends>
<header>..lib.expandablewidget</header> <header>..fit.fit_forms</header>
<container>1</container>
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>

47
setup.cfg Normal file
View File

@ -0,0 +1,47 @@
[metadata]
name = nmreval
version = 0.1
description = Evaluation of data
long_description = file: README.md
author = Dominik Demuth
author_email = dominik.demuth@physik.tu-darmstadt.de
install_requires =
numpy
scipy
matplotlib
bsddb3
pyqtgraph
pyqt
h5py
keywords = nmr, physics, science
classifiers =
Development Status :: 3 - Alpha
Intended Audience :: End Users/Desktop
Intended Audience :: Science/Research
Topic :: Scientific/Engineering :: Physics
Topic :: Scientific/Engineering :: Visualization
Programming Language :: Python :: 3
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3 :: Only
license = BSD 3-Clause License
[options]
include_package_data = True
packages = find:
scripts = bin/evaluate.py
[options.packages.find]
include =
nmreval*
resources*
[options.package_data]
* = *.txt, *.npz, *.png, *.json

242
setup.py
View File

@ -1,11 +1,3 @@
from setuptools import setup
setup(
name='nmreval',
version='0.1',
packages=['.nmreval']
)
"""A setuptools based setup module. """A setuptools based setup module.
See: See:
@ -26,193 +18,57 @@ long_description = (here / 'README.md').read_text(encoding='utf-8')
# Fields marked as "Optional" may be commented out. # Fields marked as "Optional" may be commented out.
setup( setup(
# This is the name of your project. The first time you publish this # name='nmreval', # Required
# package, this name will be registered for you. It will determine how # version='0.1', # Required
# users can install this project, e.g.: # description='A sample Python project', # Optional
# long_description=long_description, # Optional
# long_description_content_type='text/markdown', # Optional (see note above)
# url='https://chaos3.fkp.physik.tu-darmstadt.de/source/nmreval/', # Optional
# author='Dominik Demuth', # Optional
# author_email='dominik.demuth@physik.tu-darmstadt.de', # Optional
# classifiers=[ # Optional
# 'Development Status :: 3 - Alpha',
# 'Intended Audience :: End Users/Desktop',
# 'Intended Audience :: Science/Research',
# 'Topic :: Scientific/Engineering :: Physics',
# 'Topic :: Scientific/Engineering :: Visualization',
# 'License :: OSI Approved :: BSD 3-Clause License',
# 'Programming Language :: Python :: 3',
# 'Programming Language :: Python :: 3.7',
# 'Programming Language :: Python :: 3.8',
# 'Programming Language :: Python :: 3.9',
# "Programming Language :: Python :: 3.10",
# 'Programming Language :: Python :: 3 :: Only',
# ],
# #
# $ pip install sampleproject # keywords='nmr, physics, science', # Optional
# # package_dir={'': '.'}, # Optional
# And where it will live on PyPI: https://pypi.org/project/sampleproject/ # packages=find_packages(where='.'), # Required
# # include_package_data=True,
# There are some restrictions on what makes a valid project name # python_requires='>=3.7',
# specification here: # install_requires=[
# https://packaging.python.org/specifications/core-metadata/#name # 'numpy',
name='nmreval', # Required # 'scipy',
# 'matplotlib',
# Versions should comply with PEP 440: # 'bsddb3',
# https://www.python.org/dev/peps/pep-0440/ # 'pyqtgraph',
# # 'pyqt',
# For a discussion on single-sourcing the version across setup.py and the # 'h5py'
# project code, see # ], # Optional
# https://packaging.python.org/guides/single-sourcing-package-version/ # # extras_require={ # Optional
version='0.1', # Required # # 'dev': ['check-manifest'],
# # 'test': ['coverage'],
# This is a one-line description or tagline of what your project does. This # # },
# corresponds to the "Summary" metadata field: # package_data={ # Optional
# https://packaging.python.org/specifications/core-metadata/#summary # 'sample': ['package_data.dat'],
description='A sample Python project', # Optional # },
# data_files=[('my_data', ['data/data_file'])], # Optional
# This is an optional longer description of your project that represents # entry_points={ # Optional
# the body of text which users will see when they visit PyPI. # 'console_scripts': [
# # 'evaluate=bin:evaluate',
# Often, this is the same as your README, so you can just read it in from # ],
# that file directly (as we have already done above)
#
# This field corresponds to the "Description" metadata field:
# https://packaging.python.org/specifications/core-metadata/#description-optional
long_description=long_description, # Optional
# Denotes that our long_description is in Markdown; valid values are
# text/plain, text/x-rst, and text/markdown
#
# Optional if long_description is written in reStructuredText (rst) but
# required for plain-text or Markdown; if unspecified, "applications should
# attempt to render [the long_description] as text/x-rst; charset=UTF-8 and
# fall back to text/plain if it is not valid rst" (see link below)
#
# This field corresponds to the "Description-Content-Type" metadata field:
# https://packaging.python.org/specifications/core-metadata/#description-content-type-optional
long_description_content_type='text/x-rst', # Optional (see note above)
# This should be a valid link to your project's main homepage.
#
# This field corresponds to the "Home-Page" metadata field:
# https://packaging.python.org/specifications/core-metadata/#home-page-optional
url='https://github.com/pypa/sampleproject', # Optional
# This should be your name or the name of the organization which owns the
# project.
author='Dominik Demuth', # Optional
# This should be a valid email address corresponding to the author listed
# above.
author_email='dominik.demuth@physik.tu-darmstadt.de', # Optional
# Classifiers help users find your project by categorizing it.
#
# For a list of valid classifiers, see https://pypi.org/classifiers/
classifiers=[ # Optional
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 3 - Alpha',
# Indicate who your project is intended for
'Intended Audience :: Developers',
'Topic :: Software Development :: Build Tools',
# Pick your license as you wish
'License :: OSI Approved :: MIT License',
# Specify the Python versions you support here. In particular, ensure
# that you indicate you support Python 3. These classifiers are *not*
# checked by 'pip install'. See instead 'python_requires' below.
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
"Programming Language :: Python :: 3.10",
'Programming Language :: Python :: 3 :: Only',
],
# This field adds keywords for your project which will appear on the
# project page. What does your project relate to?
#
# Note that this is a list of additional keywords, separated
# by commas, to be used to assist searching for the distribution in a
# larger catalog.
keywords='sample, setuptools, development', # Optional
# When your source code is in a subdirectory under the project root, e.g.
# `src/`, it is necessary to specify the `package_dir` argument.
package_dir={'': 'src'}, # Optional
# You can just specify package directories manually here if your project is
# simple. Or you can use find_packages().
#
# Alternatively, if you just want to distribute a single Python file, use
# the `py_modules` argument instead as follows, which will expect a file
# called `my_module.py` to exist:
#
# py_modules=["my_module"],
#
packages=find_packages(where='src'), # Required
# Specify which Python versions you support. In contrast to the
# 'Programming Language' classifiers above, 'pip install' will check this
# and refuse to install the project if the version does not match. See
# https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires
python_requires='>=3.7, <4',
# This field lists other packages that your project depends on to run.
# Any package you put here will be installed by pip when your project is
# installed, so they must be valid existing projects.
#
# For an analysis of "install_requires" vs pip's requirements files see:
# https://packaging.python.org/discussions/install-requires-vs-requirements/
install_requires=[
'numpy',
'scipy',
'matplotlib',
'bsddb3',
'pyqtgraph',
'PyQt4',
'h5py'
], # Optional
# List additional groups of dependencies here (e.g. development
# dependencies). Users will be able to install these using the "extras"
# syntax, for example:
#
# $ pip install sampleproject[dev]
#
# Similar to `install_requires` above, these must be valid existing
# projects.
# extras_require={ # Optional
# 'dev': ['check-manifest'],
# 'test': ['coverage'],
# }, # },
# If there are data files included in your packages that need to be
# installed, specify them here.
package_data={ # Optional
'sample': ['package_data.dat'],
},
# Although 'package_data' is the preferred approach, in some case you may
# need to place data files outside of your packages. See:
# http://docs.python.org/distutils/setupscript.html#installing-additional-files
#
# In this case, 'data_file' will be installed into '<sys.prefix>/my_data'
data_files=[('my_data', ['data/data_file'])], # Optional
# To provide executable scripts, use entry points in preference to the
# "scripts" keyword. Entry points provide cross-platform support and allow
# `pip` to create the appropriate form of executable for the target
# platform.
#
# For example, the following would provide a command called `sample` which
# executes the function `main` from this package when invoked:
entry_points={ # Optional
'console_scripts': [
'sample=bin:main',
],
},
# List additional URLs that are relevant to your project as a dict.
#
# This field corresponds to the "Project-URL" metadata fields:
# https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use
#
# Examples listed include a pattern for specifying where the package tracks
# issues, where the source is hosted, where to say thanks to the package
# maintainers, and where to support the project financially. The key is
# what's used to render the link text on PyPI.
# project_urls={ # Optional # project_urls={ # Optional
# 'Bug Reports': 'https://github.com/pypa/sampleproject/issues', # 'Source': 'https://chaos3.fkp.physik.tu-darmstadt.de/source/nmreval/',
# 'Funding': 'https://donate.pypi.org',
# 'Say Thanks!': 'http://saythanks.io/to/example',
# 'Source': 'https://github.com/pypa/sampleproject/',
# }, # },
) )