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