Data set examples¶
Basic example¶
Source code :
# -*- coding: utf-8 -*-
import guidata
import guidata.dataset as gds
# Note: the following line is not required if a QApplication has already been created
_app = guidata.qapplication()
class Processing(
gds.DataSet,
title="Processing Parameters",
comment="This comment concerns this class of parameters, and may be overriden "
"when calling the constructor by passing a comment argument. That is the same for "
"the title.",
):
"""Example"""
a = gds.FloatItem("Parameter #1", default=2.3)
b = gds.IntItem("Parameter #2", min=0, max=10, default=5)
type = gds.ChoiceItem("Processing algorithm", ("type 1", "type 2", "type 3"))
param = Processing() # Default title and comment are used if not provided here
param.edit()
print(param) # Showing param contents
param.b = 4 # Modifying item value
param.view()
# Alternative way for creating a DataSet instance:
param = Processing.create(a=7.323, b=4)
print(param)
Other examples¶
A lot of examples are available in the guidata test module
from guidata import tests
tests.run()
The two lines above execute the guidata test launcher :
All guidata items demo¶
import atexit
import datetime
import shutil
import tempfile
from enum import Enum
import numpy as np
import guidata.dataset as gds
from guidata.config import _
from guidata.env import execenv
from guidata.qthelpers import qt_app_context
# Creating temporary files and registering cleanup functions
TEMPDIR = tempfile.mkdtemp(prefix="test_")
atexit.register(shutil.rmtree, TEMPDIR)
FILE_ETA = tempfile.NamedTemporaryFile(suffix=".eta", dir=TEMPDIR)
atexit.register(FILE_ETA.close)
FILE_CSV = tempfile.NamedTemporaryFile(suffix=".csv", dir=TEMPDIR)
atexit.register(FILE_CSV.close)
class ImageTypes(Enum):
"""Image types."""
#: Image filled with zeros
ZEROS = _("Zeros")
#: Empty image (filled with data from memory state)
EMPTY = _("Empty")
#: Image filled with random data (uniform law)
UNIFORMRANDOM = _("Random (uniform law)")
#: Image filled with random data (normal law)
NORMALRANDOM = _("Random (normal law)")
#: 2D Gaussian image
GAUSS = _("Gaussian")
#: Bilinear form image
RAMP = _("2D ramp")
class FilteringMethod(gds.LabeledEnum):
"""LabeledEnum example with invariant keys and UI labels."""
GAUSSIAN = "gaussian", _("Gaussian filter")
MEDIAN = "median", _("Median filter")
SOBEL = "sobel", _("Sobel edge detection")
LAPLACIAN = "laplacian", _("Laplacian filter")
BILATERAL = "bilateral", _("Bilateral filter")
MORPHOLOGICAL = "morphological" # Uses key as label
class ThresholdMode(gds.LabeledEnum):
"""Another LabeledEnum example."""
OTSU = "otsu_method", _("Otsu's method")
ADAPTIVE = "adaptive_mean", _("Adaptive mean")
GLOBAL = "global_threshold", _("Global threshold")
TRIANGLE = "triangle_algorithm", _("Triangle algorithm")
class Parameters(gds.DataSet):
"""
DataSet test
The following text is the DataSet 'comment': <br>Plain text or
<b>rich text<sup>2</sup></b> are both supported,
as well as special characters (α, β, γ, δ, ...)
"""
dir = gds.DirectoryItem("Directory", default=TEMPDIR)
preview = gds.TextItem("File names preview", default="-")
option = gds.ChoiceItem("Option", (("1", "first choice"), ("2", "second choice")))
fname = gds.FileOpenItem("Open file", ("csv", "eta"), FILE_CSV.name)
fnames = gds.FilesOpenItem("Open files", "csv", [FILE_CSV.name])
fname_s = gds.FileSaveItem("Save file", "eta", FILE_ETA.name)
string = gds.StringItem("String", default="default string !?")
text = gds.TextItem("Text", default="default\nmultiline\ntext")
float_slider = gds.FloatItem(
"Float (with slider)", default=0.5, min=0, max=1, step=0.01, slider=True
)
integer = gds.IntItem("Integer", default=5, min=3, max=16, slider=True).set_pos(
col=1
)
dtime = gds.DateTimeItem("Date/time", default=datetime.datetime(2010, 10, 10))
date = gds.DateItem("Date", default=datetime.date(2010, 10, 10)).set_pos(col=1)
bool1 = gds.BoolItem("Boolean option without label")
bool2 = gds.BoolItem("Boolean option with label", "Label")
_bg = gds.BeginGroup("A sub group")
color = gds.ColorItem("Color", default="red")
choice1 = gds.ChoiceItem(
"Single choice 1",
[("16", "first choice"), ("32", "second choice"), ("64", "third choice")],
)
choice2 = gds.ChoiceItem("Image type", ImageTypes, default=ImageTypes.GAUSS)
# LabeledEnum examples - Pattern 1 with invariant keys and UI labels
filter_method = gds.ChoiceItem(
"Filtering method", FilteringMethod, default=FilteringMethod.GAUSSIAN
)
threshold_mode = gds.ChoiceItem(
"Threshold mode", ThresholdMode, default=ThresholdMode.OTSU
)
mchoice2 = gds.ImageChoiceItem(
"Single choice 2",
[
("rect", "first choice", "gif.png"),
("ell", "second choice", "txt.png"),
("qcq", "third choice", "file.png"),
],
)
_eg = gds.EndGroup("A sub group")
floatarray = gds.FloatArrayItem(
"Float array", default=np.ones((50, 5), float), format=" %.2e "
).set_pos(col=1)
mchoice3 = gds.MultipleChoiceItem(
"MC type 1", [str(i) for i in range(12)]
).horizontal(4)
mchoice1 = (
gds.MultipleChoiceItem(
"MC type 2", ["first choice", "second choice", "third choice"]
)
.vertical(1)
.set_pos(col=1)
)
dictionary = gds.DictItem(
"Dictionary",
default={
"lkl": 2,
"tototo": 3,
"zzzz": "lklk",
"bool": True,
"float": 1.234,
"list": [1, 2.5, 3, "str", False, 5, {"lkl": 2, "l": [1, 2, 3]}],
},
help="This is a dictionary",
)
def test_all_items():
"""Test all DataItem objects"""
with qt_app_context():
prm = Parameters()
prm.floatarray[:, 0] = np.linspace(-5, 5, 50)
# Demonstrate LabeledEnum functionality
execenv.print("=== LabeledEnum Pattern 1 Demo ===")
execenv.print(f"Filter method (enum member): {prm.filter_method!r}")
execenv.print(f"Filter value (invariant key): {prm.filter_method.value!r}")
execenv.print(f"Filter label (UI display): {prm.filter_method.label!r}")
execenv.print(f"Filter str(): {str(prm.filter_method)!r}")
# Show different ways to set LabeledEnum values
prm.filter_method = "sobel" # Set by invariant key
execenv.print(f"Set by key 'sobel': {prm.filter_method!r}")
prm.filter_method = "Median filter" # Set by UI label
execenv.print(f"Set by label 'Median filter': {prm.filter_method!r}")
prm.filter_method = 0 # Set by index
execenv.print(f"Set by index 0: {prm.filter_method!r}")
execenv.print("=== End LabeledEnum Demo ===")
execenv.print(prm)
if prm.edit():
execenv.print(prm)
prm.view()
execenv.print("OK")
if __name__ == "__main__":
test_all_items()
Embedding guidata objects in GUI layouts¶
import numpy as np
from qtpy.QtWidgets import QMainWindow, QSplitter
import guidata.dataset as gds
from guidata.configtools import get_icon
from guidata.dataset.qtwidgets import DataSetEditGroupBox, DataSetShowGroupBox
from guidata.env import execenv
from guidata.qthelpers import (
add_actions,
create_action,
get_std_icon,
qt_app_context,
win32_fix_title_bar_background,
)
from guidata.tests.dataset.test_activable_dataset import Parameters
from guidata.widgets import about
class AnotherDataSet(gds.DataSet):
"""
Example 2
<b>Simple dataset example</b>
"""
param0 = gds.ChoiceItem("Choice", ["deazdazk", "aeazee", "87575757"])
param1 = gds.FloatItem("Foobar 1", default=0, min=0)
a_group = gds.BeginGroup("A group")
param2 = gds.FloatItem("Foobar 2", default=0.93)
param3 = gds.FloatItem("Foobar 3", default=123)
_a_group = gds.EndGroup("A group")
class ExampleMultiGroupDataSet(gds.DataSet):
"""Example DS with multiple groups"""
choices = gds.MultipleChoiceItem("Choices", ["a", "b", "c", "d", "e"])
dictionary = gds.DictItem("Dictionary", {"a": 1, "b": 2, "c": 3})
param0 = gds.ChoiceItem("Choice", ["deazdazk", "aeazee", "87575757"])
param1 = gds.FloatItem("Foobar 1", default=0, min=0)
t_group = gds.BeginTabGroup("T group")
a_group = gds.BeginGroup("A group")
param2 = gds.FloatItem("Foobar 2", default=0.93)
dir1 = gds.DirectoryItem("Directory 1")
file1 = gds.FileOpenItem("File 1")
_a_group = gds.EndGroup("A group")
b_group = gds.BeginGroup("B group")
param3 = gds.FloatItem("Foobar 3", default=123)
param4 = gds.BoolItem("Boolean")
_b_group = gds.EndGroup("B group")
c_group = gds.BeginGroup("C group")
param5 = gds.FloatItem("Foobar 4", default=250)
param6 = gds.DateItem("Date").set_prop("display", format="dd.MM.yyyy")
param7 = gds.ColorItem("Color")
_c_group = gds.EndGroup("C group")
_t_group = gds.EndTabGroup("T group")
class OtherDataSet(gds.DataSet):
"""Another example dataset"""
group1 = gds.BeginGroup("Group 1")
title = gds.StringItem("Title", default="Title")
icon = gds.ChoiceItem(
"Icon",
(
("python.png", "Python"),
("guidata.svg", "guidata"),
("settings.png", "Settings"),
),
)
opacity = gds.FloatItem("Opacity", default=1.0, min=0.1, max=1)
transform = gds.FloatArrayItem("Transform", default=np.array([1, 2, 3, 4, 5, 6]))
_group1 = gds.EndGroup("Group 1")
group2 = gds.BeginGroup("Group 2")
computed = gds.StringItem("Computed").set_computed(
lambda ds: f"T: {ds.title}, I: {ds.icon}, O: {ds.opacity}"
)
_group2 = gds.EndGroup("Group 2")
class MainWindow(QMainWindow):
"""Main window"""
def __init__(self):
QMainWindow.__init__(self)
win32_fix_title_bar_background(self)
self.setWindowIcon(get_icon("python.png"))
self.setWindowTitle("Application example")
# Instantiate dataset-related widgets:
self.groupbox1 = DataSetShowGroupBox(
"Activable dataset", Parameters, comment=""
)
self.groupbox2 = DataSetShowGroupBox(
"Standard dataset", AnotherDataSet, comment=""
)
self.groupbox3 = DataSetEditGroupBox(
"Standard dataset", OtherDataSet, comment=""
)
self.groupbox4 = DataSetEditGroupBox(
"Standard dataset", ExampleMultiGroupDataSet, comment=""
)
self.groupbox3.SIG_APPLY_BUTTON_CLICKED.connect(self.update_window)
self.update_groupboxes()
splitter = QSplitter(self)
splitter.addWidget(self.groupbox1)
splitter.addWidget(self.groupbox2)
splitter.addWidget(self.groupbox3)
splitter.addWidget(self.groupbox4)
self.setCentralWidget(splitter)
self.setContentsMargins(10, 5, 10, 5)
# File menu
file_menu = self.menuBar().addMenu("File")
quit_action = create_action(
self,
"Quit",
shortcut="Ctrl+Q",
icon=get_std_icon("DialogCloseButton"),
tip="Quit application",
triggered=self.close,
)
add_actions(file_menu, (quit_action,))
# Edit menu
edit_menu = self.menuBar().addMenu("Edit")
editparam1_action = create_action(
self, "Edit dataset 1", triggered=self.edit_dataset1
)
editparam2_action = create_action(
self, "Edit dataset 2", triggered=self.edit_dataset2
)
editparam4_action = create_action(
self, "Edit dataset 4", triggered=self.edit_dataset4
)
ro_param4_action = create_action(
self, "Dataset 4: read-only", toggled=self.ro_dataset4
)
add_actions(
edit_menu,
(editparam1_action, editparam2_action, editparam4_action, ro_param4_action),
)
# ? menu
help_menu = self.menuBar().addMenu("?")
about_action = create_action(
self,
"About guidata",
icon=get_std_icon("MessageBoxInformation"),
triggered=about.show_about_dialog,
)
add_actions(help_menu, (about_action,))
def update_window(self):
"""Update window"""
dataset = self.groupbox3.dataset
self.setWindowTitle(dataset.title)
self.setWindowIcon(get_icon(dataset.icon))
self.setWindowOpacity(dataset.opacity)
def update_groupboxes(self):
"""Update groupboxes"""
self.groupbox1.dataset.set_activable(False) # This is an activable dataset
self.groupbox1.get()
self.groupbox2.get()
self.groupbox4.get()
def ro_dataset4(self, readonly: bool):
self.groupbox4.dataset.set_readonly(readonly)
self.groupbox4.get()
def edit_dataset1(self):
"""Edit dataset 1"""
self.groupbox1.dataset.set_activable(True) # This is an activable dataset
if self.groupbox1.dataset.edit(self):
self.update_groupboxes()
def edit_dataset2(self):
"""Edit dataset 2"""
if self.groupbox2.dataset.edit(self):
self.update_groupboxes()
def edit_dataset4(self):
"""Edit dataset 4"""
if self.groupbox4.dataset.edit(self):
self.update_groupboxes()
def test_editgroupbox():
"""Test editgroupbox"""
with qt_app_context(exec_loop=True):
window = MainWindow()
window.show()
execenv.print("OK")
if __name__ == "__main__":
test_editgroupbox()
Data item groups and group selection¶
import guidata.dataset as gds
from guidata.env import execenv
from guidata.qthelpers import qt_app_context
prop1 = gds.ValueProp(False)
prop2 = gds.ValueProp(False)
class Parameters(gds.DataSet):
"""
Group selection test
<b>Group selection example:</b>
"""
g1 = gds.BeginGroup("group 1")
enable1 = gds.BoolItem(
"Enable parameter set #1",
help="If disabled, the following parameters will be ignored",
default=False,
).set_prop("display", store=prop1)
prm11 = gds.FloatItem("Prm 1.1", default=0, min=0).set_prop("display", active=prop1)
prm12 = gds.FloatItem("Prm 1.2", default=0.93).set_prop("display", active=prop1)
_g1 = gds.EndGroup("group 1")
g2 = gds.BeginGroup("group 2")
enable2 = gds.BoolItem(
"Enable parameter set #2",
help="If disabled, the following parameters will be ignored",
default=True,
).set_prop("display", store=prop2)
prm21 = gds.FloatItem("Prm 2.1", default=0, min=0).set_prop("display", active=prop2)
prm22 = gds.FloatItem("Prm 2.2", default=0.93).set_prop("display", active=prop2)
_g2 = gds.EndGroup("group 2")
def test_bool_selector():
"""Test bool selector"""
with qt_app_context():
prm = Parameters()
prm.edit()
execenv.print(prm)
execenv.print("OK")
if __name__ == "__main__":
test_bool_selector()
Activable data sets¶
class Parameters(gds.ActivableDataSet):
"""
Example
<b>Activable dataset example</b>
"""
def __init__(self, title=None, comment=None, icon=""):
gds.ActivableDataSet.__init__(self, title, comment, icon)
enable = gds.BoolItem(
"Enable parameter set",
help="If disabled, the following parameters will be ignored",
default=False,
)
param0 = gds.ChoiceItem("Param 0", ["choice #1", "choice #2", "choice #3"])
param1 = gds.FloatItem("Param 1", default=0, min=0)
param2 = gds.FloatItem("Param 2", default=0.93)
color = gds.ColorItem("Color", default="red")
Parameters.active_setup()
def test_activable_dataset():
"""Test activable dataset"""
with qt_app_context():
prm = Parameters()
prm.set_activable(True)
prm.edit()
prm.set_activable(False)
prm.edit()
prm.set_readonly()
prm.edit()
prm.set_readonly(False)
prm.edit()
execenv.print("OK")
if __name__ == "__main__":
test_activable_dataset()
Data set groups¶
from guidata.dataset import DataSetGroup
from guidata.env import execenv
from guidata.qthelpers import qt_app_context
from guidata.tests.dataset.test_all_features import Parameters
def test_dataset_group():
"""Test DataSetGroup"""
with qt_app_context():
e1 = Parameters("DataSet #1")
e2 = Parameters("DataSet #2")
g = DataSetGroup([e1, e2], title="Parameters group")
g.edit()
execenv.print(e1)
g.edit()
execenv.print("OK")
g = DataSetGroup([e1, e2], title="Parameters group in table mode")
g.edit(mode="table")
execenv.print(e1)
g.edit()
execenv.print("OK")
g.edit()
execenv.print(e1)
g.edit()
execenv.print("OK")
if __name__ == "__main__":
test_dataset_group()
Utilities¶
Update/restore a dataset from/to a dictionary¶
import numpy as np
from guidata.dataset.conv import restore_dataset, update_dataset
from guidata.tests.dataset.test_all_items import Parameters
def test_update_restore_dataset():
"""Test update/restore dataset from/to another dataset or dictionary"""
dataset = Parameters()
dsdict = {
"integer": 1,
"float_slider": 1.0,
"bool1": True,
"string": "test",
"floatarray": np.array([1, 2, 3]),
"dictionary": {"a": 1, "b": 2},
}
# Update dataset from dictionary
update_dataset(dataset, dsdict)
# Check dataset values
assert dataset.integer == dsdict["integer"]
assert dataset.float_slider == dsdict["float_slider"]
assert dataset.bool1 == dsdict["bool1"]
assert dataset.string == dsdict["string"]
assert np.all(dataset.floatarray == dsdict["floatarray"])
assert dataset.dictionary == dsdict["dictionary"]
# Update dataset from another dataset
dataset2 = Parameters()
update_dataset(dataset2, dataset)
# Check dataset values
assert dataset2.integer == dataset.integer
assert dataset2.float_slider == dataset.float_slider
assert dataset2.bool1 == dataset.bool1
assert dataset2.string == dataset.string
assert np.all(dataset2.floatarray == dataset.floatarray)
assert dataset2.dictionary == dataset.dictionary
# Restore dataset from dictionary
restore_dataset(dataset, dsdict)
# Check dataset values
assert dataset.integer == dsdict["integer"]
assert dataset.float_slider == dsdict["float_slider"]
assert dataset.bool1 == dsdict["bool1"]
assert dataset.string == dsdict["string"]
assert np.all(dataset.floatarray == dsdict["floatarray"])
assert dataset.dictionary == dsdict["dictionary"]
if __name__ == "__main__":
test_update_restore_dataset()
Create a dataset class from a function signature¶
from __future__ import annotations
import numpy as np
from guidata.dataset import create_dataset_from_func
from guidata.env import execenv
def func_ok(
a: int, b: float, c: str = "test", d: dict[str, int] = {"x": 1, "y": 3}
) -> None:
"""A function with type annotations"""
pass
def func_no_type(a, b, c="test"):
"""A function without type annotations"""
pass
def func_no_default(a: int, b: float, c: str, data: np.ndarray) -> None:
"""A function without default values"""
pass
def test_dataset_from_func():
"""Test generate dataset class from function"""
for func in (func_ok, func_no_default):
execenv.print(func.__name__)
dataset = create_dataset_from_func(func)
execenv.print(dataset)
execenv.print(dataset.create(a=1, b=2.0))
execenv.print("")
func = func_no_type
try:
create_dataset_from_func(func)
assert False, "Should have raised a ValueError"
except ValueError:
# This is expected
pass
if __name__ == "__main__":
test_dataset_from_func()
Create a dataset class from a function dictionary¶
import numpy as np
from guidata.dataset import create_dataset_from_dict
from guidata.env import execenv
TEST_DICT1 = {
"a": 1,
"b": 2.0,
"c": "test",
"d": {"x": 1, "y": 3},
"data": np.array([1, 2, 3]),
}
TEST_DICT2 = {
"a": 1,
"unsupported": [2.0, 3.0],
}
def test_dataset_from_dict():
"""Test generate dataset class from a dictionary"""
for dictionary in (TEST_DICT1,):
execenv.print(dictionary)
dataset = create_dataset_from_dict(dictionary)
execenv.print(dataset)
execenv.print(dataset.create())
execenv.print("")
try:
create_dataset_from_dict(TEST_DICT2)
assert False, "Should have raised a ValueError"
except ValueError:
# This is expected
pass
if __name__ == "__main__":
test_dataset_from_dict()
Data set HDF5 serialization/deserialization¶
import os.path as osp
import tempfile
from guidata.dataset import assert_datasets_equal
from guidata.env import execenv
from guidata.io import HDF5Reader, HDF5Writer
from guidata.qthelpers import qt_app_context
from guidata.tests.dataset.test_all_items import Parameters
def test_loadsave_hdf5():
"""Test HDF5 I/O"""
with tempfile.TemporaryDirectory() as temp_dir:
fname = osp.join(temp_dir, "test.h5")
with qt_app_context():
p1 = Parameters()
# p1.edit()
# Save to HDF5 file
writer = HDF5Writer(fname)
p1.serialize(writer)
writer.close()
p2 = Parameters()
# Set all items to None for testing purposes:
for item in p2._items:
item.__set__(p2, None)
# Load from HDF5 file
reader = HDF5Reader(fname)
p2.deserialize(reader)
reader.close()
assert_datasets_equal(p1, p2, "Parameters do not match after HDF5 I/O")
execenv.print("OK")
if __name__ == "__main__":
test_loadsave_hdf5()
Data set JSON serialization/deserialization¶
import os
from guidata.env import execenv
from guidata.io import JSONReader, JSONWriter
from guidata.qthelpers import qt_app_context
from guidata.tests.dataset.test_all_items import Parameters
def test_loadsave_json():
"""Test JSON I/O"""
fname = "test.json"
with qt_app_context():
if os.path.exists(fname):
os.unlink(fname)
p1 = Parameters()
if execenv.unattended or p1.edit():
writer = JSONWriter(fname)
p1.serialize(writer)
writer.save()
p2 = Parameters()
reader = JSONReader(fname)
p2.deserialize(reader)
reader.close()
p2.edit()
os.unlink(fname)
# TODO: Uncomment this part of the test, and make it work!
# if execenv.unattended:
# assert_datasets_equal(p1, p2, "Parameters do not match after HDF5 I/O")
execenv.print("OK")
if __name__ == "__main__":
test_loadsave_json()