Ready-to-use widgets¶
As a complement to the guidata.dataset module which focus on automatic
GUI generation for data sets editing and display, the guidata.widgets
module provides a set of ready-to-use widgets for building interactive GUIs.
Note
Most of the widgets originally come from the Spyder project (Copyright © Spyder Project Contributors, MIT-licensed). They were adapted to be used outside of the Spyder IDE and to be compatible with guidata internals.
Python console¶
from guidata.configtools import get_icon
from guidata.env import execenv
from guidata.qthelpers import qt_app_context
from guidata.widgets.console import Console
def test_console():
"""Test Console widget."""
with qt_app_context(exec_loop=True):
widget = Console(debug=False, multithreaded=True)
widget.resize(800, 600)
widget.setWindowTitle("Console")
widget.setWindowIcon(get_icon("guidata.svg"))
widget.show()
execenv.print("OK")
if __name__ == "__main__":
test_console()
Code editor¶
from guidata.configtools import get_icon
from guidata.env import execenv
from guidata.qthelpers import qt_app_context
from guidata.widgets import codeeditor
def test_codeeditor():
"""Test Code editor."""
with qt_app_context(exec_loop=True):
widget = codeeditor.CodeEditor(language="python")
widget.set_text_from_file(codeeditor.__file__)
widget.resize(800, 600)
widget.setWindowTitle("Code editor")
widget.setWindowIcon(get_icon("guidata.svg"))
widget.show()
execenv.print("OK")
if __name__ == "__main__":
test_codeeditor()
Array editor¶
import numpy as np
from guidata.env import execenv
from guidata.qthelpers import exec_dialog, qt_app_context
from guidata.widgets.arrayeditor import ArrayEditor
def launch_arrayeditor(data, title="", xlabels=None, ylabels=None, variable_size=False):
"""Helper routine to launch an arrayeditor and return its result"""
dlg = ArrayEditor()
dlg.setup_and_check(
data, title, xlabels=xlabels, ylabels=ylabels, variable_size=variable_size
)
exec_dialog(dlg)
return dlg.get_value()
def test_arrayeditor():
"""Test array editor for all supported data types"""
with qt_app_context():
# Variable size version
for title, data in (
("string array", np.array(["kjrekrjkejr"])),
(
"masked array",
np.ma.array([[1, 0], [1, 0]], mask=[[True, False], [False, False]]),
),
("int array", np.array([1, 2, 3], dtype="int8")),
):
launch_arrayeditor(data, "[Variable size] " + title, variable_size=True)
for title, data in (
("string array", np.array(["kjrekrjkejr"])),
("unicode array", np.array(["ñññéáíó"])),
(
"masked array",
np.ma.array([[1, 0], [1, 0]], mask=[[True, False], [False, False]]),
),
(
"record array",
np.zeros(
(2, 2),
{
"names": ("red", "green", "blue"),
"formats": (np.float32, np.float32, np.float32),
},
),
),
(
"record array with titles",
np.array(
[(0, 0.0), (0, 0.0), (0, 0.0)],
dtype=[(("title 1", "x"), "|i1"), (("title 2", "y"), ">f4")],
),
),
("bool array", np.array([True, False, True])),
("int array", np.array([1, 2, 3], dtype="int8")),
("float16 array", np.zeros((5, 5), dtype=np.float16)),
):
launch_arrayeditor(data, title)
for title, data, xlabels, ylabels in (
("float array", np.random.rand(5, 5), ["a", "b", "c", "d", "e"], None),
(
"complex array",
np.round(np.random.rand(5, 5) * 10)
+ np.round(np.random.rand(5, 5) * 10) * 1j,
np.linspace(-12, 12, 5),
np.linspace(-12, 12, 5),
),
):
launch_arrayeditor(data, title, xlabels, ylabels)
arr = np.zeros((3, 3, 4))
arr[0, 0, 0] = 1
arr[0, 0, 1] = 2
arr[0, 0, 2] = 3
launch_arrayeditor(arr, "3D array")
execenv.print("OK")
if __name__ == "__main__":
test_arrayeditor()
Collection editor¶
import datetime
import numpy as np
from guidata.env import execenv
from guidata.qthelpers import qt_app_context
from guidata.widgets.collectionseditor import CollectionsEditor
try:
from PIL import Image as PILImage
except ImportError:
# PIL is not installed
PILImage = None
def get_test_data():
"""Create test data."""
testdict = {"d": 1, "a": np.random.rand(10, 10), "b": [1, 2]}
testdate = datetime.date(1945, 5, 8)
test_timedelta = datetime.timedelta(days=-1, minutes=42, seconds=13)
try:
import pandas as pd
except (ModuleNotFoundError, ImportError):
test_timestamp = None
test_pd_td = None
test_dtindex = None
test_series = None
test_df = None
else:
test_timestamp = pd.Timestamp("1945-05-08T23:01:00.12345")
test_pd_td = pd.Timedelta(days=2193, hours=12)
test_dtindex = pd.date_range(start="1939-09-01T", end="1939-10-06", freq="12h")
test_series = pd.Series({"series_name": [0, 1, 2, 3, 4, 5]})
test_df = pd.DataFrame(
{
"string_col": ["a", "b", "c", "d"],
"int_col": [0, 1, 2, 3],
"float_col": [1.1, 2.2, 3.3, 4.4],
"bool_col": [True, False, False, True],
}
)
class Foobar:
""" """
def __init__(self):
self.text = "toto"
self.testdict = testdict
self.testdate = testdate
foobar = Foobar()
test_data = {
"object": foobar,
"module": np,
"str": "kjkj kj k j j kj k jkj",
"unicode": "éù",
"list": [1, 3, [sorted, 5, 6], "kjkj", None],
"tuple": ([1, testdate, testdict, test_timedelta], "kjkj", None),
"dict": testdict,
"float": 1.2233,
"int": 223,
"bool": True,
"array": np.random.rand(10, 10).astype(np.int64),
"masked_array": np.ma.array(
[[1, 0], [1, 0]], mask=[[True, False], [False, False]]
),
"1D-array": np.linspace(-10, 10).astype(np.float16),
"3D-array": np.random.randint(2, size=(5, 5, 5)).astype(np.bool_),
"empty_array": np.array([]),
"date": testdate,
"datetime": datetime.datetime(1945, 5, 8, 23, 1, 0, int(1.5e5)),
"timedelta": test_timedelta,
"complex": 2 + 1j,
"complex64": np.complex64(2 + 1j),
"complex128": np.complex128(9j),
"int8_scalar": np.int8(8),
"int16_scalar": np.int16(16),
"int32_scalar": np.int32(32),
"int64_scalar": np.int64(64),
"float16_scalar": np.float16(16),
"float32_scalar": np.float32(32),
"float64_scalar": np.float64(64),
"bool_scalar": bool,
"bool__scalar": np.bool_(8),
"timestamp": test_timestamp,
"timedelta_pd": test_pd_td,
"datetimeindex": test_dtindex,
"series": test_series,
"ddataframe": test_df,
"None": None,
"unsupported1": np.arccos,
# Test for Issue #3518
"big_struct_array": np.zeros(
1000, dtype=[("ID", "f8"), ("param1", "f8", 5000)]
),
}
if PILImage is not None:
image = PILImage.fromarray(
np.random.randint(256, size=(100, 100)).astype(np.uint8)
).convert("P")
test_data["image"] = image
return test_data
def test_collectionseditor():
"""Test Collections editor."""
with qt_app_context(exec_loop=True):
dialog = CollectionsEditor()
dialog.setup(get_test_data())
dialog.show()
execenv.print("OK")
if __name__ == "__main__":
test_collectionseditor()
Dataframe editor¶
import numpy as np
import pytest
try:
import pandas as pd
import pandas.testing as pdt
from guidata.widgets.dataframeeditor import DataFrameEditor
except ImportError:
# pandas is not installed
pd = pdt = DataFrameEditor = None
from guidata.env import execenv
from guidata.qthelpers import exec_dialog, qt_app_context
@pytest.mark.skipif(pd is None, reason="pandas is not installed")
def test_dataframeeditor():
"""DataFrame editor test"""
def test_edit(data, title="", parent=None):
"""Test subroutine"""
dlg = DataFrameEditor(parent=parent)
if dlg.setup_and_check(data, title=title):
exec_dialog(dlg)
return dlg.get_value()
else:
import sys
sys.exit(1)
with qt_app_context():
df1 = pd.DataFrame(
[
[True, "bool"],
[1 + 1j, "complex"],
["test", "string"],
[1.11, "float"],
[1, "int"],
[np.random.rand(3, 3), "Unkown type"],
["Large value", 100],
["áéí", "unicode"],
],
index=["a", "b", np.nan, np.nan, np.nan, "c", "Test global max", "d"],
columns=[np.nan, "Type"],
)
out = test_edit(df1)
pdt.assert_frame_equal(df1, out)
result = pd.Series([True, "bool"], index=[np.nan, "Type"], name="a")
out = test_edit(df1.iloc[0])
pdt.assert_series_equal(result, out)
df1 = pd.DataFrame(np.random.rand(100100, 10))
out = test_edit(df1)
pdt.assert_frame_equal(out, df1)
series = pd.Series(np.arange(10), name=0)
out = test_edit(series)
pdt.assert_series_equal(series, out)
execenv.print("OK")
if __name__ == "__main__":
test_dataframeeditor()
Import wizard¶
import pytest
from guidata.env import execenv
from guidata.qthelpers import exec_dialog, qt_app_context
from guidata.widgets.importwizard import ImportWizard
@pytest.fixture()
def text():
"""Return text to test"""
return "17/11/1976\t1.34\n14/05/09\t3.14"
def test_importwizard(text):
"""Test"""
with qt_app_context():
dialog = ImportWizard(None, text)
if exec_dialog(dialog):
execenv.print(dialog.get_data())
execenv.print("OK")
if __name__ == "__main__":
test_importwizard("17/11/1976\t1.34\n14/05/09\t3.14")
Icon browser¶
The icon browser is a utility widget for browsing and exploring icon collections in directories. It is useful for developers managing icons for their applications and libraries.
Features:
Browse icon collections with tree view for folder navigation
Adjustable thumbnail sizes (16-256 pixels) via toolbar
Single-click on icons to open file location in system file explorer
Support for PNG, SVG, ICO, JPG, GIF, and BMP formats
Responsive grid layout that adapts to window size
Refresh action to reload current folder after external changes
Command-line usage:
$ # Launch with folder selection dialog
$ giconbrowser
$ # Launch with a specific folder
$ giconbrowser /path/to/icons
Programmatic usage:
from __future__ import annotations
import os.path as osp
from guidata.env import execenv
from guidata.qthelpers import qt_app_context
from guidata.widgets.iconbrowser import IconBrowserWindow
def get_guidata_icons_path() -> str:
"""Get the path to guidata's icon directory.
Returns:
Path to the icons directory
"""
import guidata
guidata_path = osp.dirname(guidata.__file__)
icons_path = osp.join(guidata_path, "data", "icons")
return icons_path
def test_iconbrowser():
"""Test the icon browser widget."""
with qt_app_context(exec_loop=not execenv.unattended):
icons_dir = get_guidata_icons_path()
window = IconBrowserWindow(init_folder=icons_dir)
window.resize(900, 600)
window.show()
if not execenv.unattended:
window.activateWindow()
if __name__ == "__main__":
test_iconbrowser()