|
5 | 5 | extension: .md |
6 | 6 | format_name: markdown |
7 | 7 | format_version: '1.3' |
8 | | - jupytext_version: 1.14.0 |
| 8 | + jupytext_version: 1.13.7 |
9 | 9 | kernelspec: |
10 | | - display_name: Python 3 (ipykernel) |
| 10 | + display_name: Python 3 |
11 | 11 | language: python |
12 | 12 | name: python3 |
13 | 13 | --- |
@@ -231,6 +231,44 @@ p.edit_traits() |
231 | 231 | <!-- #region slideshow={"slide_type": "slide"} --> |
232 | 232 | ## Specifying an editor |
233 | 233 |
|
| 234 | +- Editors: encapsulate display instructions for a trait type |
| 235 | + - Hide GUI-toolkit code behind an abstraction layer |
| 236 | + - All standard traits has a predefined editor that is automatically |
| 237 | + displayed when the trait is displayed, unless overridden |
| 238 | +<!-- #endregion --> |
| 239 | + |
| 240 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 241 | +## Examples |
| 242 | + |
| 243 | +This code automatically uses `StrEditor`, the default for `Str` traits: |
| 244 | +<!-- #endregion --> |
| 245 | + |
| 246 | +```python |
| 247 | +class Stringy(HasStrictTraits): |
| 248 | + characters = Str() |
| 249 | + |
| 250 | +s = Stringy(characters='<b>Stringy characters</b>') |
| 251 | +s.edit_traits( |
| 252 | + view=View( |
| 253 | + Item("characters") |
| 254 | + ) |
| 255 | +) |
| 256 | +``` |
| 257 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 258 | +This code uses an HTMLEditor: |
| 259 | +<!-- #endregion --> |
| 260 | +```python |
| 261 | +from traitsui.api import HTMLEditor |
| 262 | +s.edit_traits( |
| 263 | + view=View( |
| 264 | + Item("characters", editor=HTMLEditor()) |
| 265 | + ) |
| 266 | +) |
| 267 | +``` |
| 268 | + |
| 269 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 270 | + |
| 271 | +## A few useful editors |
234 | 272 | - We illustrate the powerful `InstanceEditor` here |
235 | 273 | - Consider the following |
236 | 274 |
|
@@ -313,9 +351,136 @@ sam = Person(name='Sam', age=29, bff=frodo) |
313 | 351 | sam.edit_traits() |
314 | 352 | ``` |
315 | 353 |
|
| 354 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 355 | +- Another useful editor allows us to interface with `DataFrame`s |
| 356 | +<!-- #endregion --> |
| 357 | + |
| 358 | +```python |
| 359 | +import pandas as pd |
| 360 | +from traits.api import Event, Instance, Int |
| 361 | +from traitsui.api import ModelView |
| 362 | +from traitsui.ui_editors.data_frame_editor import DataFrameEditor |
| 363 | + |
| 364 | +class FramedData(HasStrictTraits): |
| 365 | + data = Instance(pd.DataFrame) |
| 366 | + |
| 367 | + def _data_default(self): |
| 368 | + return pd.DataFrame([ |
| 369 | + {'A': 5, 'B': 0, 'C': 3, 'D': 3}, |
| 370 | + {'A': 7, 'B': 9, 'C': 3, 'D': 5}, |
| 371 | + {'A': 2, 'B': 4, 'C': 7, 'D': 6} |
| 372 | + ]) |
| 373 | + |
| 374 | +class FramedDataView(ModelView): |
| 375 | + model = Instance(FramedData) |
| 376 | + |
| 377 | + view = View( |
| 378 | + Item("model.data", editor=DataFrameEditor(editable=True)) |
| 379 | + ) |
| 380 | + |
| 381 | +FramedDataView(model=FramedData()).edit_traits() |
| 382 | +``` |
| 383 | + |
| 384 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 385 | +## Enter plotting |
| 386 | +- Another useful editor is the `MplFigureEditor` |
| 387 | +- Allows interacting with `matplotlib.figure.Figure` instances |
| 388 | +- Included in the `ets_tutorial` package bundled in this repository |
| 389 | +<!-- #endregion --> |
| 390 | + |
| 391 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 392 | +Example: |
| 393 | +<!-- #endregion --> |
| 394 | +```python |
| 395 | +from matplotlib.figure import Figure |
| 396 | +import numpy as np |
| 397 | +from skimage.data import chelsea |
| 398 | +from traits.api import Array, HasStrictTraits, Instance |
| 399 | +from traitsui.api import View, Item |
| 400 | + |
| 401 | +from ets_tutorial.util.mpl_figure_editor import MplFigureEditor |
| 402 | + |
| 403 | +class ImageViewer(HasStrictTraits): |
| 404 | + data = Array() |
| 405 | + |
| 406 | + figure = Instance(Figure) |
| 407 | + |
| 408 | + traits_view = View( |
| 409 | + Item("figure", editor=MplFigureEditor(), show_label=False) |
| 410 | + ) |
| 411 | + |
| 412 | + def _data_default(self): |
| 413 | + return chelsea() |
| 414 | + |
| 415 | + def _figure_default(self): |
| 416 | + figure = Figure() |
| 417 | + axes = figure.add_subplot(111) |
| 418 | + axes.imshow(chelsea()) |
| 419 | + return figure |
| 420 | + |
| 421 | +ImageViewer().edit_traits() |
| 422 | +``` |
| 423 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 424 | +## The ModelView object: |
| 425 | +- We want our science model to be free of UI code |
| 426 | +- But it's still useful for models and views to responde to changes to one |
| 427 | + another -- `ModelView`s |
| 428 | +- `ModelView`s also monitor UI toolkit events like window creation, |
| 429 | + closing, user clicking OK or Cancel buttons |
| 430 | +- Example: |
| 431 | +<!-- #endregion --> |
| 432 | + |
| 433 | +```python |
| 434 | +from traits.api import observe |
| 435 | +class Image(HasStrictTraits): |
| 436 | + data = Array() |
| 437 | + |
| 438 | + def _data_default(self): |
| 439 | + return chelsea() |
| 440 | + |
| 441 | +class ImageView(ModelView): |
| 442 | + model = Instance(Image) |
316 | 443 |
|
| 444 | + figure = Instance(Figure) |
| 445 | + |
| 446 | + view = View( |
| 447 | + Item("figure", editor=MplFigureEditor(), show_label=False) |
| 448 | + ) |
| 449 | + |
| 450 | + @observe("model.data") |
| 451 | + def build_mpl_figure(self, event): |
| 452 | + figure = Figure() |
| 453 | + axes = figure.add_subplot(111) |
| 454 | + axes.imshow(self.model.data) |
| 455 | + self.figure = figure |
| 456 | + |
| 457 | +``` |
| 458 | + |
| 459 | +```python |
| 460 | +image = Image() |
| 461 | +image_view = ImageView(model=image) |
| 462 | +image_view.edit_traits() |
| 463 | +``` |
| 464 | + |
| 465 | +```python |
| 466 | +from skimage.data import astronaut |
| 467 | +image.data = astronaut() |
| 468 | +``` |
317 | 469 |
|
318 | 470 | <!-- #region slideshow={"slide_type": "slide"} --> |
| 471 | +## Exercise time! |
| 472 | +- Starting from where we left off in Stage 2.1: |
| 473 | + - Create a `ModelView` for the `ImageFile` object that displays its filepath |
| 474 | + (readonly), and the image array in a matplotlib figure |
| 475 | + - Ensure figure is updated if the `filepath` attribute of `ImageFile` is |
| 476 | + modified |
| 477 | + - Create a `ModelView` for the `ImageFolder` object that displays the directory |
| 478 | + (readonly) and the `DataFrame` |
| 479 | + - Bonus points: |
| 480 | + - What mechanism would we use to hide the `DataFrame` if the directory doesn't have any images |
| 481 | + and instead show a helpful message? |
| 482 | + - Hint: keyword arguments for `Item` |
| 483 | +<!-- #endregion --> |
319 | 484 | ## Toolkit selection |
320 | 485 |
|
321 | 486 | - TraitsUI supports: Qt or wxPython |
@@ -350,3 +515,7 @@ ETSConfig.toolkit = 'qt' |
350 | 515 |
|
351 | 516 |
|
352 | 517 | <!-- #endregion --> |
| 518 | + |
| 519 | +```python |
| 520 | + |
| 521 | +``` |
0 commit comments