SVG Text Elements
FREE     Duration: 13:44
Part of Course: Introductory D3 Course
 

Takeaways:

  • One of the most important parts of Data Visualization is text labels and axis
  • SVG provides a keyword for defining a graphics element consistent of text
  • The SVG Text Element phase attributes and properties to indicate things like the font specification, writing directions, and attributes for how to exactly render and paint a character
  • Because SVG Text Elements are rendered using the same rendering methods as the rest of the SVG Graphical Elements, the same coordinate system, transformation, and etc. apply
  • For the SVG Text Element, you need to provide an X coordinate, a Y coordinate, and the text that you want written in the SVG Viewport
  • Because SVG Text Elements are DOM elements, you can use D3 to append SVG Text tags as well as define and update their attribute value pairs
  • Because you can use D3 to append and define the SVG Text tags, it means you can also do it in a data-driven way

Transcript:

SVG Text Elements

SVG Revisited


<svg> ... </svg>

SVG is a Vector Based Graphics system

SVG is a family of specifications for creating vector graphics.

Since Vector Graphics are not created out of pixels, they can be scaled up to larger or smaller sizes without losing image quality.

The SVG system creates DOM objects for each graphical element.

Things within the SVG Viewport dimension's are visible

Things inside the SVG tags though outside the Viewport dimensions are not visible.


<svg width="200" height="200">
    <g>
        <circle cx="20" cy="20" r="20" />
        <circle cx="70" cy="70" r="20" />
    </g>
    <g>
        <rect x="110" y="110" height="30" width="30" />
        <rect x="160" y="160" height="30" width="30" />
    </g>
</svg>

SVG images and their behaviors are defined in XML text files.

Since the DOM includes XML as part of the DOM specification, we can use the DOM to access and update the structure, content and style of SVG Images.

This means that SVG elements can be styled using CSS just like HTML.

So far we have covered the basic shapes that can be made in SVG.

One very important part of Data Visualizations we have not covered yet is text.



SVG Text Elements


[ Image: Text a Graphics Elements ]

Typography is the art and technique of arranging type in order to make language visible.

The arrangement of type involves the selection of typefaces, point size, line length, line spacing, adjusting the spaces between groups of letters and adjusting the space between pairs of letters.

Additionally - color, readability and legibility are important parts of Typography.


[ Image: Scatterplot ]

One of the most important parts of Data Visualization is text labels and axis.

Text labels and axis help to set the ground floor of understanding.

It tells us about scale, about relative scale, and it lets us figure out the space we are operating in.


[ Image: Graphic Without A Scale]

After all, if the graph or visualization is missing text, then it is very hard to read.

This chart could be a great one if we were talking about costs of a business going down.

This chart could be a terrible one if we were talking about the number of kids who receive adequate nutrition.

This chart could be misleading in that amplitude of the Y axis could be statistically insignificant.

This chart could be misleading in that the lowest X and highest X could be millions of years apart where as we only care about hourly increments.

This chart could also be completely wrong if we had asked for a chart about the unemployment rate and this chart was about the number of clowns over the last century.

Without text on the graph or chart, we are operating blind.

Which, as you can imagine, is not the goal of data visualization.


<svg>
    <text ... > ... <text>
</svg>

SVG provides a keyword for defining a graphics element consisting of text.

The SVG Text Element has attributes and properties that indicate things like the font specification, writing direction, and attributes for how to exactly render and paint the characters.

Because SVG Text Elements are rendered using the same rendering methods as the rest of the SVG Graphical Elements, the same coordinate system, transformations and etc apply.


<svg>
    <text x="50" y="50" font-family="sans-serif" font-size="12px" ><text>
</svg>

The SVG Text Element renders the first character at the initial current text position.

This position is defined by the 'x' and 'y' attributes of the SVG Text Element.

This tells us that the text will start to be drawn at point (50, 50), with the font-family sans-serif and with the font-size of "12px".

We can even apply a rotation to each glyph of the text.



Adding SVG Text Elements


<svg>
    <circle cx="20" cy="20" r="20" />
    <text x="50" y="50">Circle<text>
</svg>

Looking at the example again, let's cover how to build the text element.

We compare it with building a circle, something we already know how to do.

First, we need to use the keyword "TEXT", just like the circle uses the keyword "CIRCLE"

Next, we need to define the x and y coordinates of where the graphics element is drawn from.

In the case of the circle, it is the center point.

In the case of the text, it is to the bottom left corner.

The radius tells us how far the circle goes out.

For the text, we do not define this.

It goes out as far as the actual words between the text tags go.


<svg>
    <circle cx="20" cy="20" r="20" />
    <text x="50" y="50">Circle<text>
</svg>

One important thing to notice is that the text keyword has an opening and closing tag.

The text inside of the opening and closing text tags is the actual text that is written out in the SVG image.

This is important to key in mind because so far we have just added attributes and values to the keyword and haven't specified anything inside of the opening and closing tags.


<svg>
    <circle cx="20" cy="20" r="20" fill="purple"/>
    <text x="50" y="50" font-family="sans-serif" font-size="12px" fill="red">Circle<text>
</svg>

Just like we can specify extra attributes to the SVG Circle like the fill color,

We can specify extra attributes to the SVG Text.

The ones we focus on are the font-family, the font-size as well as the Fill.

This tells us that the text will start to be drawn at the point (50, 50), with the font-family sans-serif, with the font-size of "12px", and the fill color of "red".


<!DOCTYPE html>
<html>
    <head><script type="text/javascript" src="d3.v3.min.js"></script></head>
    <body>
        <svg>
            <circle cx="20" cy="20" r="20" fill="purple"/>
            <text x="50" y="50" font-family="sans-serif" font-size="12px" fill="red">Circle<text>
        </svg>
    </body>
</html>

We can thus write an HTML file as follows and the browser will understand it correctly.

When we load this in the browser, we get the following


[ Image: A Purple Circle With Red Text ]

The purple circle shows up as we would now expect.

The red text shows up on the screen and is visible in the developer's tools elements section.

In this way we can add text to our data visualizations to help explain and improve readability and legibility.


<svg>
    <circle cx="20" cy="20" r="20" fill="purple" />
    <text x="50" y="50" font-family="sans-serif" font-size="12px" fill="red">Circle<text>
</svg>

The great thing about SVG is that all of the keyword elements are constructed the same.

There are attributes and their values.

As you can imagine, this makes it familiar, easy and flexible when we go to add text using D3.



D3 and SVG Text Elements


d3.selection.append("circle").attr("cx",20).attr("cy",20).attr("r",20).style("fill","purple");

For SVG Basic shapes, we already know how to add attributes using D3.

Adding attributes and their values to make SVG Text will be the same using D3.


<svg>
    <circle cx="20" cy="20" r="20" fill="purple"/>
    <text x="50" y="50" font-family="sans-serif" font-size="12px" fill="red">circle<text>
</svg>

The one thing we need to cover is how to insert the text into the opening and closing tags.

We need to tell D3 that we want to put the word circle into the SVG Text example on the screen.


d3.selection.text([value])

This is the D3 Text Operator

If a value is specified, then it sets the text content of all the selected elements to the specified value.

If the value is constant, then all the elements are given the same text content.

If the value is a function, then the function is evaluated for each element in order.


<svg>
    <circle cx="20" cy="20" r="20" fill="purple" />
    <text x="50" y="50" font-family="sans-serif" font-size="12px" fill="red">circle<text>
</svg>

Using the D3 Text Operator we can set the text of the SVG Text.

Because the D3 text operator allows for constant values as well as functions that return a value

we can dynamically set the text content of the SVG Text.


Let's take a look at the JavaScript Console to see how this works.


We start with what we already know - how to create SVG circles using D3 and data.

var svgContainer = d3.select("body").append("svg").attr("width","200").attr("height","200");

svgContainer.append("circle").attr("cx",20).attr("cy",20).attr("r",20).style("fill","purple");

BROWSER - Click in Developer's Tools Elements Section to open up the Body & SVG

First we create the SVG Container viewport.

Then we append a circle to the SVG Container

Then we add attributes to the SVG Circle.

In the circle's case we add in the cx, cy, radius and fill to match the example we did above.

The purple circle shows up as expected.


Next, let's start with baby steps, adding the text keyword to the SVG Container.

var svgText = svgContainer.append("text");

Given how we added the circle to the SVG Container, we can append the text keyword to the svgContainer.

BROWSER - Click on the SVG keyword text in the elements section of the chrome web developer tools

The text keyword shows up as the last child element of the SVG Container because we used append.

Notice that the opening tag and closing tag of the Text SVG Element are added for us.


Next, let's add the x and y coordinates.

svgText.attr("x",50).attr("y",50);

This tells the browser that the text will start at the point 50,50.

The text then expands to the right.


Next, using the D3 text operator, let's add the word circle as a string

svgText.text("circle");

BROWSER - Click in Developer's Tools Elements Section to open up the Body & SVG

The word circle now appears on the screen

In the elements section of the developer tools, you can see that the word was added between the tags.

Though it was added with double quotations, the quotations do not show up in the SVG Container.


We can run the same command again with a different word now.

svgText.text("data");

The word data now appears on the screen

In the elements section of the developer tools, you can see that the word was added between tags.

The D3 text command adds in the new text and replaces the old text.


Let's change it back to the word circle and make the X and Y points 20,20.

svgText.attr("x",20).attr("y",20).text("circle");

It is now back to being the word circle.

And the point where the text starts is the center point of the circle.

You can see that the word "Circle" starts at the center point and moves to the right

One other thing to note is that the characters are drawn up in our regular coordinate space, not the SVG Coordinate space.


Let's move it back to the X and Y points 50, 50, so we have a clear view of the text.

svgText.attr("x",50).attr("y",50);

We can see the SVG Text word - circle, clearly.


Now, let's add in the font and font-size.

svgText.attr("font-family","sans-serif").attr("font-size",12);

You can see that the font style changed as did the font-size.

One important thing to keep in mind when using font-families is that if the user does not have that font on their computer, the browser will try to find an equivalent font.

For this reason, it's best to stick to generic font-family names, like the "sans-serif" in this example.


The other thing to notice is that for the font-size we did not specify the units, D3 added the px text for us.

We can add in the px ourselves if we want.

svgText.attr("font-size","30px");

It works the same way.


Next, let's take a look at how we can use data to create SVG Basic Shapes and then to add SVG Text labels to those SVG Basic shapes based on the data.



D3, Data and SVG Text


dataSet = [{"name":"Shanghai"        , "population":18, "rank": 1},
           {"name":"Guangzhou"       , "population":11, "rank":10},
           {"name":"Dongguan"        , "population": 8, "rank":20},
           {"name":"Cairo"           , "population": 7, "rank":30},
           {"name":"Saint Petersburg", "population": 5, "rank":40},
           {"name":"New Taipei"      , "population": 4, "rank":50}];


We define a data set that contains text and numbers.

This data set is based on the top 50 largest cities in the world and their population as measured in Millions according to Wikipedia.

For now, we design a super basic data visualization.

We will create circles where the radius is based on the population in millions.

Then we will add the name of the city next to the circle.

We position the circles on the graph based on their index number.


To the JavaScript Console


First, we define the data set:

dataSet = [{"name":"Shanghai"        , "population":18, "rank": 1},
           {"name":"Guangzhou"       , "population":11, "rank":10},
           {"name":"Dongguan"        , "population": 8, "rank":20},
           {"name":"Cairo"           , "population": 7, "rank":30},
           {"name":"Saint Petersburg", "population": 5, "rank":40},
           {"name":"New Taipei"      , "population": 4, "rank":50}];

We will use this to bind each JSON object to each circle element.


First, we start by adding an SVG Container

var svgContainer = d3.select("body").append("svg").attr("width","200").attr("height","200");

BROWSER - Expand body in elements section

This will contain all of the elements of the data visualization


Next, let's add circles to the svg container and attach the data.

var circles = svgContainer.selectAll("circle").data(dataSet).enter().append("circle");

BROWSER - Expand the SVG in elements section

The circles now appear


We check to make sure the each JSON object was bound to each circle

circles;

BROWSER - Click into the array, then into the first circle, then into the data attribute and highlight the information

The JavaScript object was bound to each circle.

BROWSER - Close all of the arrays.

Next, let's use the object to create the circle attributes.


We position each circle according to it's index, remembering that it is zero-indexed.

The radius of each circle is define by the population.

circles.attr("cx", function(d,i) { return (i+1)*25; })
    .attr("cy", function(d,i) { return (i+1)*25; })
    .attr("r" , function(d,i) { return d.population });

The circles now appear in the SVG Viewport.

The circles decrease in size as they go from left to right and from up to down.

This is expected and it shows what we want - the relative size of the cities.

However, as we covered earlier, without looking directly at the data, it is hard to know which circle pertains to which city.


Let's add SVG Text labels to each circle based on the data.

var circleLabels = svgContainer.selectAll("text").data(dataSet).enter().append("text");

We use the same D3 pattern as before.

Except this time instead of adding SVG Circle elements, we are adding SVG Text elements

We bind the data set in the same way

Each SVG Text Element gets it's own JSON data object


We check to make sure the each JSON object was bound to each text element

circleLabels;

BROWSER - Click into the array, then into the first text, then into the data attribute and highlight the information

The JavaScript object was bound to each text element.

BROWSER - Close all of the arrays.

Next, let's use the object to create the text attributes.


For the text elements, we first have to define where they live

This is defined the same way as the circles, according to the data index

circleLabels.attr("x", function(d,i) { return (i+1)*25; })
    .attr("y", function(d,i) { return (i+1)*25; });

This has given each text element the attribute and value to match the circle.


Now we add the actual text based on the data's city name.

Instead of a hard-coded value, we use an anonymous function to get the name from the data property

circleLabels.text(function(d,i) { return d.name; });

The name of each city appears on top of each circle.

Which solves the issue of knowing which circle pertains to which city.

However, the text is black and the circle is black so it's hard to read.


Let's change the style of the text elements.

circleLabels.style("fill","red");

The red labels is now fully visible.

Well - other than the fact that the text on the last two countries runs out of the SVG Viewport dimensions and are thus partially hidden.

We will come back to that later.


For now, let's change the text of the circle Labels to be the rank.

Because the D3 text operator replaces the text, we can just call the text operator again with a function that returns the rank instead of the name of the city.

circleLabels.text(function(d,i) { return d.rank; });

The rank of each city is now visible and because the font is still red, we can read it.

However, without specifying what the number next to each circle means, we have no way of knowing whether it's a population or rank.


Because we use a function to set the text, we can concatenate a string and a number to set the text to a better explanation

circleLabels.text(function(d,i) { return "rank: " + d.rank; });


And there you have it, we used data to create SVG Basic Shapes and then to added SVG Text labels to those SVG Basic shapes based on the data.

<< Back To D3 Screencast and Written Tutorials Index