Text¶
Rich Text¶
Toyplot provides a limited subset of HTML5 markup that you can use to format your text (technically, Toyplot uses the XHTML5 Syntax for HTML5, but this distinction only shows-up when using the <br/> tag, discussed below). For example, you can create text with superscripts and subscripts:
import toyplot
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"});
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 to combine effects:
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"},
);
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"},
);
And you can apply a limited subset of CSS styles within rich text:
canvas = toyplot.Canvas(width=600, height=200)
canvas.text(
300,
100,
"This is a <span style='fill:red;font-size:120%'>special</span> word.",
style={"font-size":"16px"},
);
Finally, you can embed hyperlinks in rich text, using the <a> tag:
canvas = toyplot.Canvas(width=600, height=200)
canvas.text(
300,
100,
"See <a style='fill: steelblue' href='http://toyplot.readthedocs.org'>Toyplot</a> for details.",
style={"font-size":"16px"},
);
Note that additional tags or style attributes currently aren’t allowed in rich-text. We expect that rich text capabilities will continue to 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 the <sup>
tag to
format tick labels for Logarithmic Scales.
Caveats¶
Because all text in Toyplot is parsed as XHTML5, there are a few important caveats to be aware of:
- You must use
<br/>
or<br></br>
to insert a line break …<br>
is not allowed. - You must escape
<
as<
and>
as>
because otherwise they will be confused with XHTML5 tags. - You must escape
&
as&
because otherwise it will be confused with an XHTML5 entity.
canvas = toyplot.Canvas(width=600, height=200)
canvas.text(300, 100, "3 < 4 & 5 > 6", style={"font-size":"16px"});
Alignment¶
By default, blocks of text in Toyplot are centered vertically and horizontally around their anchor. To illustrate this, the following figures display the anchor as a small black dot:
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
property to
alter the position of a line of 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
property (note that this is
non-standard CSS, provided by Toyplot for symmetry with the standard
baseline-shift
property which we will see 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, you can use the -toyplot-vertical-align
property to
alter the vertical position of a block of text relative to its anchor:
canvas = toyplot.Canvas(width=800, height=300)
axes = canvas.cartesian(show=False)
axes.hlines(0, color="lightgray")
axes.text(-1, 0, "Top", style={"-toyplot-vertical-align":"top", "font-size":"24px"})
axes.scatterplot(-1, 0, color="black", size=3)
axes.text(0, 0, "Middle", style={"-toyplot-vertical-align":"middle", "font-size":"24px"})
axes.scatterplot(0, 0, color="black", size=3)
axes.text(1, 0, "Bottom", style={"-toyplot-vertical-align":"bottom", "font-size":"24px"})
axes.scatterplot(1, 0, color="black", size=3)
axes.text(2, 0, "1st Baseline", style={"-toyplot-vertical-align":"first-baseline", "font-size":"24px"})
axes.scatterplot(2, 0, color="black", size=3)
axes.text(3, 0, "Last Baseline", style={"-toyplot-vertical-align":"last-baseline", "font-size":"24px"})
axes.scatterplot(3, 0, color="black", size=3);
Note that to see the difference between first-baseline
and
last-baseline
requires a block of text with more than one line,
since they align the anchor with the first and last line’s baselines
respectively:
canvas = toyplot.Canvas(width=800, height=300)
axes = canvas.cartesian(show=False)
axes.hlines(0, color="lightgray")
axes.text(-1, 0, "Top<br/>Top", style={"-toyplot-vertical-align":"top", "font-size":"24px"})
axes.scatterplot(-1, 0, color="black", size=3)
axes.text(0, 0, "Middle<br/>Middle", style={"-toyplot-vertical-align":"middle", "font-size":"24px"})
axes.scatterplot(0, 0, color="black", size=3)
axes.text(1, 0, "Bottom<br/>Bottom", style={"-toyplot-vertical-align":"bottom", "font-size":"24px"})
axes.scatterplot(1, 0, color="black", size=3)
axes.text(2, 0, "1st Baseline<br/>1st Baseline", style={"-toyplot-vertical-align":"first-baseline", "font-size":"24px"})
axes.scatterplot(2, 0, color="black", size=3)
axes.text(3, 0, "Last Baseline<br/>Last Baseline", style={"-toyplot-vertical-align":"last-baseline", "font-size":"24px"})
axes.scatterplot(3, 0, color="black", size=3);
As you can see, -toyplot-vertical-align
alters the alignment of an
entire block of text. If you wish to alter the vertical alignment of
text within the block, you can use the standard CSS
alignment-baseline
property:
text = """<span style="alignment-baseline:alphabetic">Alphabetic</span>"""
text += """ <span style="alignment-baseline:middle">Middle</span>"""
text += """ <span style="alignment-baseline:central">Central</span>"""
text += """ <span style="alignment-baseline:hanging">Hanging</span>"""
canvas = toyplot.Canvas(width=600, height=300)
axes = canvas.cartesian(show=False)
axes.hlines(0, color="lightgray")
axes.text(-1, 0, text, style={"font-size":"24px"})
axes.scatterplot(-1, 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 these style properties 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);
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 override the defaults to center each line of text within the label:
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 = {"text-anchor":"middle"}
numberline.axis.ticks.labels.offset = 60