baltic utility functions¶
This module provides baltic utility functions with no Tree dependency in their signature: date conversion, plot scale bars and time grids, node bar/piechart/treemap annotations, tanglegram tip-order optimization (untangle), root-to-tip regression, colormap helpers, bezier/gradient polygon drawing, and highest posterior density (hpd) intervals.
Notes
This version of baltic (v1.0 (Cedar)) contains many API changes from previous versions, and is not backwards-compatible. If you find pieces of documentation that refer to the old API, please let us know and we will try to update them with the next update.
Attributes
- logger
logging.Logger Default logger which will be passed to other
balticfunctions.
- baltic.bt_utils.branch_to_json(curNode, treeType, traits, mostRecentDate, treeDict=None)¶
Format a
baltic.branchLike.BranchLikeobject into a dictionary suitable for Auspice JSON.Parameters
- curNode
baltic.branchLike.BranchLike Current branch being serialized.
- treeType{‘divergence’, ‘time’}
Interpretation of branch lengths in the exported tree.
- traitsiterable[str]
Trait names to include in the exported node attributes.
- mostRecentDatefloat
Most recent sampling date used when exporting time-based confidence intervals.
- treeDictdict, optional
Existing dictionary to populate during recursive export. Callers normally leave this unset.
Returns
- dict
Auspice-shaped node dictionary for curNode, with its descendants nested under
children.
Examples
>>> import baltic as bt >>> from baltic import bt_utils >>> ll = bt.make_tree("((A:1.0,B:1.0):1.0,C:1.0);", treeType="time") >>> _ = ll.traverse_tree() >>> ll.set_absolute_time(2020.0) >>> payload = bt_utils.branch_to_json(ll.root, "time", [], ll.mostRecent) >>> sorted(payload.keys()) ['children', 'node_attrs']
- curNode
- baltic.bt_utils.calendar_to_decimal_date(date, fmt='%Y-%m-%d', variable=False)¶
Convert a calendar date of a specified format into a decimal number.
This is the inverse of
decimal_to_calendar_date().Parameters
- datestr
Date string to be converted.
- fmtstr, default=”%Y-%m-%d”
String encoding the format of the input date. Must be parsable by Python’s datetime module.
- variablebool, default=False
Set to
Truewhen dates may be of variable lengths (e.g. when looping over["2025-01-01", "2025-02"]). Will use highest precision available. WithFalsea date that does not match fmt exactly raisesValueError.
Returns
- float or tuple[float, tuple[float, float]]
With
variable=False, the decimal year. Withvariable=True, a(midpoint, (earliest, latest))pair: the bounds span the whole month forYYYY-MMinput and the whole year forYYYY, and collapse to the date itself when a full date was given.As a special case, a falsy fmt short-circuits the conversion and returns date unchanged, so the result is then a
str.
Raises
- ValueError
If date does not match fmt and variable is
False.
Examples
>>> from baltic import bt_utils >>> bt_utils.calendar_to_decimal_date("1253-07-06") 1253.509589041096 >>> midpoint, bounds = bt_utils.calendar_to_decimal_date("2020-03", variable=True) >>> round(midpoint, 3) 2020.205 >>> len(bounds) 2
Attribution
The exact-date conversion is adapted from the
dt2timplementation in the Stack Overflow answer “Convert fractional years to a real date in Python” by userunutbu, posted 10 October 2013. Handling of partial and uncertain dates was subsequently added forbaltic.The original Stack Overflow contribution is distributed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA 3.0).
Source: https://stackoverflow.com/a/19306024 License: https://creativecommons.org/licenses/by-sa/3.0/
- baltic.bt_utils.clean_axes(ax, hideSpines=['left', 'top', 'right', 'bottom'], removeTickLabels='both')¶
Remove selected spines, suppress ticks and ticklabels on x, y or both axes.
It is often used after
baltic.tree.Tree.plot_tree().Parameters
- ax
matplotlib.axes.Axes Axes to modify.
- hideSpineslist[str], default=[‘left’, ‘top’, ‘right’, ‘bottom’]
Spine names to hide.
- removeTickLabels{‘x’, ‘y’, ‘both’, ‘none’}, default=”both”
Tick-label groups to remove.
Returns
matplotlib.axes.AxesThe cleaned axes.
Examples
>>> import matplotlib.pyplot as plt >>> from baltic import bt_utils >>> fig, ax = plt.subplots() >>> bt_utils.clean_axes(ax, hideSpines=["top", "right"], removeTickLabels="x") <...Axes...>
- ax
- baltic.bt_utils.convert_date_format(dateString, startFormat, endFormat)¶
Reformat a date string from one
datetimeformat to another.This helper is commonly paired with
calendar_to_decimal_date()when preparing axis labels.Parameters
- dateStringstr
Input date string.
- startFormatstr
Format used to parse dateString.
- endFormatstr
Format used to render the output string.
Returns
- str
Reformatted date string.
Examples
>>> from baltic import bt_utils >>> bt_utils.convert_date_format("2020-03-15", "%Y-%m-%d", "%b %Y") 'Mar 2020'
- baltic.bt_utils.decimal_to_calendar_date(timepoint, fmt='%Y-%m-%d')¶
Convert a decimal year value to a formatted calendar date string.
Parameters
- timepointfloat
Decimal year to convert.
- fmtstr, default=”%Y-%m-%d”
Output date format passed to
datetime.datetime.strftime().
Returns
- str
Formatted calendar date.
Raises
- ValueError
If timepoint falls outside
datetime’s supported range of years 1 to 9999. Decimal dates from deep-time or BCE trees are therefore not convertible;generate_calendar_timeline()handles those with its deep-time spacing options instead.
Examples
>>> from baltic import bt_utils >>> bt_utils.decimal_to_calendar_date(2020.5) '2020-07-02'
Attribution
Adapted from the Stack Overflow answer “decimal years to datetime in Python” by Jon Clements, posted 3 January 2014. Modified for use in
balticand for configurable output formatting.The original Stack Overflow contribution is distributed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA 3.0).
Source: https://stackoverflow.com/a/20911144 License: https://creativecommons.org/licenses/by-sa/3.0/
- baltic.bt_utils.desaturate(colour, desat=0.65, out='auto')¶
Desaturate a colour by scaling its HSV saturation component.
Use
desaturate_cmap()to apply the same transformation to an entire colormap.Parameters
- colourstr or tuple
Input colour specification.
- desatfloat, default=0.65
Saturation multiplier in the interval
[0, 1].- out{‘auto’, ‘hex’, ‘rgb’, ‘rgba’}, default=’auto’
Output format for the desaturated colour.
'auto'matches the form of colour, returning a hex string for string input and a tuple of the same arity for tuple input.
Returns
- str or tuple
Desaturated colour in the requested format.
Raises
- ValueError
If desat lies outside
[0, 1].- TypeError
If colour is neither a colour string nor a 3- or 4-element RGB(A) sequence.
Examples
>>> from baltic import bt_utils >>> bt_utils.desaturate("#ff0000", desat=0.5) '#ff8080'
- baltic.bt_utils.desaturate_cmap(cmap, desat=0.65)¶
Create a desaturated version of a matplotlib colormap.
This applies
desaturate()across sampled colours from the input map.Parameters
- cmap
matplotlib.colors.Colormap Colormap to desaturate.
- desatfloat, default=0.65
Saturation multiplier applied to sampled colours.
Returns
matplotlib.colors.ListedColormapDesaturated colormap.
Examples
>>> import matplotlib as mpl >>> from baltic import bt_utils >>> cmap = bt_utils.desaturate_cmap(mpl.cm.viridis, desat=0.4) >>> cmap.N 256
- cmap
- baltic.bt_utils.draw_gradient_polygon(ax, polygonXY, extent, colour, minAlpha=0.0, maxAlpha=1.0, n=256, axis='y', origin='lower', reverse=False, zorder=0, interpolation='bicubic', addPatch=True, patchKwargs=None, imshowKwargs=None)¶
Draw an RGBA gradient image and clip it to a polygon.
Parameters
- ax
matplotlib.axes.Axes Axes on which to draw the clipped gradient.
- polygonXYarray-like
Polygon vertices used as the clipping path.
- extentsequence[float]
Image extent passed to
matplotlib.axes.Axes.imshow()as[xmin, xmax, ymin, ymax].- colourcolor
Base color used for the gradient.
- minAlpha, maxAlphafloat, optional
Alpha range used to build the gradient ramp.
- nint, default=256
Number of gradient samples.
- axis{‘x’, ‘y’}, default=”y”
Direction along which alpha should vary.
- origin{‘lower’, ‘upper’}, default=”lower”
Image origin passed to
imshow.- reversebool, default=False
If
True, reverse the alpha ramp.- zorderfloat, default=0
Z-order for the gradient image and default clipping patch.
- interpolationstr, default=”bicubic”
Interpolation mode used by
imshow.- addPatchbool, default=True
If
True, add the clipping patch to the axes.- patchKwargsdict, optional
Additional keyword arguments forwarded to the polygon patch.
- imshowKwargsdict, optional
Additional keyword arguments forwarded to
imshow.
Returns
- tuple
(image, patch)for the gradient image and the clipping polygon.
Examples
>>> import matplotlib.pyplot as plt >>> from baltic import bt_utils >>> fig, ax = plt.subplots() >>> im, patch = bt_utils.draw_gradient_polygon( ... ax, ... polygonXY=[(0, 0), (1, 0), (1, 1), (0, 1)], ... extent=[0, 1, 0, 1], ... colour="steelblue", ... ) >>> patch.__class__.__name__ 'Polygon'
- ax
- baltic.bt_utils.five_point_bezier(points, precision=50)¶
Quartic Bézier curve (5 control points). Returns arrays of x and y coordinates.
This geometry helper supports routines such as
baltic.curonia.plot_gradient_clade_tree().Parameters
- pointssequence[tuple[float, float]]
Five control points defining the quartic Bézier curve.
- precisionint, default=50
Number of samples to evaluate along the curve.
Returns
- tuple[numpy.ndarray, numpy.ndarray]
Arrays of x and y coordinates sampled along the curve.
Examples
>>> from baltic import bt_utils >>> xs, ys = bt_utils.five_point_bezier([(0, 0), (1, 0), (1, 1), (2, 1), (2, 0)], precision=5) >>> len(xs), len(ys) (5, 5)
- baltic.bt_utils.format_time_grid(ax, timeline, inputDateFmt='%Y-%m-%d', outputFmtFxn=None, labelPosition='mid', axis='x', **kwargs)¶
Format tick positions and labels for a time-grid axis.
This helper complements
plot_time_grid()on the same axes.Parameters
- ax
matplotlib.axes.Axes Axes whose ticks should be updated.
- timelinelist[str] or list[float]
Ordered list of calendar dates, or plain decimal years for a deep-time timeline (decades, millennia, or millions of years; see
generate_calendar_timeline()), defining grid boundaries.- inputDateFmtstr, default=”%Y-%m-%d”
Date format used to parse entries in timeline. Ignored when timeline already holds plain decimal years.
- outputFmtFxncallable, optional
Function used to convert each timeline entry into a label string. Defaults to a month/year formatter for calendar-string timelines, or (for deep-time timelines) a formatter that picks a single unit – years, kya, or Ma – for the whole axis based on the largest boundary magnitude, e.g.
-3 Mafor 3 million years before year 0.- labelPosition{‘left’, ‘mid’}, default=”mid”
Whether labels should be placed on boundaries or interval midpoints.
- axis{‘x’, ‘y’}, default=”x”
Axis whose ticks should be updated.
- **kwargsdict, optional
Additional keyword arguments forwarded to the tick label setters.
Returns
matplotlib.axes.AxesThe modified matplotlib Axes object.
Examples
>>> import matplotlib.pyplot as plt >>> from baltic import bt_utils >>> fig, ax = plt.subplots() >>> timeline = ["2020-01-01", "2020-04-01", "2020-07-01", "2020-10-01"] >>> bt_utils.format_time_grid(ax, timeline) <...Axes...>
Deep-time timelines (plain decimal years, e.g. spanning millennia or millions of years) are labelled with an automatically-chosen unit instead of a calendar format:
>>> deepTimeline = bt_utils.generate_calendar_timeline(-3_200_000, -2_800_000, spacing=(200, 'kyr')) >>> bt_utils.format_time_grid(ax, deepTimeline) <...Axes...>
- ax
- baltic.bt_utils.generate_calendar_timeline(startDateStr, endDateStr, spacing='monthly', dateFmt='%Y-%m-%d', roundDates=True)¶
Generate a list of calendar breakpoints between two dates.
The output is designed for
plot_time_grid()andformat_time_grid().Parameters
- startDateStrstr or float
Start date of the interval. For deep-time
spacing(see below) this is a plain decimal year (e.g.-44000) rather than a calendar-formatted string, since years <=0 or >9999 cannot be parsed bydatetime.strptime.- endDateStrstr or float
End date of the interval. Same convention as
startDateStr.- spacing{‘yearly’, ‘monthly’, ‘weekly’, ‘decadal’, ‘centennial’, ‘millennial’}, int, or (n, unit) tuple, default=”monthly”
Calendar spacing to use.
'yearly','monthly'or'weekly', or an int number of days: sub-annual/annual spacing, resolved viadatetimeas before. Requires dates withindatetime’s year 1-9999 range.'decadal','centennial'or'millennial': fixed 10/100/1000-year spacing.(n, unit), e.g.(500, 'kyr')or(2, 'Myr'): arbitrary deep-time spacing, withunitone of'years','decades','centuries','millennia','kyr','Myr'or'Gyr'.
The three deep-time forms never touch
datetimeand therefore support timelines spanning years <=0 (BCE/before-present) or >9999, which BALTIC represents as negative or very large decimal dates (as parsed from BEAST trees).- dateFmtstr, default=”%Y-%m-%d”
Date format used to parse inputs and format outputs. Ignored for deep-time
spacing, where boundaries are plain decimal years.- roundDatesbool, default=True
Whether to align the timeline to calendar boundaries when possible. For deep-time spacing this rounds down to the nearest multiple of the step (e.g. the nearest earlier millennium boundary).
Returns
- list[str] or list[float]
Sequence of formatted date strings, or (for deep-time spacing) a sequence of plain decimal years.
Examples
>>> from baltic import bt_utils >>> bt_utils.generate_calendar_timeline("2020-01-01", "2020-04-01", spacing="monthly") ['2020-01-01', '2020-02-01', '2020-03-01', '2020-04-01'] >>> bt_utils.generate_calendar_timeline(-44000, -41000, spacing="millennial") [-44000, -43000, -42000, -41000] >>> bt_utils.generate_calendar_timeline(-3_200_000, -2_800_000, spacing=(200, 'kyr')) [-3200000, -3000000, -2800000]
- baltic.bt_utils.get_path_effects(mainColour='k', outlineColour='w', mainWeight=0.5, outlineWeight=4)¶
Construct a simple stroked text/line path effect stack.
These effects are useful with
baltic.tree.Tree.plot_text().Parameters
- mainColourcolor, default=”k”
Foreground colour for the inner stroke.
- outlineColourcolor, default=”w”
Colour for the outer stroke.
- mainWeightfloat, default=0.5
Line width of the inner stroke.
- outlineWeightfloat, default=4
Line width of the outer stroke.
Returns
- list
Matplotlib path-effect objects.
Examples
>>> from baltic import bt_utils >>> effects = bt_utils.get_path_effects(mainColour="black", outlineColour="white") >>> len(effects) 2
- baltic.bt_utils.hpd(data, level=0.95)¶
Compute the highest posterior density interval for a sample.
This summary is used by plotting helpers such as
baltic.curonia.plot_skygrid().Parameters
- datasequence[float]
Posterior samples. Must support
len(), so a generator has to be materialised first.- levelfloat, default=0.95
Posterior mass to include in the interval, between 0 and 1. Values above 1 are not validated and raise
IndexError.
Returns
- tuple[float, float] or None
Lower and upper bounds of the highest posterior density interval, or
Nonewhenround(level * len(data))is below 2, which is the case for a single sample or a level near zero.
Notes
This is the empirical HPD: the narrowest window containing
round(level * n)of the sorted samples. Both bounds are therefore observed data values rather than interpolated quantiles, and the interval is only meaningful for a unimodal posterior – on a bimodal sample it collapses onto whichever mode is tightest rather than reporting a disjoint region.Original implementation copyright (C) 2010 Joseph Heled.
Examples
>>> from baltic import bt_utils >>> bt_utils.hpd([1, 2, 2, 3, 4], level=0.8) (1, 3)
The bounds are always observed values, and a bimodal sample yields a degenerate interval over one mode:
>>> bt_utils.hpd([1.0, 2.0, 2.5, 3.0, 10.0], level=0.6) (2.0, 3.0) >>> bt_utils.hpd([0, 0, 0, 0, 10, 10, 10, 10], level=0.5) (0, 0)
Attribution
Adapted from
biopy.bayesianStats.hpd.Copyright (C) 2010 Joseph Heled. Original author: Joseph Heled <jheled@gmail.com>.
The upstream source directs users to its GPL v3 and LGPL v3 copying terms. The package metadata identifies the package license as “LGPL (V3)”, although its license classifier inconsistently names AGPL v3. The precise upstream licensing designation should therefore be confirmed with the copyright holder before relying on a single SPDX identifier.
Source: https://github.com/jheled/biopy/blob/master/biopy/bayesianStats.py GPL terms: https://github.com/jheled/biopy/blob/master/gpl.txt LGPL terms: https://github.com/jheled/biopy/blob/master/lgpl.txt Package metadata: https://github.com/jheled/biopy/blob/master/setup.py
- baltic.bt_utils.make_cmap(colours, position=None, name='custom_cmap')¶
- Create a colormap from mixed color formats:
RGB float tuples (0–1)
RGB int tuples (0–255)
Hex strings “#RRGGBB” or “RRGGBB”
HTML/CSS names (“red”, “steelblue”)
Matplotlib shorthand (“r”, “C0”)
The resulting colormap can be passed to
desaturate_cmap().Parameters
- colourssequence
Sequence of colors to interpolate between.
- positionsequence[float], optional
Positions associated with each color. Must start at
0and end at1when provided.- namestr, default=”custom_cmap”
Name assigned to the resulting colormap.
Returns
matplotlib.colors.LinearSegmentedColormapColormap built from the provided colors.
Examples
>>> from baltic import bt_utils >>> cmap = bt_utils.make_cmap(["#0000ff", "#ffffff", "#ff0000"]) >>> cmap.name 'custom_cmap'
- baltic.bt_utils.plot_node_bar(ax, node, traitName, traitColourDict, xyFxn=None, height=10, width=0.2, otherThres=0.0, connectNode=True, connectingCorner='lower middle', orientation='vertical', **kwargs)¶
Plot a stacked bar summarizing discrete trait probabilities for a node.
Parameters
- ax
matplotlib.axes.Axes Axes on which the bar should be drawn.
- node
baltic.branchLike.BranchLike Branch whose trait probabilities should be displayed.
- traitNamestr
Trait prefix used to locate
.setand.set.probvalues.- traitColourDictdict
Mapping from trait state to display colour.
- xyFxncallable, optional
Function returning the anchor coordinates for the bar.
- heightfloat, default=10
Total span of the stacked bar.
- widthfloat, default=0.2
Width of the bar orthogonal to height.
- otherThresfloat, default=0.0
Probability threshold below which states are grouped into
other.- connectNodebool, default=True
If
True, draw a dashed connector back to the node location.- connectingCornerstr, default=”lower middle”
Corner of the bar used as the connector origin.
- orientation{‘vertical’, ‘horizontal’}, default=”vertical”
Orientation of the stacked bar.
- **kwargsdict, optional
Additional keyword arguments forwarded to
matplotlib.patches.Rectangle.
Returns
- None
Patches are added to ax in place. Note this differs from
plot_node_piechart()andplot_node_treemap(), which return the axes.
Examples
>>> import matplotlib.pyplot as plt >>> from baltic import bt_utils >>> class DummyNode: ... x, y = 0.0, 0.0 ... traits = {"location.set": ["A", "B"], "location.set.prob": [0.7, 0.3]} >>> fig, ax = plt.subplots() >>> bt_utils.plot_node_bar(ax, DummyNode(), "location", {"A": "tab:blue", "B": "tab:orange"})
- ax
- baltic.bt_utils.plot_node_piechart(ax, node, traitName, traitColourDict, centerFxn=None, radius=0.5, other_thres=0.0, **kwargs)¶
Plot a pie chart summarizing discrete trait probabilities for a node.
Parameters
- ax
matplotlib.axes.Axes Axes on which the pie chart should be drawn.
- node
baltic.branchLike.BranchLike Branch whose trait probabilities should be displayed.
- traitNamestr
Trait prefix used to locate
.setand.set.probvalues.- traitColourDictdict
Mapping from trait state to display colour.
- centerFxncallable, optional
Function returning the chart center.
- radiusfloat, default=0.5
Pie chart radius.
- other_thresfloat, default=0.0
Probability threshold below which states are grouped into
other.- **kwargsdict, optional
Additional keyword arguments forwarded to
matplotlib.axes.Axes.pie().
Returns
matplotlib.axes.AxesThe axes with the pie wedges added.
Examples
>>> import matplotlib.pyplot as plt >>> from baltic import bt_utils >>> class DummyNode: ... x, y = 0.0, 0.0 ... traits = {"location.set": ["A", "B"], "location.set.prob": [0.7, 0.3]} >>> fig, ax = plt.subplots() >>> bt_utils.plot_node_piechart(ax, DummyNode(), "location", {"A": "tab:blue", "B": "tab:orange"}) <...Axes...>
- ax
- baltic.bt_utils.plot_node_treemap(ax, node, traitName, traitColourDict, height, width, centerFxn=None, area=1.0, other_thres=0.0, **kwargs)¶
Plot a treemap summarizing discrete trait probabilities for a node.
Parameters
- ax
matplotlib.axes.Axes Axes on which the treemap should be drawn.
- node
baltic.branchLike.BranchLike Branch whose trait probabilities should be displayed.
- traitNamestr
Trait prefix used to locate
.setand.set.probvalues.- traitColourDictdict
Mapping from trait state to display colour.
- height, widthfloat
Size of the treemap rectangle.
- centerFxncallable, optional
Function returning the rectangle center.
- areafloat, default=1.0
Included for API compatibility with related plotting helpers.
- other_thresfloat, default=0.0
Probability threshold below which states are grouped into
other.- **kwargsdict, optional
Additional keyword arguments forwarded to
matplotlib.patches.Rectangle.
Notes
Requires
squarify, imported lazily inside this function. It ships with thebalticconda environment but is not inrequirements.txt, so a pip-only install may needpip install squarify.Returns
matplotlib.axes.AxesThe axes with the treemap patches added.
Examples
>>> import matplotlib.pyplot as plt >>> from baltic import bt_utils >>> class DummyNode: ... x, y = 0.0, 0.0 ... traits = {"location.set": ["A", "B"], "location.set.prob": [0.7, 0.3]} >>> fig, ax = plt.subplots() >>> bt_utils.plot_node_treemap(ax, DummyNode(), "location", {"A": "tab:blue", "B": "tab:orange"}, height=1.0, width=1.0) <...Axes...>
- ax
- baltic.bt_utils.plot_scale_bar(ax, xy, L=None, tree=None, alnL=None, textXY=None, unitText=None, style='simple', orientation='horizontal', ySpan=None, fancyWidth=0.1, lineKwargs=None, textKwargs=None)¶
Plot a scale bar on the given axes.
Parameters
- ax
matplotlib.axes.Axes Axes on which the scale bar will be plotted.
- xytuple[float, float]
Coordinates of the starting point of the scale bar.
- Lfloat, optional
Length of the scale bar. If not provided, it will be inferred from the tree or default to
0.001.- tree
Tree, optional A
baltictree object used to infer the scale bar length and units if L is not provided.- alnLint, optional
Alignment length used to convert branch lengths (in substitutions per site) to mutation counts.
- textXYtuple[float, float], optional
Coordinates for the scale bar label. If not provided, defaults to a position near the scale bar.
- unitTextstr, optional
Text describing the units of the scale bar. If not provided, defaults to “subs/site” for divergence trees or “years” for time trees.
- style{‘simple’, ‘fancy’}, default=”simple”
Style of the scale bar. Defaults to
'simple'.- orientation{‘horizontal’, ‘vertical’}, default=”horizontal”
Orientation of the scale bar. Defaults to
'horizontal'.- ySpanfloat, optional
Vertical span of the scale bar, used to calculate default label positions. If not provided, it will be inferred from the tree.
- fancyWidthfloat, default=0.1
Width of the terminal markers for
style='fancy'expressed as a fraction of the scale-bar length.- lineKwargsdict, optional
Additional keyword arguments passed to the
matplotlibline plotting function for the scale bar.- textKwargsdict, optional
Additional keyword arguments passed to the
matplotlibtext plotting function for the scale bar label.
Returns
matplotlib.axes.AxesThe modified matplotlib Axes object.
Notes
If both L and tree are provided, L takes precedence.
If alnL is provided for a divergence tree, the scale bar will be labeled in mutation counts instead of substitutions per site.
The style parameter determines whether the scale bar has simple or fancy end markers.
The orientation parameter determines whether the scale bar is drawn horizontally or vertically.
Raises
- ValueError
If an invalid style or orientation is provided.
Warnings
If neither L nor tree is provided, the scale bar defaults to a length of
0.001with units of “subs/site”.If both tree and ySpan are provided, ySpan will be ignored in favor of the tree’s ySpan.
Examples
>>> import matplotlib.pyplot as plt >>> import baltic as bt >>> from baltic import bt_utils >>> ll = bt.make_tree("((A:1.0,B:1.0):1.0,C:1.5);", treeType="divergence") >>> _ = ll.traverse_tree() >>> fig, ax = plt.subplots() >>> ll.plot_tree(ax) <...Axes...> >>> bt_utils.plot_scale_bar(ax, xy=(0.1, 0.2), tree=ll) <...Axes...>
- ax
- baltic.bt_utils.plot_time_grid(ax, timeline, dateFmt='%Y-%m-%d', colourFxn=None, colour=None, edgeColourFxn=None, edgeColour=None, axis='x', **kwargs)¶
Shade alternating time intervals on an axis.
This helper is typically used with timelines from
generate_calendar_timeline().Parameters
- ax
matplotlib.axes.Axes Axes on which the spans should be drawn.
- timelinelist[str], list[float], or range
Time boundaries as calendar strings, or as plain decimal years (e.g. from a deep-time
generate_calendar_timeline()call spanning decades, millennia, or millions of years).- dateFmtstr, default=”%Y-%m-%d”
Date format used when timeline contains calendar strings. Ignored when timeline already holds plain decimal years.
- colourFxn, edgeColourFxncallable, optional
Functions that map interval indices to face and edge colours.
- colour, edgeColourcolor, optional
Constant face and edge colours used when the corresponding functions are not provided.
- axis{‘x’, ‘y’}, default=”x”
Axis along which spans should be drawn.
- **kwargsdict, optional
Additional keyword arguments forwarded to
ax.axvspanorax.axhspan.
Returns
matplotlib.axes.AxesThe modified matplotlib Axes object.
Examples
>>> import matplotlib.pyplot as plt >>> from baltic import bt_utils >>> fig, ax = plt.subplots() >>> timeline = ["2020-01-01", "2020-04-01", "2020-07-01", "2020-10-01"] >>> bt_utils.plot_time_grid(ax, timeline, colour="lightgray") <...Axes...>
Deep-time timelines (e.g. from
generate_calendar_timeline(..., spacing="millennial")) are plain decimal years and are shaded the same way, without anydateFmt:>>> deepTimeline = bt_utils.generate_calendar_timeline(-44000, -41000, spacing="millennial") >>> bt_utils.plot_time_grid(ax, deepTimeline, colour="lightgray") <...Axes...>
- ax
- baltic.bt_utils.plot_tmrca_posterior(ax, tmrcaFile, tmrcaName='age(root)', burnin=None, yCoord=None, fullViolin=True, hpdLvl=0.95, precision=100, kdeWidth=3, normalise=True, orientation='horizontal', connectNode=False, node=None, violinKwargs={}, outlineKwargs={}, connectionLineKwargs={})¶
Plot a KDE-based posterior density for a TMRCA statistic from a log file.
Parameters
- ax
matplotlib.axes.Axes Axes on which the posterior should be drawn.
- tmrcaFilestr
Path to the tab-delimited log file containing posterior samples.
- tmrcaNamestr, default=”age(root)”
Column name to extract from the log file.
- burninint, optional
Minimum state value to retain from the log.
- yCoordfloat, optional
Anchor coordinate for plotting the density.
- fullViolinbool, default=True
If
True, draw the full violin; otherwise draw a half violin.- hpdLvlfloat, default=0.95
Highest posterior density mass to report.
- precisionint, default=100
Number of x positions used to evaluate the KDE.
- kdeWidthfloat, default=3
Width scaling applied to the KDE curve.
- normalisebool, default=True
If
True, normalise the KDE height before scaling by kdeWidth.- orientation{‘horizontal’, ‘vertical’}, default=”horizontal”
Orientation of the violin plot.
- connectNodebool, default=False
If
True, connect the posterior summary back to node.- node
baltic.branchLike.BranchLike, optional Branch to connect to when connectNode is enabled.
- violinKwargs, outlineKwargs, connectionLineKwargsdict, optional
Keyword arguments forwarded to the violin fill, outline, and connector line artists.
Returns
matplotlib.axes.AxesThe modified matplotlib Axes object.
Examples
>>> import matplotlib.pyplot as plt >>> from baltic import bt_utils >>> fig, ax = plt.subplots() >>> bt_utils.plot_tmrca_posterior(ax, "tmrca.log", tmrcaName="age(root)", burnin=1000000) <...Axes...>
- ax
- baltic.bt_utils.project_polar_vector(x, y, radians, length)¶
Translate a point by a vector specified in polar coordinates.
This helper complements
project_to_polar()for circular tree layouts.Parameters
- x, yfloat
Starting point.
- radiansfloat
Direction of the vector in radians.
- lengthfloat
Vector length.
Returns
- tuple[float, float]
Endpoint coordinates.
Examples
Angles are measured counter-clockwise from the positive x axis, so a quarter turn of length 2 moves straight up. The x component is rounded here because it is a floating-point residue rather than an exact zero.
>>> import math >>> from baltic import bt_utils >>> x, y = bt_utils.project_polar_vector(0.0, 0.0, math.pi / 2, 2.0) >>> round(x, 12), round(y, 12) (0.0, 2.0) >>> tuple(round(v, 12) for v in bt_utils.project_polar_vector(1.0, 1.0, 0.0, 3.0)) (4.0, 1.0)
- baltic.bt_utils.project_to_polar(x, y, yRange, circleStart=0.0, circleFraction=1.0)¶
Convert rectangular tree coordinates to Cartesian coordinates on a circle.
This projection underlies circular layouts in
baltic.tree.Tree.plot_tree().Parameters
- xfloat
Radial distance from the origin.
- yfloat
Position along the non-informative tree axis.
- yRangefloat
Total span of the non-informative axis.
- circleStartfloat, default=0.0
Starting angular offset as a fraction of a full turn.
- circleFractionfloat, default=1.0
Fraction of the circle used by the layout.
Returns
- tuple[float, float]
Projected Cartesian coordinates.
Examples
>>> from baltic import bt_utils >>> bt_utils.project_to_polar(1.0, 0.0, 10.0) (0.0, 1.0)
- baltic.bt_utils.state_collapse_tree(tree, switchFxn, keepLast=True, adjustEarlyHeights=False)¶
Return a deepcopied and reduced version of the tree provided where subtrees are labelled identically when branches evaluate switchFxn to False. Also known by the name of Phylotype maps/trees.
Parameters
- tree
baltic.tree.Tree Tree to collapse by partition state.
- switchFxncallable
Function that receives a branch and returns
Truewhen a new partition should start at that branch.- keepLastbool, default=True
If
True, retain the most recent descendant branch for each partition. IfFalse, retain the earliest descendant instead.- adjustEarlyHeightsbool, default=False
If
TrueandkeepLastisFalse, adjust the retained early descendants to end at the most recent representative height.
Returns
baltic.tree.TreeA new, deep-copied tree. The tree passed in is left unmodified.
Examples
>>> import baltic as bt >>> from baltic import bt_utils >>> ll = bt.make_tree("(((A:1.0,B:1.0):1.0,C:1.0):1.0,D:1.0);", treeType="divergence") >>> ll.sort_branches() >>> for branch in ll.Objects: ... branch.traits["state"] = "X" if getattr(branch, "name", "").startswith(("A", "B")) else "Y" >>> collapsed = bt_utils.state_collapse_tree( ... ll, ... switchFxn=lambda k: k.traits.get("state") != k.parent.traits.get("state") if k.parent else True, ... ) >>> len(collapsed.get_external()) <= len(ll.get_external()) True
- tree
- baltic.bt_utils.to_scientific_notation_str(value, decimalPlaces=2, latex=True, omitPowerWhenZero=True)¶
Format number in scientific notation as str.
Parameters
- valuefloat
Very large or very small number to be formatted.
- decimalPlacesint
How many significant digits to report. Defaults to 2.
- latexbool
Whether to format output str to LaTeX “$1.23\times10^{3}$” or plain text “1.23 x 10^3”. Defaults to True.
- omitPowerWhenZerobool
Whether to add the exponent when exponent is 0. Defaults to True.
Returns
- str
Scientifically formatted string
Examples
>>> from baltic import bt_utils >>> bt_utils.to_scientific_notation_str(3000000, latex=False) '3.00 x 10^6' >>> bt_utils.to_scientific_notation_str(0.0012) '$1.20\\times10^{-3}$' >>> bt_utils.to_scientific_notation_str(2, latex=False, omitPowerWhenZero=True) '2.00'
- baltic.bt_utils.unnest(nodeList, towardsRoot=True)¶
Remove nested nodes from a selection until descendant sets no longer overlap.
Parameters
- nodeListiterable[
baltic.branchLike.BranchLike] Nodes or leaf-like branches to filter.
- towardsRootbool, default=True
If
True, preferentially keep deeper nodes; otherwise keep more tip-proximal entries.
Returns
- list
Filtered list in which no entry’s descendant tips overlap another’s. Used by
baltic.tree.Tree.condense_tree()to pick the outermost collapsible nodes.
Examples
>>> import baltic as bt >>> from baltic import bt_utils >>> ll = bt.make_tree("(((A:1.0,B:1.0):1.0,C:1.0):1.0,D:1.0);", treeType="divergence") >>> _ = ll.traverse_tree() >>> nodes = [ll.find_MRCA("A", "B"), ll.find_MRCA("A", "B", "C")] >>> kept = bt_utils.unnest(nodes, towardsRoot=True) >>> len(kept) 1
- nodeListiterable[
- baltic.bt_utils.untangle(tree, reference, min_shared=2, maxPolytomy=9)¶
Reorder internal node children across multiple trees to reduce tip crossing.
Parameters
- tree
baltic.tree.Tree Tree whose child orderings will be updated.
- reference
baltic.tree.Tree Reference tree whose tip ordering guides the untangling.
- min_sharedint, default=2
Minimum number of shared descendant tips required before a child set is considered in the local ordering score.
- maxPolytomyint, default=9
Largest number of children for which the exhaustive permutation search is attempted. Nodes with more children than this are skipped silently and keep their existing child order, avoiding a factorial blow-up.
Returns
baltic.tree.TreeThe same tree object, with child orderings updated in place. The return value is a convenience for chaining, not a copy, and reference is not modified.
Examples
>>> import baltic as bt >>> from baltic import bt_utils >>> tree = bt.make_tree("(((A:1.0,B:1.0):1.0,C:1.0):1.0,D:1.0);", treeType="divergence") >>> reference = bt.make_tree("((A:1.0,C:1.0):1.0,(B:1.0,D:1.0):1.0);", treeType="divergence") >>> _ = tree.traverse_tree() >>> _ = reference.traverse_tree() >>> untangled = bt_utils.untangle(tree, reference) >>> untangled is tree True
- tree
- baltic.bt_utils.untangle_trees(trees, iterations=10, maxPolytomy=8, bidirectional=True)¶
Untangle a list of trees for tanglegram visualisation.
This repeatedly applies
untangle()across the tree list.Parameters
- treeslist[Tree]
Trees ordered as they will appear in the tanglegram. Trees are modified in place.
- iterationsint, default=10
Number of global passes along the chain.
- maxPolytomyint, default=8
Maximum polytomy size to brute-force while reordering child sets.
- bidirectionalbool, default=True
Whether to do backward passes as well as forward passes.
Returns
- list[Tree]
The same list, untangled.
Examples
>>> import baltic as bt >>> from baltic import bt_utils >>> trees = [ ... bt.make_tree("((A:1.0,B:1.0):1.0,C:1.0);", treeType="divergence"), ... bt.make_tree("((A:1.0,C:1.0):1.0,B:1.0);", treeType="divergence"), ... ] >>> result = bt_utils.untangle_trees(trees, iterations=1) >>> len(result) 2