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:
[1]:
import toyplot
canvas = toyplot.Canvas(width=600, height=150)
canvas.text(300, 100, "100<sup>-53</sup>", style={"font-size":"32px"});
[2]:
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:
[3]:
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:
[4]:
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:
[5]:
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:
[6]:
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:
[7]:
canvas = toyplot.Canvas(width=600, height=200)
canvas.text(
300,
100,
"See <a href='http://toyplot.readthedocs.org'>Toyplot</a> for details.",
style={"font-size":"16px"},
);
Keep in mind that the default behavior for a hyperlink in most browsers is to replace the current document with the hyperlinked content, which probably isn’t what you want when you’re using Toyplot in a Jupyter notebook! To override this behavior, use the standard target='_blank'
attribute, so that hyperlinked content opens in a separate tab:
[8]:
canvas = toyplot.Canvas(width=600, height=200)
canvas.text(
300,
100,
"See <a target='_blank' href='http://toyplot.readthedocs.org'>Toyplot</a> for details.",
style={"font-size":"16px"},
);
Note that Toyplot hyperlinks are rendered using the CSS steelblue
color by default, but you can customize this by styling the <a> tag. For example, the following styles a hyperlink the same way a traditional web browser would:
[9]:
canvas = toyplot.Canvas(width=600, height=200)
canvas.text(
300,
100,
"See <a target='_blank' style='text-decoration-line: underline;fill: blue' 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.
[10]:
canvas = toyplot.Canvas(width=600, height=200)
canvas.text(300, 100, "3 < 4 & 6 > 5", 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:
[11]:
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:
[12]:
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):
[13]:
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:
[14]:
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:
[15]:
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:
[16]:
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:
[17]:
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:
[18]:
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:
[19]:
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:
[20]:
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:
[21]:
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:
[22]:
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:
[23]:
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:
[24]:
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)
[25]:
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:
[26]:
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