Skip to content
Snippets Groups Projects
sequences.py 3.61 KiB
from __future__ import annotations
from lib.structures import *
import matplotlib.pyplot as pp
import lib.plotdefs as pd
import copy

"""
Builds on abstractions defined in lib.structures.
"""

def _titlecase(s: str) -> str:
    return " ".join(_s[:1].upper() + _s[1:]
        for _s in s.replace(" ", "_").split("_"))

class SuperSequence:
    """
    Sequence of labeled Sequences. Mostly for visualization purposes.

    Fields
    ------
    sequences : dict[str, Sequence]
    """

    def __init__(self, sequences: dict[str, Sequence]=None):
        """
        Constructor.

        Parameters
        ----------
        sequences : dict[str, Sequence]
        """
        self.sequences = dict() if sequences is None else sequences

    def __getitem__(self, key: str) -> Sequence:
        assert isinstance(key, str)
        return self.sequences[key]

    def __setitem__(self, key: str, seq: Sequence):
        assert isinstance(key, str)
        assert isinstance(seq, Sequence)
        self.sequences[key] = seq

    def get(self, key, default) -> Sequence:
        return self.sequences.get(key, default)

    def keys(self):
        return self.sequences.keys()

    def items(self):
        return self.sequences.items()

    def update(self, other):
        self.sequences.update(other)
        return self

    def __add__(self, other):
        sequences = copy.deepcopy(self.sequences)
        return SuperSequence(sequences).update(other)

    def __iadd__(self, other):
        return self.update(other)

    def by_times(self) -> list[Sequence]:
        """
        Return Sequences in a list ordered by earliest Event.
        """
        return sorted(
            self.sequences.values(),
            key=lambda e: e.min_time()
        )

    def to_sequence(self) -> Sequence:
        """
        Condense to a single Sequence to pass to the computer.
        """
        seq = Sequence()
        for S in self.by_times():
            seq = seq + S
        return seq

    @staticmethod
    def _gen_timeline(detailed=False, layout=(1, 4, 32, 1, 32, -10, 10)) \
            -> pd.Plotter:
        FS = pp.rcParams["font.size"]
        pp.rcParams["font.size"] = 3
        P = pd.Plotter()
        P.set_yticks([]).set_yticklabels([]).ggrid(True)
        pp.rcParams["font.size"] = FS
        return P

    def draw_simple(self) -> pd.Plotter:
        P = SuperSequence._gen_timeline(detailed=False)
        FS = pp.rcParams["font.size"]
        pp.rcParams["font.size"] = 3

        H = 0.2
        c = 0
        tl_level = 0
        tl_max = 0
        t1_last = dict()
        Tmin = 0
        Tmax = 0
        for i, (s, S) in enumerate(self.items()):
            tmin, tmax = S.when()
            Tmin = min(Tmin, tmin)
            Tmax = max(Tmax, tmax)
            k = 0
            while tmin < t1_last.get(k, tmin):
                k += 1
            tl_level = k
            tl_max = max(tl_max, tl_level)
            P.ax.add_patch(
                pp.Rectangle(
                    (tmin, tl_level * H), tmax - tmin, H / 2,
                    edgecolor="k", facecolor=f"C{c}",
                    zorder=100
                )
            )
            P.ax.text(tmin, tl_level * H - H / 15, _titlecase(s),
                horizontalalignment="left", verticalalignment="top")
            c = (c + 1) % 10
            t1_last[tl_level] = tmax
        P.set_xlim(Tmin - (Tmax - Tmin) / 20, Tmax + (Tmax - Tmin) / 20)
        P.set_ylim(-H / 2, (tl_max + 1) * H)
        P.set_xlabel("Time [s]")

        pp.rcParams["font.size"] = FS
        return P

    def draw_detailed(self) -> pd.Plotter:
        P = SuperSequence._gen_timeline(detailed=True)
        pass