polychron.util
Module
MonotonicTimer
A monotonic timer, for capturing execution time for sections of code
start
start() -> 'MonotonicTimer'
Record the start of the timed period
Returns:
Type | Description |
---|---|
'MonotonicTimer'
|
returns itself, so that .start can be chained on the ctor. |
stop
stop() -> 'MonotonicTimer'
Record the end of the timed period
Returns:
Type | Description |
---|---|
'MonotonicTimer'
|
returns itself, so that .elapsed/elapsed_ns can be chained on calls to stop. |
Raises:
Type | Description |
---|---|
RuntimeError
|
stop must be called after start |
elapsed_ns
elapsed_ns() -> int
Get the elapsed time in nanoseconds
Timing precision is platform specific, see the time.monotonic_ns docs
Returns:
Type | Description |
---|---|
int
|
Elapsed time between the most recent calls to start and stop in nanoseconds |
Raises:
Type | Description |
---|---|
RunmtimeError
|
start() and stop() must have been called before elapsed_ns |
elapsed
elapsed() -> float
Get the elapsed time in seconds.
Timing precision is platform specific, see the time.monotonic_ns docs
Returns:
Type | Description |
---|---|
float
|
Elapsed time between the most recent calls to start and stop in fractional seconds |
Raises:
Type | Description |
---|---|
RunmtimeError
|
start() and stop() must have been called before elapsed_ns |
trim
trim(im_trim: Image) -> Image.Image
Trims images down, cropping out dark background (<= 100/255 in all channels) unless the whole image is considerd dark (<= 100/255 in all channels)
Parameters:
Name | Type | Description | Default |
---|---|---|---|
im_trim
|
Image
|
Input image to trim |
required |
Returns:
Type | Description |
---|---|
Image
|
Potentially cropped version on im_trim |
bbox_from_polygon
bbox_from_polygon(points_str: str) -> list[float]
Get the axis aligned bounding box from an svg polygon points attribute, supporting rectangles (box) and kites (diamond).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
points_str
|
str
|
the points attribute from an svg |
required |
Returns:
Type | Description |
---|---|
list[float]
|
The 4 floating point coordinates defining the axis aligned bounding box for click detection, as |
Todo
- Gracefully handle bad input strings
- Todo pass in the transform values as an alt to -1*?
bbox_from_ellipse
bbox_from_ellipse(cx: float, cy: float, rx: float, ry: float) -> list[float]
Get the axis aligned bounding box for an ellipse, using the ellipse parameters from svg attributes.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
cx
|
float
|
the cx attribute from the ellipse, as a float |
required |
cy
|
float
|
the cy attribute from the ellipse, as a float |
required |
rx
|
float
|
the rx attribute from the ellipse, as a float |
required |
ry
|
float
|
the ry attribute from the ellipse, as a float |
required |
Returns:
Type | Description |
---|---|
list[float]
|
The 4 floating point coordinates defining the axis aligned bounding box for click detection, as |
Todo
- Gracefully handle bad inputs
- Todo pass in the transform values as an alt to -1*?
rank_func
rank_func(tes: dict[str, list[str]], dot_str: str) -> str
adds strings into dot string to make nodes of the same group the same rank
Parameters:
Name | Type | Description | Default |
---|---|---|---|
tes
|
dict[str, list[str]]
|
a dictionary |
required |
dot_str
|
str
|
The original dot/gv string |
required |
Returns:
Type | Description |
---|---|
str
|
The mutated dot/gv string |
Todo
- Rename parameters and variables
- Use for key, x_rank in tes.items()
- find the closing } of the digraph instead of always getting rid of the final 2 chars
- use ",".join(x_rank) and an fstring
- Close the digraph on it's own line (i.e. add a newline at the end / don't include the [:-1])
node_coords_from_svg_string
node_coords_from_svg_string(svg_string: str) -> tuple[dict[str, list[float]], list[float]]
Get the coordinates of each node from a string containing the SVG representation of a graphviz DiGraph.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
svg_string
|
str
|
The SVG version of a DiGraph produced by graphviz |
required |
Returns:
Type | Description |
---|---|
tuple[dict[str, list[float]], list[float]]
|
A tuple of a dictionary of axis aligned bounding boxes for each node |
Note
This function depends upon graphviz producing svg files with the expected structure
node_coords_from_svg
node_coords_from_svg(svg_file: str | Path | IO[str]) -> tuple[dict[str, list[float]], list[float]]
Get the coordinates of each node from a Directed Acyclic Graph from an SCG file on disk
Parameters:
Name | Type | Description | Default |
---|---|---|---|
svg_file
|
str | Path | IO[str]
|
path to the svg file on disk, or an open file handle |
required |
Returns:
Type | Description |
---|---|
tuple[dict[str, list[float]], list[float]]
|
A tuple of a dictionary of axis aligned bounding boxes for each node |
node_coords_from_dag
node_coords_from_dag(graph: DiGraph | Dot) -> tuple[dict[str, list[float]], list[float]]
Get the coordinates of each node from a Directed Acyclic Graph via SVG rendering in graphviz.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
graph
|
DiGraph | Dot
|
The networkx or pydot Graph |
required |
Returns:
Type | Description |
---|---|
tuple[dict[str, list[float]], list[float]]
|
A tuple of a dictionary of axis aligned bounding boxes for each node |
node_coords_check
node_coords_check(coords: tuple[float, float], img_size: tuple[int, int], img_scale: float, node_coords: dict[str, list[float]], node_coords_scale: list[float]) -> str | None
Return the node at the provided coordinates, using data extracted from an svg, with potential zooming and panning of an image
Parameters:
Name | Type | Description | Default |
---|---|---|---|
coords
|
tuple[float, float]
|
the (x, y) target coordinates in UI-space, accounting for panning |
required |
img_size
|
tuple[int, int]
|
the (w, h) of the image on disk |
required |
img_scale
|
float
|
the zoom level for the image in UI-space |
required |
node_coords
|
dict[str, list[float]]
|
the axis aligned bounding box coordinates in svg-space for each node |
required |
node_coords_scale
|
list[float]
|
The (w, h) of the svg for coordinate translation |
required |
Returns:
Type | Description |
---|---|
str | None
|
the id of the node selected, or None |
phase_info_func
phase_info_func(file_graph: DiGraph) -> Tuple[dict[Any, Any], list[Any], list[Any], list[dict[Any, Any]]]
Returns a dictionary of phases and nodes in each phase
Parameters:
Name | Type | Description | Default |
---|---|---|---|
file_graph
|
DiGraph
|
A networkx graph to extract phase information from |
required |
Returns:
Type | Description |
---|---|
dict[Any, Any]
|
A tuple of results: |
list[Any]
|
|
list[Any]
|
|
list[dict[Any, Any]]
|
|
Tuple[dict[Any, Any], list[Any], list[Any], list[dict[Any, Any]]]
|
|
Todo
This has not been fully-reimplemented for cases where stratigraphic data was provided via .dot/.gv file, see FILE_INPUT
edge_of_phase
edge_of_phase(test1: list[Any], pset: list[str], node_list: list[Any], node_info: list[dict[str[Any]]]) -> tuple[list[str], list[str], Iterable[str], list[tuple[Any, str]], dict[str, list[str]]]
Find nodes on edge of each phase
Parameters:
Name | Type | Description | Default |
---|---|---|---|
test1
|
list[Any]
|
a list of graph nodes (contexts and phases boundary nodes) ordered as a line_graph |
required |
pset
|
list[str]
|
a list of (unique) groups/phases |
required |
node_list
|
list[Any]
|
a list of node labels |
required |
node_info
|
list[dict[str[Any]]]
|
a list of node attribute dictionaries, in the same order as node_list |
required |
Returns:
Type | Description |
---|---|
list[str]
|
A tuple of: |
list[str]
|
|
Iterable[str]
|
|
list[tuple[Any, str]]
|
|
dict[str, list[str]]
|
|
tuple[list[str], list[str], Iterable[str], list[tuple[Any, str]], dict[str, list[str]]]
|
|
Todo
- This has not been fully-reimplemented for cases where stratigraphic data was provided via .dot/.gv file, see FILE_INPUT
- Returning the keys and dictionary is redundant - only need to return the dict.
node_del_fixed
node_del_fixed(graph: DiGraph, node: str) -> nx.DiGraph
Remove a node from the graph, replacing edges where possible.
A new edge will not be created if the relative relationship between two nodes is already provided through another context.
I.e. given the following graph of 4 nodes
flowchart LR
a --> b0
a --> b1
b0 --> c
b1 --> c
Deleting b0
will produce the following, without a direct edge from a --> c
flowchart LR
a --> b1
b1 --> c
Parameters:
Name | Type | Description | Default |
---|---|---|---|
graph
|
DiGraph
|
The graph to modify |
required |
node
|
str
|
the name of the node to be removed |
required |
Returns:
Type | Description |
---|---|
DiGraph
|
The mutated graph |
Raises:
Type | Description |
---|---|
NetworkXError
|
If the provided node is not a member of the graph |
Todo
- The input parameter is mutated, and returned by the function. This should probably either return a mutated copy or not return the graph.
all_node_info
all_node_info(node_list: List[Any], x_image: List[str], node_info: List[Any]) -> List[Any]
obtains node attributes from original dot file
phase_length_finder
phase_length_finder(con_1: str, con_2: str, group_limits: dict[str, list[float]]) -> List[Any]
Find the group/phase length between any two contexts or phase boundaries
Parameters:
Name | Type | Description | Default |
---|---|---|---|
con_1
|
str
|
Context or phase boundary node id to find the phase length between |
required |
con_2
|
str
|
Context or phase boundary node id to find the phase length between |
required |
group_limits
|
dict[str, list[float]]
|
Dictionary containing a list of group limits from MCMC calibration per context/phase_boundary label in the chronological_dag |
required |
Returns:
Type | Description |
---|---|
List[Any]
|
List of potential phase durations in years. |
List[Any]
|
An empty list is returned if either context label is not present in the mcmc calibration data. |
List[Any]
|
If the length of samples is not the same for the provided contexts, the shorter value is used. This should not occur in regular usage. |
Todo
- Special case handling when con_1 == con_2?
imagefunc
imagefunc(dotfile: Any) -> Any
Sets note attributes to a dot string from the provided file
phase_relabel
phase_relabel(graph: DiGraph) -> nx.DiGraph
Relabels the phase labels to be alphas and betas, for display only, still refer to them with a's and b's
Parameters:
Name | Type | Description | Default |
---|---|---|---|
graph
|
DiGraph
|
The graph to modify |
required |
Returns:
Type | Description |
---|---|
DiGraph
|
The mutated graph |
Todo
- The input parameter is mutated, and returned by the function. This should probably either return a mutated copy or not return the graph.
- Ideally this should not create labels for nodes which do not start with a_/b_ but contain them, and ideally should only mutate for valid groups, in case user provided context labels include a_ (not currently prevented, although it may be as a workaround)
alp_beta_node_add
alp_beta_node_add(group: str, graph: DiGraph) -> None
Adds an alpha and beta node for the named group to the graph
Parameters:
Name | Type | Description | Default |
---|---|---|---|
group
|
str
|
The group label to add alpha and beta nodes for |
required |
graph
|
DiGraph
|
The graph to be mutated |
required |
phase_labels
phase_labels(phi_ref: list[str], post_group: list[Literal['abutting', 'gap', 'overlap', 'end'] | GroupRelationship], phi_accept: list[list[float]], all_samps_phi: list[list[float]]) -> tuple[list[str], dict[str, list[float]], dict[str, list[float]]]
Provides group/phase limits for a group/phase
Parameters:
Name | Type | Description | Default |
---|---|---|---|
phi_ref
|
list[str]
|
Ordered list of group/phase labels |
required |
post_group
|
list[Literal['abutting', 'gap', 'overlap', 'end'] | GroupRelationship]
|
Ordered list containing the relationship between the nth group, and the n+1th group |
required |
phi_accept
|
list[list[float]]
|
Accepted group boundaries from MCMC simulation. The length of the outer list depends on the values of post_group |
required |
all_samps_phi
|
list[list[float]]
|
all samples for group boundaries from MCMC, including rejected samples. The length of the outer list depends on the values of post_group |
required |
Returns:
Type | Description |
---|---|
list[str]
|
A 3-element tuple of: |
dict[str, list[float]]
|
|
dict[str, list[float]]
|
|
tuple[list[str], dict[str, list[float]], dict[str, list[float]]]
|
|
del_empty_phases
del_empty_phases(phi_ref: list[str], del_phase: set[str], phasedict: dict[tuple[str, str], str]) -> list[list[str]]
Checks for any phase rels that need changing due to missing dates
Parameters:
Name | Type | Description | Default |
---|---|---|---|
phi_ref
|
list[str]
|
Ordered list of group/phase labels |
required |
del_phase
|
set[str]
|
Groups/Phases which should be removed |
required |
phasedict
|
dict[tuple[str, str], str]
|
Dictionary of directed relationships between groups |
required |
Returns:
Type | Description |
---|---|
list[list[str]]
|
List of pairs of group labels which a new 'gap' relationship should be created for |
Todo
Should duplicates be removed from the retuned list?
group_rels_delete_empty
group_rels_delete_empty(file_graph: DiGraph, new_group_rels: list[list[str]], p_list: list[tuple[str, str]], phasedict: dict[tuple[str, str], str], phase_nodes: list[str], graph_data: tuple[DiGraph, list[list[Any]], list[Any], list[Any]]) -> Tuple[nx.DiGraph, List[str], Dict[str, str]]
Adds edges between phases that had gaps due to no contexts being left in them
Parameters:
Name | Type | Description | Default |
---|---|---|---|
file_graph
|
DiGraph
|
The input graph |
required |
new_group_rels
|
list[list[str]]
|
list of new edges to create. Each element must be a list/tuple of 2 group labels. |
required |
p_list
|
list[tuple[str, str]]
|
a list of (unique) groups/phases, each contianing 2 elements. |
required |
phasedict
|
dict[tuple[str, str], str]
|
A dictionary containing the type of relationship between two phases |
required |
phase_nodes
|
list[str]
|
a list of group/phase node labels, which is modified to include newly created nodes |
required |
graph_data
|
tuple[DiGraph, list[list[Any]], list[Any], list[Any]]
|
A collection of graph_data information |
required |
Returns:
Type | Description |
---|---|
DiGraph
|
A tuple of: |
List[str]
|
|
Dict[str, str]
|
|
Tuple[DiGraph, List[str], Dict[str, str]]
|
|
Todo
- phase_nodes is only written to, never read from. Can it be removed?
chrono_edge_add
chrono_edge_add(file_graph: DiGraph, graph_data, xs_ys, phasedict: dict[tuple[str, str], str], phase_trck: list[tuple[str, str]], post_dict: dict[str, Literal['abutting', 'gap', 'overlap'] | GroupRelationship], prev_dict: dict[str, Literal['abutting', 'gap', 'overlap'] | GroupRelationship]) -> Tuple[nx.DiGraph, List[Any], List[str]]
chrono_edge_add
chrono_edge_remov
chrono_edge_remov(file_graph: DiGraph) -> tuple[nx.DiGraph, list[list[Any]], list[Any], list[Any]]
Removes any excess edges so we can render the chronograph
Parameters:
Name | Type | Description | Default |
---|---|---|---|
file_graph
|
DiGraph
|
The input graph |
required |
Returns:
Type | Description |
---|---|
DiGraph
|
A tuple containing: |
list[list[Any]]
|
|
list[Any]
|
|
list[Any]
|
|
edge_label
edge_label(src: str, dst: str) -> str
Renders a string for the edge from src to dst.
Used for deleted edges
Previously part of Start_page.edge_render
Parameters:
Name | Type | Description | Default |
---|---|---|---|
src
|
str
|
The context label for the start of the directed edge |
required |
dst
|
str
|
The context label for the destination of the directed edge |
required |
remove_invalid_attributes_networkx_lt_3_4
remove_invalid_attributes_networkx_lt_3_4(graph: DiGraph) -> nx.DiGraph
Function which removes 'contraction' attribtues from the provided networkx DiGraph if they are set and networkx is less than 3.4.
This is required for networkx-pydot interaction, as networkx < 3.4 does not correctly escape these values in it's pydot interface, leading to unescaped :
errors.
Networkx 3.4 requires python 3.10+, so while python 3.9 support is required we must also support older networkx releases which include this bug.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
graph
|
DiGraph
|
The DiGraph to remove contraction attributes from |
required |
Returns:
Type | Description |
---|---|
DiGraph
|
The graph with invalid contraction attribtues removed |
get_right_click_binding
get_right_click_binding(double: bool = False) -> str
Get the platform-specific tkinter binding for right-clicking.
This is different on a Mac than everywhere else
Parameters:
Name | Type | Description | Default |
---|---|---|---|
double
|
bool
|
if the bind should be for double clicking |
False
|
Returns:
Type | Description |
---|---|
str
|
the bind string for right click |
luminance
luminance(rgb: tuple[float, float, float]) -> float
Given an rgb-tuple in normalised srgb space, return the percieved luminance
Paramters
rgb: an 3-tuple of RGB values as floats in the range [0, 1]
Returns:
Type | Description |
---|---|
float
|
Percieved relative luminance of the provided srgb colour |
contrast_ratio
contrast_ratio(a: float, b: float) -> float
Get the contrast ratio between relative luminance values
Parameters:
Name | Type | Description | Default |
---|---|---|---|
a
|
float
|
a luminance value to compare |
required |
b
|
float
|
the other luminance value to compare |
required |
Returns:
Type | Description |
---|---|
float
|
The contrast ratio |