Visualize solutions#

The io module allows you to convert MutableTransition, Topology instances, and ProblemSets to Mermaid language with asmermaid(). The resulting diagrams can be embedded directly in Markdown. Initial and final states are rendered as rectangular nodes, intermediate states as rounded nodes, and compact interaction nodes as circles. Verbose solver-setting nodes remain rectangular. This is particularly useful after running find_solutions(), which produces a ReactionInfo object with a list of MutableTransition instances (see Generate transitions).

The same objects can also be converted to DOT language with asdot() and rendered with third-party libraries such as Graphviz. A few examples below demonstrate this alternative.

See also

The objects that the StateTransitionManager produces along the way, such as ProblemSets and QNResults, are rendered in Inspect intermediate results.

Topologies#

First of all, here is an example of how to visualize a group of Topology instances. We use create_isobar_topologies() and create_n_body_topology() to create a few standard topologies.

Hide code cell content

topology = create_n_body_topology(2, 4)
source = qrules.io.asmermaid(topology, markdown=True, render_initial_state_id=True)
Markdown(source)
        flowchart LR
    n_0["$$0$$"]
    n_1["$$1$$"]
    n_2["$$2$$"]
    n_3["$$3$$"]
    A["$$-1$$"]
    B["$$-2$$"]
    N0@{ shape: text, label: " " }
    B --- N0
    A --- N0
    N0 --- n_0
    N0 --- n_1
    N0 --- n_2
    N0 --- n_3
    

Note the IDs of the nodes is also rendered if there is more than node:

topologies = create_isobar_topologies(4)
Markdown(qrules.io.asmermaid(topologies, markdown=True))
        flowchart LR
    T0_0["$$0$$"]
    T0_1["$$1$$"]
    T0_2["$$2$$"]
    T0_3["$$3$$"]
    T0_A@{ shape: text, label: " " }
    T0_N0(("$$(0)$$"))
    T0_N1(("$$(1)$$"))
    T0_N2(("$$(2)$$"))
    T0_A --- T0_N0
    T0_N0 --- T0_N1
    T0_N0 --- T0_N2
    T0_N1 --- T0_0
    T0_N1 --- T0_1
    T0_N2 --- T0_2
    T0_N2 --- T0_3
    T1_0["$$0$$"]
    T1_1["$$1$$"]
    T1_2["$$2$$"]
    T1_3["$$3$$"]
    T1_A@{ shape: text, label: " " }
    T1_N0(("$$(0)$$"))
    T1_N1(("$$(1)$$"))
    T1_N2(("$$(2)$$"))
    T1_A --- T1_N0
    T1_N0 --- T1_N1
    T1_N0 --- T1_0
    T1_N1 --- T1_N2
    T1_N1 --- T1_1
    T1_N2 --- T1_2
    T1_N2 --- T1_3
    

This can be turned on or off with the arguments of asmermaid():

topologies = create_isobar_topologies(3)
Markdown(qrules.io.asmermaid(topologies, markdown=True, render_node=False))
        flowchart LR
    T0_0["$$0$$"]
    T0_1["$$1$$"]
    T0_2["$$2$$"]
    T0_A@{ shape: text, label: " " }
    T0_N0@{ shape: text, label: " " }
    T0_N1@{ shape: text, label: " " }
    T0_A --- T0_N0
    T0_N0 --- T0_N1
    T0_N0 --- T0_0
    T0_N1 --- T0_1
    T0_N1 --- T0_2
    

asmermaid() provides other options as well:

topologies = create_isobar_topologies(5)
some_topology = topologies[0]
source = qrules.io.asmermaid(
    some_topology,
    markdown=True,
    render_final_state_id=False,
    render_node=False,
    render_resonance_id=True,
)
Markdown(source)
        flowchart LR
    n_0@{ shape: text, label: " " }
    n_1@{ shape: text, label: " " }
    n_2@{ shape: text, label: " " }
    n_3@{ shape: text, label: " " }
    n_4@{ shape: text, label: " " }
    A@{ shape: text, label: " " }
    N0@{ shape: text, label: " " }
    N1@{ shape: text, label: " " }
    N2@{ shape: text, label: " " }
    N3@{ shape: text, label: " " }
    n_5("$$5$$")
    n_6("$$6$$")
    n_7("$$7$$")
    A --- N0
    N0 --- n_5
    n_5 --- N1
    N0 --- n_0
    N1 --- n_6
    n_6 --- N2
    N1 --- n_1
    N2 --- n_7
    n_7 --- N3
    N2 --- n_2
    N3 --- n_3
    N3 --- n_4
    

The same options are available for asdot(); its output can be rendered with graphviz.Source:

dot = qrules.io.asdot(
    some_topology,
    render_final_state_id=False,
    render_node=False,
    render_resonance_id=True,
)
graphviz.Source(dot)
../_images/abd305894adcdcf0af1585ae8506fe835dfd14ba875268965f3b0a24d54a7ce9.svg

StateTransitions#

After finding the Quantum number solutions, QRules finds Particle definitions that match these quantum numbers. All these steps are hidden in the convenience functions StateTransitionManager.find_solutions() and generate_transitions(). In the following, we’ll visualize the allowed transitions for the decay \(\psi' \to \gamma\eta\eta\) as an example.

import qrules

reaction = qrules.generate_transitions(
    initial_state="psi(2S)",
    final_state=["gamma", "eta", "eta"],
    allowed_interaction_types="EM",
)

As noted in 3. Find solutions, the transitions contain all spin projection combinations (which is necessary for the ampform package). It is possible to convert all these solutions to Mermaid language with asmermaid(). To avoid visualizing all solutions, we just take a subset of the transitions:

some_transitions = reaction.transitions[::50][:3]
source = qrules.io.asmermaid(some_transitions)

This str of Mermaid language for the list of MutableTransition instances can be wrapped in a Mermaid code fence with markdown=True and displayed directly as Markdown:

source = qrules.io.asmermaid(some_transitions, markdown=True, render_node=False)
Markdown(source)
        flowchart LR
    T0_0["$$0: \gamma\left[\text{-}1\right]$$"]
    T0_1["$$1: \eta\left[0\right]$$"]
    T0_2["$$2: \eta\left[0\right]$$"]
    T0_N0["$$\psi(2S)\left[\text{-}1\right]$$"]
    T0_N1@{ shape: text, label: " " }
    T0_3("$$f_{2}(2340)\left[\text{-}2\right]$$")
    T0_N0 --- T0_3
    T0_3 --- T0_N1
    T0_N0 --- T0_0
    T0_N1 --- T0_1
    T0_N1 --- T0_2
    T1_0["$$0: \gamma\left[\text{-}1\right]$$"]
    T1_1["$$1: \eta\left[0\right]$$"]
    T1_2["$$2: \eta\left[0\right]$$"]
    T1_N0["$$\psi(2S)\left[\text{-}1\right]$$"]
    T1_N1@{ shape: text, label: " " }
    T1_3("$$f_{2}^\prime(1525)\left[0\right]$$")
    T1_N0 --- T1_3
    T1_3 --- T1_N1
    T1_N0 --- T1_0
    T1_N1 --- T1_1
    T1_N1 --- T1_2
    T2_0["$$0: \gamma\left[\text{-}1\right]$$"]
    T2_1["$$1: \eta\left[0\right]$$"]
    T2_2["$$2: \eta\left[0\right]$$"]
    T2_N0["$$\psi(2S)\left[\text{-}1\right]$$"]
    T2_N1@{ shape: text, label: " " }
    T2_3("$$a_{0}(980)^{0}\left[0\right]$$")
    T2_N0 --- T2_3
    T2_3 --- T2_N1
    T2_N0 --- T2_0
    T2_N1 --- T2_1
    T2_N1 --- T2_2
    

You can also serialize the Mermaid source to a file with io.write(). The file extension for a Mermaid file is .mmd:

qrules.io.write(reaction, "decay_topologies_with_spin.mmd")

Alternatively, io.write() can serialize the same object as DOT when the .gv file extension is used:

qrules.io.write(reaction, "decay_topologies_with_spin.gv")

Collapse graphs#

Since this list of all possible spin projections transitions is rather long, it is often useful to use strip_spin=True or collapse_graphs=True to bundle comparable graphs. First, strip_spin=True allows one collapse (ignore) the spin projections (we again show a selection only):

first_transitions = reaction.transitions[:3]
source = qrules.io.asmermaid(first_transitions, markdown=True, strip_spin=True)
Markdown(source)
        flowchart LR
    T0_0["$$0: \gamma$$"]
    T0_1["$$1: \eta$$"]
    T0_2["$$2: \eta$$"]
    T0_N0["$$\psi(2S)$$"]
    T0_N1@{ shape: text, label: " " }
    T0_3("$$a_{2}(1320)^{0}$$")
    T0_N0 --- T0_3
    T0_3 --- T0_N1
    T0_N0 --- T0_0
    T0_N1 --- T0_1
    T0_N1 --- T0_2
    T1_0["$$0: \gamma$$"]
    T1_1["$$1: \eta$$"]
    T1_2["$$2: \eta$$"]
    T1_N0["$$\psi(2S)$$"]
    T1_N1@{ shape: text, label: " " }
    T1_3("$$a_{0}(980)^{0}$$")
    T1_N0 --- T1_3
    T1_3 --- T1_N1
    T1_N0 --- T1_0
    T1_N1 --- T1_1
    T1_N1 --- T1_2
    

or, with stripped node properties:

source = qrules.io.asmermaid(
    first_transitions,
    markdown=True,
    render_node=True,
    strip_spin=True,
)
Markdown(source)
        flowchart LR
    T0_0["$$0: \gamma$$"]
    T0_1["$$1: \eta$$"]
    T0_2["$$2: \eta$$"]
    T0_A["$$\psi(2S)$$"]
    T0_N0(("$$\begin{gathered} L = 0 \\\ S = 1 \\\ P = \text{+}1 \end{gathered}$$"))
    T0_N1(("$$\begin{gathered} L = 2 \\\ S = 0 \\\ P = \text{+}1 \end{gathered}$$"))
    T0_3("$$a_{2}(1320)^{0}$$")
    T0_A --- T0_N0
    T0_N0 --- T0_3
    T0_3 --- T0_N1
    T0_N0 --- T0_0
    T0_N1 --- T0_1
    T0_N1 --- T0_2
    T1_0["$$0: \gamma$$"]
    T1_1["$$1: \eta$$"]
    T1_2["$$2: \eta$$"]
    T1_A["$$\psi(2S)$$"]
    T1_N0(("$$\begin{gathered} L = 2 \\\ S = 1 \\\ P = \text{+}1 \end{gathered}$$"))
    T1_N1(("$$\begin{gathered} L = 0 \\\ S = 0 \\\ P = \text{+}1 \end{gathered}$$"))
    T1_3("$$a_{0}(980)^{0}$$")
    T1_A --- T1_N0
    T1_N0 --- T1_3
    T1_3 --- T1_N1
    T1_N0 --- T1_0
    T1_N1 --- T1_1
    T1_N1 --- T1_2
    T2_0["$$0: \gamma$$"]
    T2_1["$$1: \eta$$"]
    T2_2["$$2: \eta$$"]
    T2_A["$$\psi(2S)$$"]
    T2_N0(("$$\begin{gathered} L = 0 \\\ S = 1 \\\ P = \text{+}1 \end{gathered}$$"))
    T2_N1(("$$\begin{gathered} L = 0 \\\ S = 0 \\\ P = \text{+}1 \end{gathered}$$"))
    T2_3("$$a_{0}(980)^{0}$$")
    T2_A --- T2_N0
    T2_N0 --- T2_3
    T2_3 --- T2_N1
    T2_N0 --- T2_0
    T2_N1 --- T2_1
    T2_N1 --- T2_2
    

Note

By default, asmermaid() renders edge IDs, because they represent the (final) state IDs as well. This can be disabled with render_final_state_id=False.

If that list is still too much, there is collapse_graphs=True, which bundles all graphs with the same final state groupings:

source = qrules.io.asmermaid(
    reaction, collapse_graphs=True, markdown=True, render_node=False
)
Markdown(source)
        flowchart LR
    T0_0["$$0: \gamma$$"]
    T0_1["$$1: \eta$$"]
    T0_2["$$2: \eta$$"]
    T0_N0["$$\psi(2S)$$"]
    T0_N1@{ shape: text, label: " " }
    T0_3("$$\begin{array}{ll} b_{1}(1235)^{0} & \omega(1650) \\\ h_{1}(1170) & \phi(1020) \\\ h_{1}(1415) & \phi(1680) \\\ J/\psi(1S) & \rho(770)^{0} \\\ \omega(782) & \rho(1450)^{0} \\\ \omega(1420) & \rho(1700)^{0} \end{array}$$")
    T0_N0 --- T0_3
    T0_3 --- T0_N1
    T0_N0 --- T0_1
    T0_N1 --- T0_0
    T0_N1 --- T0_2
    T1_0["$$0: \gamma$$"]
    T1_1["$$1: \eta$$"]
    T1_2["$$2: \eta$$"]
    T1_N0["$$\psi(2S)$$"]
    T1_N1@{ shape: text, label: " " }
    T1_3("$$\begin{array}{llll} a_{0}(980)^{0} & \chi_{c2}(1P) & f_{2}^\prime(1525) & f_{0}(2020) \\\ a_{2}(1320)^{0} & f_{0}(500) & f_{0}(1500) & f_{2}(2010) \\\ a_{0}(1450)^{0} & f_{0}(980) & f_{2}(1565) & f_{2}(2150) \\\ a_{2}(1700)^{0} & f_{2}(1270) & f_{0}(1710) & f_{2}(2300) \\\ \chi_{c0}(1P) & f_{0}(1370) & f_{2}(1950) & f_{2}(2340) \end{array}$$")
    T1_N0 --- T1_3
    T1_3 --- T1_N1
    T1_N0 --- T1_0
    T1_N1 --- T1_1
    T1_N1 --- T1_2
    

The same options also work with asdot(), for example:

dot = qrules.io.asdot(reaction, collapse_graphs=True, render_node=False)
graphviz.Source(dot)
../_images/2c970b5edfc726972b1e393cbaefc70ed9ba72d2b293e94183ec1e2cf958a02d.svg

Other state renderings#

The convert() method makes it possible to convert the types of its states. This for instance allows us to only render the spin states on in a Transition:

spin_transitions = sorted({
    t.convert(lambda s: Spin(s.particle.spin, s.spin_projection))
    for t in reaction.transitions
})
some_spin_transitions = spin_transitions[::67][:3]
source = qrules.io.asmermaid(some_spin_transitions, markdown=True, render_node=True)
Markdown(source)
        flowchart LR
    T0_0["$$0: \left|1,\text{+}1\right\rangle$$"]
    T0_1["$$1: \left|0,0\right\rangle$$"]
    T0_2["$$2: \left|0,0\right\rangle$$"]
    T0_A["$$\left|1,\text{+}1\right\rangle$$"]
    T0_N0(("$$\begin{gathered} L = \left|2,0\right\rangle \\\ S = \left|1,\text{+}1\right\rangle \\\ P = \text{+}1 \end{gathered}$$"))
    T0_N1(("$$\begin{gathered} L = \left|2,0\right\rangle \\\ S = \left|1,\text{+}1\right\rangle \\\ P = \text{+}1 \end{gathered}$$"))
    T0_3("$$\left|1,\text{-}1\right\rangle$$")
    T0_A --- T0_N0
    T0_N0 --- T0_3
    T0_3 --- T0_N1
    T0_N0 --- T0_1
    T0_N1 --- T0_0
    T0_N1 --- T0_2
    T1_0["$$0: \left|1,\text{-}1\right\rangle$$"]
    T1_1["$$1: \left|0,0\right\rangle$$"]
    T1_2["$$2: \left|0,0\right\rangle$$"]
    T1_A["$$\left|1,\text{-}1\right\rangle$$"]
    T1_N0(("$$\begin{gathered} L = \left|2,0\right\rangle \\\ S = \left|1,0\right\rangle \\\ P = \text{+}1 \end{gathered}$$"))
    T1_N1(("$$\begin{gathered} L = \left|0,0\right\rangle \\\ S = \left|1,\text{-}1\right\rangle \\\ P = \text{+}1 \end{gathered}$$"))
    T1_3("$$\left|1,0\right\rangle$$")
    T1_A --- T1_N0
    T1_N0 --- T1_3
    T1_3 --- T1_N1
    T1_N0 --- T1_1
    T1_N1 --- T1_0
    T1_N1 --- T1_2
    T2_0["$$0: \left|1,\text{-}1\right\rangle$$"]
    T2_1["$$1: \left|0,0\right\rangle$$"]
    T2_2["$$2: \left|0,0\right\rangle$$"]
    T2_A["$$\left|1,\text{-}1\right\rangle$$"]
    T2_N0(("$$\begin{gathered} L = \left|0,0\right\rangle \\\ S = \left|1,\text{-}1\right\rangle \\\ P = \text{+}1 \end{gathered}$$"))
    T2_N1(("$$\begin{gathered} L = \left|0,0\right\rangle \\\ S = \left|0,0\right\rangle \\\ P = \text{+}1 \end{gathered}$$"))
    T2_3("$$\left|0,0\right\rangle$$")
    T2_A --- T2_N0
    T2_N0 --- T2_3
    T2_3 --- T2_N1
    T2_N0 --- T2_0
    T2_N1 --- T2_1
    T2_N1 --- T2_2
    

Or any other properties of a State, such as masses or \(J^{PC}(I^G)\) numbers:

Hide code cell source

def render_mass(state: State, digits: int = 3) -> str:
    mass = round(state.particle.mass, digits)
    width = round(state.particle.width, digits)
    if width == 0:
        return str(mass)
    return f"{mass}±{width}"


mass_transitions = sorted({
    t.convert(
        state_converter=render_mass,
        interaction_converter=lambda _: None,
    )
    for t in reaction.transitions
})
some_mass_transitions = mass_transitions[::10]
source = qrules.io.asmermaid(some_mass_transitions, markdown=True)
Markdown(source)
        flowchart LR
    T0_0["$$0: 0.0$$"]
    T0_1["$$1: 0.548$$"]
    T0_2["$$2: 0.548$$"]
    T0_N0["$$3.686$$"]
    T0_N1@{ shape: text, label: " " }
    T0_3("$$1.72±0.25$$")
    T0_N0 --- T0_3
    T0_3 --- T0_N1
    T0_N0 --- T0_1
    T0_N1 --- T0_0
    T0_N1 --- T0_2
    T1_0["$$0: 0.0$$"]
    T1_1["$$1: 0.548$$"]
    T1_2["$$2: 0.548$$"]
    T1_N0["$$3.686$$"]
    T1_N1@{ shape: text, label: " " }
    T1_3("$$0.775±0.147$$")
    T1_N0 --- T1_3
    T1_3 --- T1_N1
    T1_N0 --- T1_1
    T1_N1 --- T1_0
    T1_N1 --- T1_2
    T2_0["$$0: 0.0$$"]
    T2_1["$$1: 0.548$$"]
    T2_2["$$2: 0.548$$"]
    T2_N0["$$3.686$$"]
    T2_N1@{ shape: text, label: " " }
    T2_3("$$1.706±0.38$$")
    T2_N0 --- T2_3
    T2_3 --- T2_N1
    T2_N0 --- T2_0
    T2_N1 --- T2_1
    T2_N1 --- T2_2
    T3_0["$$0: 0.0$$"]
    T3_1["$$1: 0.548$$"]
    T3_2["$$2: 0.548$$"]
    T3_N0["$$3.686$$"]
    T3_N1@{ shape: text, label: " " }
    T3_3("$$0.6±0.45$$")
    T3_N0 --- T3_3
    T3_3 --- T3_N1
    T3_N0 --- T3_0
    T3_N1 --- T3_1
    T3_N1 --- T3_2
    

Hide code cell source

from fractions import Fraction


def render_jpc_ig(state: State) -> str:
    particle = state.particle
    text = render_fraction(particle.spin)
    superscript = ""
    if particle.parity is not None:
        superscript += render_sign(particle.parity)
    if particle.c_parity is not None:
        superscript += render_sign(particle.c_parity)
    if superscript:
        text += f"^{{{superscript}}}"
    if particle.isospin is not None and particle.g_parity is not None:
        text += R"\left("
        text += f"{render_fraction(particle.isospin.magnitude)}"
        text += f"^{{{render_sign(particle.g_parity)}}}"
        text += R"\right)"
    return text


def render_fraction(value: float | Fraction) -> str:
    fraction = Fraction(value)
    if fraction.denominator == 1:
        return str(fraction.numerator)
    return rf"\frac{{{fraction.numerator}}}{{{fraction.denominator}}}"


def render_sign(parity: int | Parity) -> str:
    if parity == -1:
        return "-"
    if parity == +1:
        return "+"
    raise NotImplementedError


jpc_ig_transitions = sorted({
    t.convert(
        state_converter=render_jpc_ig,
        interaction_converter=lambda _: None,
    )
    for t in reaction.transitions
})
source = qrules.io.asmermaid(jpc_ig_transitions, collapse_graphs=True, markdown=True)
Markdown(source)
        flowchart LR
    T0_0["$$0: 1^{--}$$"]
    T0_1["$$1: 0^{-+}\left(0^{+}\right)$$"]
    T0_2["$$2: 0^{-+}\left(0^{+}\right)$$"]
    T0_N0["$$1^{--}\left(0^{-}\right)$$"]
    T0_N1@{ shape: text, label: " " }
    T0_3("$$\begin{gathered} 1^{+-}\left(0^{-}\right) \\\ 1^{+-}\left(1^{+}\right) \\\ 1^{--}\left(0^{-}\right) \\\ 1^{--}\left(1^{+}\right) \end{gathered}$$")
    T0_N0 --- T0_3
    T0_3 --- T0_N1
    T0_N0 --- T0_1
    T0_N1 --- T0_0
    T0_N1 --- T0_2
    T1_0["$$0: 1^{--}$$"]
    T1_1["$$1: 0^{-+}\left(0^{+}\right)$$"]
    T1_2["$$2: 0^{-+}\left(0^{+}\right)$$"]
    T1_N0["$$1^{--}\left(0^{-}\right)$$"]
    T1_N1@{ shape: text, label: " " }
    T1_3("$$\begin{gathered} 0^{++}\left(0^{+}\right) \\\ 0^{++}\left(1^{-}\right) \\\ 2^{++}\left(0^{+}\right) \\\ 2^{++}\left(1^{-}\right) \end{gathered}$$")
    T1_N0 --- T1_3
    T1_3 --- T1_N1
    T1_N0 --- T1_0
    T1_N1 --- T1_1
    T1_N1 --- T1_2
    

Tip

Note that collapsing the graphs also works for custom edge properties.

Styling#

asmermaid() accepts styling arguments for the diagram, its edges, and its nodes through figure_style, edge_style, and node_style, respectively:

some_transition = reaction.transitions[0]
source = qrules.io.asmermaid(
    some_transition,
    edge_style={
        "color": "red",
        "fontcolor": "blue",
        "fontsize": 25,
    },
    figure_style={"bgcolor": "white"},
    markdown=True,
    node_style={
        "color": "gray",
        "fill": "lightgray",
        "stroke": "black",
    },
    render_node=True,
)
Markdown(source)
        flowchart LR
classDef default fill:white
    n_0["$$\textcolor{gray}{0: \gamma\left[\text{-}1\right]}$$"]
    n_1["$$\textcolor{gray}{1: \eta\left[0\right]}$$"]
    n_2["$$\textcolor{gray}{2: \eta\left[0\right]}$$"]
    A["$$\textcolor{gray}{\psi(2S)\left[\text{-}1\right]}$$"]
    N0(("$$\textcolor{gray}{\begin{gathered} L = \left|0,0\right\rangle \\\ S = \left|1,\text{-}1\right\rangle \\\ P = \text{+}1 \end{gathered}}$$"))
    N1(("$$\textcolor{gray}{\begin{gathered} L = \left|0,0\right\rangle \\\ S = \left|0,0\right\rangle \\\ P = \text{+}1 \end{gathered}}$$"))
    n_3("$$\textcolor{blue}{a_{0}(980)^{0}\left[0\right]}$$")
    A --- N0
    N0 --- n_3
    n_3 --- N1
    N0 --- n_0
    N1 --- n_1
    N1 --- n_2
    style n_0 color:gray,fill:lightgray,stroke:black
    style n_1 color:gray,fill:lightgray,stroke:black
    style n_2 color:gray,fill:lightgray,stroke:black
    style A color:gray,fill:lightgray,stroke:black
    style N0 color:gray,fill:lightgray,stroke:black
    style N1 color:gray,fill:lightgray,stroke:black
    style n_3 stroke:red,color:blue,font-size:25px
    linkStyle 0 stroke:red,color:blue,font-size:25px
    linkStyle 1 stroke:red,color:blue,font-size:25px
    linkStyle 2 stroke:red,color:blue,font-size:25px
    linkStyle 3 stroke:red,color:blue,font-size:25px
    linkStyle 4 stroke:red,color:blue,font-size:25px
    linkStyle 5 stroke:red,color:blue,font-size:25px
    

For DOT output, asdot() takes Graphviz attributes. Examples are size, color, and fontcolor. Edges and nodes can be styled with edge_style and node_style, respectively:

dot = qrules.io.asdot(
    some_transition,
    bgcolor="white",
    edge_style={
        "arrowhead": "open",
        "color": "red",
        "fontcolor": "blue",
        "fontsize": 25,
    },
    node_style={
        "color": "gray",
        "penwidth": 2,
        "shape": "ellipse",
        "style": "dashed",
    },
    render_node=True,
    size=12,
)
graphviz.Source(dot)
../_images/086b37f87ca24658cfc8f424c9c27ac540429776edf52b65073189e7c6546d91.svg

By default, Mermaid renders labels with LaTeX. This can be disabled with the latex argument of asmermaid():

source = qrules.io.asmermaid(
    some_transition,
    latex=False,
    markdown=True,
    render_node=True,
)
Markdown(source)
        flowchart LR
    n_0["0: gamma[-1]"]
    n_1["1: eta[0]"]
    n_2["2: eta[0]"]
    A["psi(2S)[-1]"]
    N0(("L=|0,0⟩<br/>S=|1,-1⟩<br/>P=+1"))
    N1(("L=|0,0⟩<br/>S=|0,0⟩<br/>P=+1"))
    n_3("a(0)(980)0[0]")
    A --- N0
    N0 --- n_3
    n_3 --- N1
    N0 --- n_0
    N1 --- n_1
    N1 --- n_2