Tutorial

First of all, load the required packages:

julia> using BioBlockcodes, BioSequences

BioSequences provides the dna"..." string macro that produces LongDNA values which are required later.

Testing a codon set for circularity with is_circular

This tutorial walks you through is_circular(codons::Vector{LongDNA}), the convenience method that answers a single question: do the given codons form a circular code?

Background

A set of codons (words of length 3 over the DNA alphabet) is a circular code if every sequence written on a circle can be decoded into codons in only one way, regardless of where you start reading. Circular codes are of interest in theoretical biology because they allow the reading frame to be retrieved locally, without a start signal.

BioBlockcodes decides circularity with a graph criterion: it builds the codon graph of the set (vertices are the mononucleotides and dinucleotides occurring in the codons, and each codon N1N2N3 contributes the edges N1 -> N2N3 and N1N2 -> N3) and checks that this directed graph contains no cycle. A codon set is circular if and only if its codon graph is acyclic.

The two methods of is_circular

is_circular is defined for two argument types:

Use the vector method when you just want a yes/no answer and do not need the graph object for anything else.

Build a codon set

A codon set is simply a vector of DNA sequences in which every sequence has length 3:

julia> codon_set = [dna"AAC", dna"GTT"]
2-element Vector{LongSequence{DNAAlphabet{4}}}:
 AAC
 GTT

You can also build the vector from strings, which is handy for longer sets:

julia> LongDNA{4}.(["AAC", "GTT"])
2-element Vector{LongSequence{DNAAlphabet{4}}}:
 AAC
 GTT

Call is_circular

julia> is_circular(codon_set)
true

The codon graph of {AAC, GTT} has no directed cycle, so the set is a circular code.

A non-circular example

The set {AGA, AAG, GAA} consists of the three cyclic permutations of the same pattern. Its codon graph contains a cycle, so it is not a circular code:

julia> is_circular([dna"AGA", dna"AAG", dna"GAA"])
false

Relationship to the CodonGraphData method

The following two calls are equivalent; the vector method just spares you the explicit construction step:

julia> is_circular([dna"AAC", dna"GTT"])
true

julia> cgd = CodonGraphData([dna"AAC", dna"GTT"]);

julia> is_circular(cgd)
true

Reach for the CodonGraphData method when you also need to run other checks on the same set (for example is_c3, is_comma_free or is_self_complementary), so the graph is built only once.

Notes and errors

  • Every codon in codons must be a valid length-3 DNA sequence. An invalid codon set (wrong length, empty, duplicates, …) raises an ArgumentError while the CodonGraphData is being constructed.
  • The order of the codons in the vector does not affect the result.
  • is_circular tests circularity only. Stronger properties such as comma-freeness or the C3 property have their own predicates.

Testing a codon set for the C3 property with is_c3

This section covers is_c3(codons::Vector{LongDNA}), which decides whether a codon set is a C3 code. The setup and codon-set construction from the is_circular section above carry over unchanged; only the property being tested is new.

Background

A codon set is C3 if the set itself and both of its reading-frame shifts are circular. The two frame shifts are obtained by rotating every codon N1N2N3 cyclically by one and by two positions; is_c3 builds the codon graph for each of the three sets and checks that none of them contains a cycle.

C3 sits strictly between the two other predicates in this tutorial: every C3 code is is_circular, and every is_strong_c3 code is C3, but neither implication reverses.

The two methods of is_c3

As with is_circular, the predicate is defined for both argument types:

  • is_c3(cgd::CodonGraphData) works on an existing codon graph.
  • is_c3(codons::Vector{LongDNA}) builds the CodonGraphData internally and forwards to the method above. Note that the two frame-shifted sets get their own graphs regardless of which method you call.

Checking a codon set

julia> is_c3([dna"AAC", dna"ATG"])
true

{AAC, ATG} is circular and stays circular under both frame shifts, so it is a C3 code.

Circular but not C3

Circularity of the set alone is not enough. {AAC, CCA} is circular, but one of its frame shifts is not, so it fails the C3 test:

julia> is_circular([dna"AAC", dna"CCA"])
true

julia> is_c3([dna"AAC", dna"CCA"])
false

Relationship to the CodonGraphData method

The two calls below are equivalent; pass a CodonGraphData when you want to run several checks on the same set without rebuilding its graph:

julia> is_c3([dna"AAC", dna"ATG"])
true

julia> cgd = CodonGraphData([dna"AAC", dna"ATG"]);

julia> is_c3(cgd)
true

Notes and errors

  • An invalid codon set raises an ArgumentError while the CodonGraphData is being constructed, exactly as for is_circular.
  • The order of the codons does not affect the result.
  • A false result does not say which frame is to blame; call is_circular on the set to see whether circularity already fails or only one of the shifts does.

Testing a codon set for the strong C3 property with is_strong_c3

This section covers is_strong_c3(codons::Vector{LongDNA}), which decides whether a codon set is a strong comma-free C3 code. The setup and codon-set construction from the is_circular section above carry over unchanged; only the property being tested is new.

Background

The relevant properties form a hierarchy, each one strictly stronger than the one before:

  1. circular – the codon graph is acyclic (see the previous section).
  2. C3 – the code and both of its frame shifts (obtained by cyclically shifting every codon one and two positions to the left) are circular. This is what is_c3 checks.
  3. strong C3 – the code is C3 and its expanded codon graph contains no cycle longer than length 2. The expanded graph adds, for every codon N1N2N3, the vertices N2 and N3N1 together with the two edges N2 -> N3N1 and N3N1 -> N2.

So is_strong_c3(codons) returns true only for sets that already pass is_circular and is_c3.

The two methods of is_strong_c3

Like is_circular, the predicate is defined for both argument types:

Checking a codon set

julia> is_strong_c3([dna"GGA", dna"TAA"])
true

The set {GGA, TAA} is circular, stays circular under both frame shifts, and its expanded graph has only length-2 cycles, so it is strong C3.

C3 but not strong C3

Passing is_c3 is necessary but not sufficient. The set {AAC, ACC} is C3, yet its expanded graph contains a longer cycle, so it fails the strong C3 test:

julia> is_c3([dna"AAC", dna"ACC"])
true

julia> is_strong_c3([dna"AAC", dna"ACC"])
false

A codon set that fails outright

{AGA, AAG, CTG, TGA, TTC} is not even circular, so every stronger property fails as well:

julia> is_strong_c3([dna"AGA", dna"AAG", dna"CTG", dna"TGA", dna"TTC"])
false

Relationship to the CodonGraphData method

As with is_circular, the two calls below are equivalent; pass a CodonGraphData when you want to run several checks on the same set without rebuilding the graph each time:

julia> is_strong_c3([dna"GGA", dna"TAA"])
true

julia> cgd = CodonGraphData([dna"GGA", dna"TAA"]);

julia> is_strong_c3(cgd)
true

Notes and errors

  • An invalid codon set raises an ArgumentError while the CodonGraphData is being constructed, exactly as for is_circular.
  • The order of the codons does not affect the result.
  • is_strong_c3 returning false tells you the set is not strong C3, but not which weaker property it still satisfies; call is_c3 or is_circular to locate the set in the hierarchy.

Plotting graphs

The codon graph behind every predicate in the previous sections can be drawn. The plotting functions live in the package extension BioBlockcodesGraphMakie, so they only become available once a Makie backend and GraphMakie have been loaded. Codon sets and CodonGraphData are built exactly as before.

Loading the extension

BioBlockcodesGraphMakie is a weak-dependency extension. Its trigger packages are CairoMakie, GraphMakie and NetworkLayout; loading them next to BioBlockcodes activates the extension automatically:

using BioBlockcodes, BioSequences
using CairoMakie, GraphMakie

Until the extension is active, plot_codon_graph is only an empty function stub and calling it throws a MethodError. Use CairoMakie for writing image files and, for example, GLMakie for an interactive window; the plotting code itself is backend-agnostic.

Plotting a single codon graph with plot_codon_graph

plot_codon_graph(cgd::CodonGraphData; fig_size = (600, 400), spring = 100) takes a CodonGraphData and returns a Makie.Figure with the directed codon graph laid out by a spring (force-directed) algorithm. Vertices are labelled with the mononucleotides and dinucleotides of the codon graph; edges carry arrow heads showing their direction.

codon_set = [dna"CAA", dna"GTC"]
cgd = CodonGraphData(codon_set)
fig = plot_codon_graph(cgd)
Example block output

The function returns the figure rather than displaying it, so you decide what to do with it — save("codon_graph.png", fig) to write a file, display(fig) to show it, or embed it in a larger layout.

Adjusting size and layout

Two keyword arguments control the output:

  • fig_size::Tuple{Int, Int} – width and height of the figure in pixels.
  • spring::Real – the C parameter of the spring layout. Larger values push the vertices further apart, which helps with dense graphs; smaller values make the drawing more compact.
plot_codon_graph(cgd; fig_size = (900, 600), spring = 200)
Example block output

Because the layout is force-directed and seeded randomly, successive calls can produce slightly different arrangements of the same graph.

Adding a title

plot_codon_graph uses the graph_title field of the CodonGraphData as the axis title. Set it when constructing the graph:

cgd_titled = CodonGraphData([dna"CAA", dna"GTC"]; graph_title = "X = {CAA, GTC}")
plot_codon_graph(cgd_titled)
Example block output

Plotting several graphs side by side

plot_multiple_codon_graphs(cgd_list::Vector{CodonGraphData}; fig_title = nothing, fig_size = (1800, 900)) arranges a list of codon graphs in a grid (the number of columns is chosen from the number of graphs) and returns one Figure. Pass fig_title for a caption above the whole grid:

cgd_list = [
    CodonGraphData([dna"ATA", dna"GGA"]; graph_title = "set 1"),
    CodonGraphData([dna"TTC", dna"GCA"]; graph_title = "set 2"),
]
plot_multiple_codon_graphs(cgd_list; fig_title = "Two codon graphs")
Example block output

Notes

  • Both functions take CodonGraphData, not a raw codon vector; build the graph first with CodonGraphData.
  • An invalid CodonGraphData, an empty cgd_list, or invalid entries in it raise an ArgumentError.
  • The extension is optional: BioBlockcodes itself has no dependency on Makie, so scripts that only test codon properties stay lightweight.

API

BioBlockcodes.CodonGraphData — Method
CodonGraphData(codon_set::Vector{LongDNA}; graph_title::String = "") -> CodonGraphData

Constructs a CodonGraphData instance from a codon set and builds the corresponding graph.

Arguments

  • codon_set::Vector{LongDNA}: Input codons used to build the graph.

Keyword Arguments

  • graph_title::String="": Optional title for the graph.

Returns

  • CodonGraphData: Fully initialized structure with vertices, edges, and labels.

Throws

  • ArgumentError: If codon_set is invalid or graph construction fails.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon_set = [dna"CCA", dna"GAT"];

julia> cgd = CodonGraphData(codon_set);

julia> cgd isa CodonGraphData
true
source
BioBlockcodes.calc_strong_c3_comb_by_size — Method
calc_strong_c3_comb_by_size(comb_size::Int, ckp_path::AbstractString, prev_res_path::AbstractString, res_path::AbstractString, stop_flag::Base.Threads.Atomic{Bool}; worker_count::Int=1) -> Bool

Computes strong-C3 combinations of a given size with checkpoint and resume logic.

Arguments

  • comb_size::Int: Size of combinations to compute (1 to 20).
  • ckp_path::AbstractString: Path to the checkpoint file.
  • prev_res_path::AbstractString: Path to the result file of the previous combination size.
  • res_path::AbstractString: Path to the output file for current results.
  • stop_flag::Base.Threads.Atomic{Bool}: Atomic stop flag for graceful interruption.

Keyword Arguments

  • worker_count::Int=nthreads(): Number of parallel workers for processing.

Returns

  • Bool: true if processing ends regularly or is completed cleanly.

Throws

  • ArgumentError: If inputs, checkpoint contents, or file states are invalid.

Examples

source
BioBlockcodes.codon_set_to_str — Method
codon_set_to_str(codon_set::Vector{LongDNA{4}}) -> String

Formats a codon set as a quoted, comma-separated string.

Arguments

  • codon_set::Vector{LongDNA{4}}: Codon set to format.

Returns

  • String: Formatted representation, e.g. "ATG", "TGA".

Throws

  • ArgumentError: If codon_set is invalid.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon_set = [dna"ATG", dna"TGA"];

julia> codon_set_to_str(codon_set) == "\"ATG\", \"TGA\""
true
source
BioBlockcodes.get_codon_set_from_line — Method
get_codon_set_from_line(line::AbstractString) -> Vector{LongDNA{4}}

Parses one line in the format COD1|COD2|...,idx1|idx2|... into a codon set.

Arguments

  • line::AbstractString: Input line with codons and corresponding indices.

Returns

  • Vector{LongDNA{4}}: Parsed and validated codon set.

Throws

  • ArgumentError: If the format, indices, or codons are invalid.

Examples

julia> using BioBlockcodes, BioSequences

julia> line = "AAC|AAG,1|2";

julia> get_codon_set_from_line(line)
2-element Vector{LongSequence{DNAAlphabet{4}}}:
 AAC
 AAG
source
BioBlockcodes.get_comp_rev_codon_set — Method
get_comp_rev_codon_set(
    codon_set::Array{T<:(BioSequences.LongDNA), 1}
) -> Any

Builds the complemented and reversed codon for each codon in the set.

Arguments

  • codon_set::Vector{LongDNA}: Input codon set.

Returns

  • Vector{LongDNA}: Complemented-and-reversed codon set in the same order.

Throws

  • ArgumentError: If codon_set is invalid.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon_set = [dna"ATG", dna"TGA", dna"TCA"];

julia> get_comp_rev_codon_set(codon_set)
3-element Vector{LongSequence{DNAAlphabet{4}}}:
 CAT
 TCA
 TGA
source
BioBlockcodes.is_c3 — Method
is_c3(cgd::CodonGraphData) -> Bool

Checks whether a codon graph satisfies the C3 property.

Arguments

  • cgd::CodonGraphData: Codon graph data object that contains the graph.

Returns

  • Bool: true if cgd is C3, otherwise false.

Throws

  • ArgumentError: If cgd is invalid.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon_set = [dna"ATG", dna"TGA"];

julia> cgd = CodonGraphData(codon_set);

julia> is_c3(cgd)
false
source
BioBlockcodes.is_c3 — Method
is_c3(codons::Array{T<:(BioSequences.LongDNA), 1}) -> Bool

Checks whether the set of codons as specified in codons satisfies the C3 property.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon_set = [dna"ATG", dna"TGA"];

julia> is_c3(codon_set)
false
source
BioBlockcodes.is_circular — Method
is_circular(cgd::CodonGraphData) -> Bool

Checks whether a codon graph is acyclic aka. contains no cycles.

Arguments

  • cgd::CodonGraphData: Codon graph data object that contains the graph.

Returns

  • Bool: true if no cycles are present, otherwise false.

Throws

  • ArgumentError: If cgd is invalid.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon_set = [dna"AAC", dna"GTT"];

julia> cgd = CodonGraphData(codon_set);

julia> is_circular(cgd)
true
source
BioBlockcodes.is_circular — Method
is_circular(
    codons::Array{T<:(BioSequences.LongDNA), 1}
) -> Bool

Checks whether the set of codons as specified in codons defines a circular code.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon_set = [dna"AAC", dna"GTT"];

julia> is_circular(codon_set)
true
source
BioBlockcodes.is_comma_free — Method
is_comma_free(cgd::CodonGraphData) -> Bool

Checks whether a codon graph is comma-free.

Arguments

  • cgd::CodonGraphData: Codon graph data object to check.

Returns

  • Bool: true if cgd is comma-free, otherwise false.

Throws

  • ArgumentError: If cgd is invalid.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon_set = [dna"CGA", dna"TAC"];

julia> cgd = CodonGraphData(codon_set);

julia> is_comma_free(cgd)
true
source
BioBlockcodes.is_comma_free — Method
is_comma_free(
    codons::Array{T<:(BioSequences.LongDNA), 1}
) -> Bool

Checks whether the set of codons as specified in codons defines a comma-free code.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon_set = [dna"AAC", dna"GTT"];

julia> is_comma_free(codon_set)
true
source
BioBlockcodes.is_self_complementary — Method
is_self_complementary(cgd::CodonGraphData) -> Bool

Checks whether a codon graph is invariant under complement and reversal.

Arguments

  • cgd::CodonGraphData: Codon graph data object to check.

Returns

  • Bool: true if the graph is self-complementary, otherwise false.

Throws

  • ArgumentError: If cgd is invalid.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon_set = [dna"AGC", dna"CTG", dna"TGT", dna"ATC"];

julia> cgd = CodonGraphData(codon_set);

julia> is_self_complementary(cgd)
false
source
BioBlockcodes.is_strong_c3 — Method
is_strong_c3(cgd::CodonGraphData) -> Bool

Checks whether a codon graph is strong C3.

Arguments

  • cgd::CodonGraphData: Codon graph data object to check.

Returns

  • Bool: true if cgd is strong C3, otherwise false.

Throws

  • ArgumentError: If cgd is invalid.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon_set = [dna"GGA", dna"TAA"];

julia> cgd = CodonGraphData(codon_set);

julia> is_strong_c3(cgd)
true
source
BioBlockcodes.is_strong_c3 — Method
is_strong_c3(
    codons::Array{T<:(BioSequences.LongDNA), 1}
) -> Bool

Checks whether the set of codons as specified in codons defines a is strong C3 code.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon_set = [dna"GGA", dna"TAA"];

julia> is_strong_c3(codon_set)
true
source
BioBlockcodes.left_shift_codon — Method
left_shift_codon(
    codon::BioSequences.LongDNA,
    shift_by::Int64
) -> BioSequences.LongSequence{A} where A<:BioSequences.DNAAlphabet

Performs a cyclic left shift on a codon.

Arguments

  • codon::LongDNA: Codon to shift.
  • shift_by::Int: Number of left shifts.

Returns

  • LongDNA: Cyclically left-shifted codon.

Throws

  • ArgumentError: If shift_by < 0 or codon is invalid.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon = dna"ACT";

julia> left_shift_codon(codon, 1)
3nt DNA Sequence:
CTA
source
BioBlockcodes.left_shift_codon_set — Method
left_shift_codon_set(
    codon_set::Array{T<:BioSequences.LongSequence{BioSequences.DNAAlphabet{4}}, 1},
    shift_by::Int64
) -> Union{BitVector, Vector}

Performs a cyclic left shift on all codons in a set.

Arguments

  • codon_set::Vector{LongDNA}: Codon set to shift.
  • shift_by::Int: Number of left shifts.

Returns

  • Vector{LongDNA}: Shifted codon set.

Throws

  • ArgumentError: If shift_by < 0 or codon_set is invalid.

Examples

julia> using BioBlockcodes, BioSequences

julia> codon_set = [dna"TTG", dna"TGA"];

julia> left_shift_codon_set(codon_set, 1)
2-element Vector{LongSequence{DNAAlphabet{4}}}:
 TGT
 GAT
source