ccu.fancyplots package

GUI elements for designing free energy diagrams.

The GUI logic is contained within ccu.fancyplots.gui. A Python interface to the free energy diagram plotting logic is available via ccu.fancyplots.gui.plotting.generate_figure().

Subpackages

Submodules

ccu.fancyplots.cli module

Command-line interface for FancyPlots.

ccu.fancyplots.data module

Classes for the storage of FancyPlots relevant data.

The class ccu.fancyplots.data.FancyCache describes how data is imported to and exported from FancyPlots.

The class ccu.fancyplots.data.FEDData defines how free energy diagram is stored.

The class ccu.fancyplots.data.FormattingParameters defines how plot formatting parameters are stored.

The class ccu.fancyplots.data.Annotation defines how plot annotations are stored.

Examples

The internal data from FancyPlots can be accessed via the attribute ccu.fancyplots.gui.root.FancyPlotsGUI.cache and dumped into a human-readable form via the following idiom:

>>> import json
>>> from pathlib import Path
>>> from ccu.fancyplots.data import DEFAULT_PARAMETERS
>>> from ccu.fancyplots.data import FancyCache
>>> data = {
...     "energy_data": [
...         [0, 0.2, 0.33, -0.5],
...         [0, -0.1, 0.25, 0],
...     "mechanism": ["*", "*CHOO", "*CO", "CO"],
...     "legend_labels: ["Cu(111)", "Cu-NP"],
>>> annotations = []
>>> formatting_parameters = DEFAULT_PARAMETERS
>>> cache = FancyCache(
...     formatting_parameters,
...     diagram_data=data,
...     annotations=annotations,
...)
>>> with Path("fancy.cache").open(
...     mode="w", encoding="utf-8"
... ) as file:  
...     _ = json.dump(cache, file, indent=2)

The same file (fancy.cache) can be loaded into a convenient format for FancyPlots via the following idiom:

>>> import json
>>> from pathlib import Path
>>> from ccu.fancypylots.data import FancyCache
>>> with Path("fancy.cache").open(  
...     mode="r", encoding="utf-8"
... ) as file:
...     cache = FancyCache(**json.load(file))
class ccu.fancyplots.data.Annotation(color: str = 'k', fontsize: float = 11.200000000000001, text: str = '', x: float = 0.0, y: float = 0.0)[source]

Bases: NamedTuple

A free energy diagram annotation.

Variables:
  • color (str) – The color to use for the annotation.

  • fontsize (float) – The fontsize to use for the annotation.

  • text (str) – The annotation text.

  • x (float) – The x-coordinate of the annotation.

  • y (float) – The y-coordinate of the annotation.

Create new instance of Annotation(color, fontsize, text, x, y)

color: str

Alias for field number 0

fontsize: float

Alias for field number 1

text: str

Alias for field number 2

x: float

Alias for field number 3

y: float

Alias for field number 4

class ccu.fancyplots.data.FEDData[source]

Bases: TypedDict

Energies and metadata for a free energy diagram.

Variables:
  • energy_data (list[list[float | None]]) – A list of lists. Each list defines energies for each step in the mechanism.

  • mechanism (list[str]) – The labels for each mechanism step.

  • legend_labels (list[str | None]) – The legend labels for each pathway.

Valid ccu.fancyplots.data.FEDData instances should satisfy the following condition for seamless use with FancyPlots:

energy_data: list[list[float | None]]
legend_labels: list[str | None]
mechanism: list[str]
class ccu.fancyplots.data.FancyCache(style_parameters: FormattingParameters, diagram_data: FEDData, annotations: list[Annotation])[source]

Bases: object

The data model for caching/loading data into FancyPlots.

Variables:
annotations: list[Annotation]
diagram_data: FEDData
save(savename: str | Path = 'cache..fancy') None[source]

Save the FancyCache.

Parameters:
  • savename – The filename in which to save the cache. Defaults to

  • f”cache.{FANCY_EXTENSION}”.

style_parameters: FormattingParameters
class ccu.fancyplots.data.FormattingParameters[source]

Bases: TypedDict

The formatting parameters to use to plot free energy diagrams.

Keys:

boxsize: tuple[float, float]
colors: tuple[str, ...]
dpi: int
font: str
fontsize: float
legend_loc: str
linewidth: float
markeredgewidth: float
markersize: int
savename: str
tick_dec: float
tick_double: bool
tick_loc: str
tick_min: float
title: str
visual: bool
xlabel: str
xlim: None | tuple[float, float]
xscale: str
ylabel: str
ylim: None | tuple[float, float]
yscale: str

ccu.fancyplots.styles module

Tkinter styles for FancyPlots.

ccu.fancyplots.styles.initialize_styles() None[source]

Create custom styles for themed widgets.

ccu.fancyplots.validation module

Classes, protocols, and functions for data validation.

In particular, this module defines the Validator and Serializer protocols that are used to validate user input from GUI widgets and serialize Python values for display in GUI widgets, respectively. Validators return a boolean indicating the validity of an input with the option to convert the input to the desired type.

Example: A simple validator that only accepts the number 5

from ccu.fancyplots.validation import ValidationError

def simple_validator(value: Any, validate_only: bool = True):
    valid value == 5

    if validate_only:
        return valid

    if valid:
        return 5

    raise ValidationError("The value is not 5")

simple_validator(5)
True

validator_from_type() creates simple wrappers around any callable that can accept a string and return a converted value. For simple types (e.g., str, int, float), creating a validator is as simple as:

from ccu.fancyplots.validation import validator_from_type

validator = validator_from_type(str)

For creating Validators from type hints, this module defines the convenience function type_hint_to_validator():

from ccu.fancyplots.validation import type_hint_to_validator

validator = type_hint_to_validator(list[str] | None, "")
validator("1")
False
validator("1", validate_only=False)
...ValidationError: Unable to validate the value
validator("1,2,3")
True
validator("1,2,3", validator_only=False)
[1, 2, 3]
# ``ccu.fancyplots`` interprets empty GUI fields as unset, so for
# convenience, "" is a valid None type
validator("", validator_only=False)
None

Note

Validation is only supported for primitive values, tuples/lists of primitive values, and unions of either two:

union_type = str | None  # okay
union_type = tuple[str]  # okay
union_type = int  # okay
union_type = tuple[float] | None  # okay
union_type = list[str]  # okay
union_type = tuple[tuple[str]]  # not okay
union_type = tuple[int | str]  # not okay

Note

The order that types are specified in the union matters.

Validation is tried in left-to-right order. That is, if the type hint is str | int, then the validation first attempts to convert the value into a string and then into an integer. This is especially important for unions involving strings, since every object can be converted into a string.

Custom validators can be constructed using some of the other utility methods. For example, with string_to_sequence(), one can do:

>>> from ccu.fancyplots.validation import (
...     string_to_sequence,
...     validator_from_type,
... )
>>> sequence_from_type = string_to_sequence(
...     element_type=int, sequence_type=tuple, delimiter="-"
... )
>>> tuple_validator = validator_from_type(sequence_from_type)
>>> tuple_validator("1-2-3")
True
>>> tuple_validator("This should return False")
False
>>> tuple_validator("1-2-3", validate_only=False)
(1, 2, 3)

Simple unions can be handled as well:

>>> from ccu.fancyplots.validation import (
...     string_to_union,
...     validator_from_type,
... )
>>> union_from_type = string_to_union(int | str)
>>> union_validator = validator_from_type(union_from_type)
>>> union_validator("1")
True
>>> union_validator("Okay")
True
>>> union_validator("This should return False")
False
>>> union_validator("1", validate_only=False)
1
>>> union_validator("Okay", validate_only=False)
True

This module also provides a convenience Validator and Serializer, no_validation_validator() and default_serializer(), respectively.

The highlight_and_warn() function is a handler for when invalid text is entered into a ttk.Entry.

See also

FancyFormatFrame

class ccu.fancyplots.validation.Serializer(*args, **kwargs)[source]

Bases: Protocol, Generic[_T]

Serialize a value.

exception ccu.fancyplots.validation.ValidationError[source]

Bases: ValueError

Invalid value.

class ccu.fancyplots.validation.Validator(*args, **kwargs)[source]

Bases: Protocol, Generic[_T]

Callables which can validate and convert values.

Adherents should raise a ValidationError if validate_only is False and value is invalid.

ccu.fancyplots.validation.default_serializer(value: _T, *, delimiter: str = ',') str[source]

Serialize values as strings.

Parameters:
  • value – The value to be serialized.

  • delimiter – A character to be used to delimit list values.

Returns:

A string representation of value.

ccu.fancyplots.validation.highlight_and_warn(event: Event) None[source]

Highlight the entry containing invalid data and warn the user.

Parameters:

event – The triggering event.

ccu.fancyplots.validation.no_validation_validator(value: _T, validate_only: Literal[False]) _T[source]

Always validate the value.

Parameters:
  • value – The value to validate.

  • validate_only – Whether to only check the value for validity or also convert the value to a valid type.

Returns:

_description_

ccu.fancyplots.validation.string_to_primitive(type_hint: type[Primitive]) Callable[[str], Primitive][source]

Return a function that parses a string into a Python primitive.

Note that the empty string is parsed as None.

Parameters:

type_hint – One of str, int, float, bool, or None.

Returns:

A Validator capable of validating Python primitives from strings.

ccu.fancyplots.validation.string_to_sequence(element_type: Validator[_T], sequence_type: type[list] | type[tuple], delimiter: str = ',') Callable[[str], tuple[_T, ...]][source]

Return a function that parses a string into a sequence.

Parameters:
  • element_type – The type into which elements of the sequence should be cast.

  • sequence_type – The type of sequence to be constructed. Must be either list or tuple.

  • delimiter – A character used to split the string into a sequence.

Returns:

A function that can be supplied to validator_from_type() to produce a Validator.

ccu.fancyplots.validation.string_to_union(validators: list[Validator[_T]]) Callable[[str], _T][source]

Return a function that tries to validate/convert a string into a union.

Parameters:

validators – A ccu.fancyplots.validation.Validator instances corresponding to the union.

Returns:

A Callable that can be used to convert a str into a member type of the union.

ccu.fancyplots.validation.type_hint_to_validator(type_hint: type[_T], label: str) Validator[_T][source]

Return a Validator from a type hint.

Parameters:
  • type_hint – A bare (no annotations) type hint such as str, int, None, tuple[int], int | None.

  • label – The name of the parameter to which the type hint belongs.

Returns:

A Validator capable of validating a value against the type hint provided.

Examples

>>> from ccu.fancyplots.validation import type_hint_to_validator
>>> validator = type_hint_to_validator(int | str, "")
>>> validator("1")
True
>>> validator("Okay")
True
>>> validator("This should return False")
True
>>> validator("1", validate_only=False)
1
>>> validator("Okay", validate_only=False)
"Okay"
ccu.fancyplots.validation.validator_from_type(from_type: Callable[[str], _T]) Validator[_T][source]

Create a Validator from a type (or factory function).

Parameters:

from_type – A function that can accept a string as input and return an object of the desired type.

Returns:

A Validator for objects of the type produced by from_type.