_images/toyplot.png

Text

Alignment

By default, text in Toyplot is centered vertically and horizontally around its anchor. To illustrate this, the following figures display the anchor as a small black dot:

import toyplot

canvas = toyplot.Canvas(width=500, height=150)
axes = canvas.cartesian(show=False)
axes.text(0, 0, "Text!", style={"font-size":"24px"})
axes.scatterplot(0, 0, color="black", size=3);
Text!

To control horizontal alignment, use the CSS text-anchor attribute to change the position of the text along its baseline, relative to the anchor:

canvas = toyplot.Canvas(width=500, height=300)
axes = canvas.cartesian(show=False, ymin=-1.5, ymax=1.5)

axes.vlines(0, color="lightgray")

axes.text(0, 1, "Centered", style={"text-anchor":"middle", "font-size":"24px"})
axes.scatterplot(0, 1, color="black", size=3)

axes.text(0, 0, "Left Justified", style={"text-anchor":"start", "font-size":"24px"})
axes.scatterplot(0, 0, color="black", size=3)

axes.text(0, -1, "Right Justified", style={"text-anchor":"end", "font-size":"24px"})
axes.scatterplot(0, -1, color="black", size=3);
CenteredLeft JustifiedRight Justified

In addition, the text can be shifted along its baseline in arbitrary amounts, using the -toyplot-anchor-shift attribute (note that this is non-standard CSS, provided by Toyplot for symmetry with the standard baseline-shift attribute which we will explore below):

canvas = toyplot.Canvas(width=500, height=300)
axes = canvas.cartesian(show=False, ymin=-2.5, ymax=1.5)

axes.vlines(0, color="lightgray")

axes.text(0, 1, "Shifted +0px", style={"-toyplot-anchor-shift":"0", "text-anchor":"start", "font-size":"24px"})
axes.scatterplot(0, 1, color="black", size=3)

axes.text(0, 0, "Shifted +20px", style={"-toyplot-anchor-shift":"20px", "text-anchor":"start", "font-size":"24px"})
axes.scatterplot(0, 0, color="black", size=3)

axes.text(0, -1, "Shifted +40px", style={"-toyplot-anchor-shift":"40px", "text-anchor":"start", "font-size":"24px"})
axes.scatterplot(0, -1, color="black", size=3);

axes.text(0, -2, "Shifted -20px", style={"-toyplot-anchor-shift":"-20px", "text-anchor":"start", "font-size":"24px"})
axes.scatterplot(0, -2, color="black", size=3);
Shifted +0pxShifted +20pxShifted +40pxShifted -20px

Vertically, the text baseline always passes through its anchor point - so to alter the vertical alongment of text, you change the baseline using the CSS alignment-baseline attribute. Note that CSS typography is a complex topic and there are many different types of baseline to accomodate different writing modes and fonts. The following baselines are the most useful for Western scripts. Note the subtle difference between the “central” and “middle” baselines - the former centers upper-case letters in Western scripts while the latter centers lower-case letters, and is the Toyplot default:

canvas = toyplot.Canvas(width=600, height=300)
axes = canvas.cartesian(show=False)

axes.hlines(0, color="lightgray")

axes.text(-1, 0, "Hanging", style={"alignment-baseline":"hanging", "font-size":"24px"})
axes.scatterplot(-1, 0, color="black", size=3)

axes.text(0, 0, "Central", style={"alignment-baseline":"central", "font-size":"24px"})
axes.scatterplot(0, 0, color="black", size=3)

axes.text(1, 0, "Middle", style={"alignment-baseline":"middle", "font-size":"24px"})
axes.scatterplot(1, 0, color="black", size=3)

axes.text(2, 0, "Alpha", style={"alignment-baseline":"alphabetic", "font-size":"24px"})
axes.scatterplot(2, 0, color="black", size=3);
HangingCentralMiddleAlpha

As you might expect, you can also shift text perpendicular to its baseline by arbitrary amounts, using baseline-shift. While you are free to use any of Toyplot’s supported CSS length units for the shift, percentages are especially useful, because they represent a distance relative to the font height:

canvas = toyplot.Canvas(width=700, height=300)
axes = canvas.cartesian(show=False)

axes.hlines(0, color="lightgray")

axes.text(-1, 0, "Shift -100%", style={"baseline-shift":"-100%", "font-size":"24px"})
axes.scatterplot(-1, 0, color="black", size=3)

axes.text(0, 0, "Shift 0%", style={"baseline-shift":"0", "font-size":"24px"})
axes.scatterplot(0, 0, color="black", size=3)

axes.text(1, 0, "Shift 66%", style={"baseline-shift":"66%", "font-size":"24px"})
axes.scatterplot(1, 0, color="black", size=3)

axes.text(2, 0, "Shift 100%", style={"baseline-shift":"100%", "font-size":"24px"})
axes.scatterplot(2, 0, color="black", size=3);
Shift -100%Shift 0%Shift 66%Shift 100%

Of course, you’re free to combine all four styles in any way that you like.

One final thing to keep in mind is that -toyplot-anchor-shift and baseline-shift move the text relative to its baseline, not the canvas. This is important because it affects their behavior when text is rotated. In the following example, look carefully and note that the text with -toyplot-anchor-shift is shifted along its rotated baseline, not simply moved left or right on the canvas. Similarly, the baseline-shift text is shifted perpendicular to its rotated baseline, not merely up or down:

canvas = toyplot.Canvas(width=500, height=300)

axes = canvas.cartesian(grid=(1,3,0), xshow=False, yshow=False, label="default")
axes.vlines(0, color="lightgray")
axes.text(0, 0, "a + b", angle=45, style={"font-size":"24px"})
axes.scatterplot(0, 0, color="black", size=3)

axes = canvas.cartesian(grid=(1,3,1), xshow=False, yshow=False, label="-toyplot-anchor-shift")
axes.vlines(0, color="lightgray")
axes.text(0, 0, "a + b", angle=45, style={"-toyplot-anchor-shift":"20px", "font-size":"24px"})
axes.scatterplot(0, 0, color="black", size=3)

axes = canvas.cartesian(grid=(1,3,2), xshow=False, yshow=False, label="baseline-shift")
axes.vlines(0, color="lightgray")
axes.text(0, 0, "a + b", angle=45, style={"baseline-shift":"-20px", "font-size":"24px"})
axes.scatterplot(0, 0, color="black", size=3);
a + bdefaulta + b-toyplot-anchor-shifta + bbaseline-shift

Rich Text

In addition to positioning text using styles, you can use (a limited subset of) HTML markup to format your text. For example, you can create text with superscripts and subscripts:

canvas = toyplot.Canvas(width=600, height=150)
canvas.text(300, 100, "100<sup>-53</sup>", style={"font-size":"32px"});
100-53
canvas = toyplot.Canvas(width=600, height=150)
canvas.text(300, 100, "H<sub>2</sub>O", style={"font-size":"32px"});
H2O

Note that you are free to nest superscripts and subscripts:

canvas = toyplot.Canvas(width=600, height=150)
canvas.text(300, 100, "W<sup>X<sub>Y</sub><sup>Z</sup></sup>", style={"font-size":"32px"});
WXYZ

There are a variety of tags to alter the inline appearance of text:

canvas = toyplot.Canvas(width=600, height=150)
canvas.text(
    300,
    100,
    "normal <b>bold</b> <i>italic</i> <strong>strong</strong> <em>emphasis</em> <small>small</small> <code>code</code>",
    style={"font-size":"24px"});
normal bold italic strong emphasis small code

And these tags can be nested as well:

canvas = toyplot.Canvas(width=600, height=150)
canvas.text(300, 100, "foo <b>bar <i>baz <code>blah</code></i></b>", style={"font-size":"32px"});
foo bar baz blah

Finally, you can insert line breaks into your text using the <br> tag:

canvas = toyplot.Canvas(width=600, height=200)
canvas.text(300, 100, "0.567832<br><small>(243, 128, 19)</small>", style={"font-size":"16px"});
0.567832(243, 128, 19)

Note that additional tags and style attributes currently aren’t allowed in rich-text. We expect that the set of tags and attributes will expand in the future.

Keep in mind that you can use rich text formatting anywhere that text is displayed, including table cells, axis labels and tick labels. You can also use rich text in format strings for tick locators - as an example, the toyplot.locator.Log locator uses superscript tags to format tick labels for Logarithmic Scales.

Coordinate System Text

In addition to all the above, Cartesian Coordinates and Numberline Coordinates provide additional parameters that affect text layout and alignment.

First, ticks and labels have a parameter location that controls whether they appear above or below an axis:

canvas = toyplot.Canvas(width=600, height=200)

numberline1 = canvas.numberline(grid=(2, 1, 0))
numberline1.axis.ticks.location="above"

numberline2 = canvas.numberline(grid=(2, 1, 1))
numberline2.axis.ticks.location="below"
-0.50.00.5-0.50.00.5

Note that although the location can be specified explicitly, in most cases the defaults should just work ... note how the location of the Y axis ticks and labels automatically changes from “above” to “below” when the Y axis spine is repositioned in the following example:

canvas = toyplot.Canvas(width=600, height=300)

axis1 = canvas.cartesian(grid=(1, 2, 0))

axis2 = canvas.cartesian(grid=(1, 2, 1))
axis2.y.spine.position="high"
-0.50.00.5-0.50.00.5-0.50.00.5-0.50.00.5

In addition to positioning tick labels above or below an axis, you can also adjust their offset - the distance from the axis spine to the text anchor. The offset parameter is specified so that increasing values move text further from the axis, whether its location is above or below - in the following example, note that both offsets are positive:

canvas = toyplot.Canvas(width=600, height=300)

axis1 = canvas.cartesian(grid=(1, 2, 0))
axis1.y.ticks.labels.offset=30

axis2 = canvas.cartesian(grid=(1, 2, 1))
axis2.y.spine.position="high"
axis2.y.ticks.labels.offset=30
-0.50.00.5-0.50.00.5-0.50.00.5-0.50.00.5

The default text alignment parameters have been carefully chosen to provide good quality layout even if you change the label font size, and regardless of label location:

canvas = toyplot.Canvas(width=600, height=400)

numberline1 = canvas.numberline(grid=(4, 1, 0))
numberline1.axis.ticks.location="above"

numberline2 = canvas.numberline(grid=(4, 1, 1))
numberline2.axis.ticks.location="above"
numberline2.axis.ticks.labels.style = {"font-size":"16px"}

numberline3 = canvas.numberline(grid=(4, 1, 2))
numberline3.axis.ticks.location="below"

numberline4 = canvas.numberline(grid=(4, 1, 3))
numberline4.axis.ticks.location="below"
numberline4.axis.ticks.labels.style = {"font-size":"16px"}
-0.50.00.5-0.50.00.5-0.50.00.5-0.50.00.5

Similarly, alignment parameters are automatically adjusted when you rotate tick labels, adjusting the anchor and baseline to provide good results:

import numpy

colormap = toyplot.color.brewer.map("BlueRed", domain_min=0, domain_max=1)

canvas = toyplot.Canvas()
numberline = canvas.color_scale(x1="50%", x2="50%", y1="-10%", y2="10%", colormap=colormap)
numberline.axis.ticks.show = True
numberline.axis.ticks.labels.angle=-90
0.00.51.0

Of-course, you are free to override any of these behaviors. For example, suppose we use rich text to add multi-line tick labels to the preceding example:

def format_color(color):
    return "(%.2f, %.2f, %.2f)" % (color["r"], color["g"], color["b"])

values = numpy.linspace(colormap.domain.min, colormap.domain.max, 4)
labels = ["%.4f<br><small>%s</small>" % (value, format_color(colormap.color(value))) for value in values]
locator = toyplot.locator.Explicit(values, labels)
canvas = toyplot.Canvas()
numberline = canvas.color_scale(x1="50%", x2="50%", y1="-10%", y2="10%", colormap=colormap)
numberline.axis.ticks.show = True
numberline.axis.ticks.labels.angle=-90

numberline.axis.ticks.locator = locator
numberline.axis.ticks.labels.style = {"font-size":"16px"}
0.0000(0.02, 0.19, 0.38)0.3333(0.65, 0.81, 0.89)0.6667(0.97, 0.72, 0.60)1.0000(0.40, 0.00, 0.12)

We might choose to center the labels horizontally and vertically, overriding the defaults:

canvas = toyplot.Canvas()
numberline = canvas.color_scale(x1="50%", x2="50%", y1="-10%", y2="10%", colormap=colormap)
numberline.axis.ticks.labels.angle=-90
numberline.axis.ticks.show = True
numberline.axis.ticks.locator = locator
numberline.axis.ticks.labels.style = {"font-size":"16px"}

numberline.axis.ticks.labels.style = {"baseline-shift":"10px"}
numberline.axis.ticks.labels.style = {"text-anchor":"middle"}
numberline.axis.ticks.labels.offset = 60
0.0000(0.02, 0.19, 0.38)0.3333(0.65, 0.81, 0.89)0.6667(0.97, 0.72, 0.60)1.0000(0.40, 0.00, 0.12)