Dynamic SVG Coordinate Space
FREE     Duration: 6:42
Part of Course: Introductory D3 Course
 

Takeaways:

  • The SVG element can be thought of as an SVG Viewport - things within the SVG Viewport's dimensions are visible, things outside of the dimensions are not visible
  • The SVG element dimensions are defined using the attribute value pairs of "height" and "width"
  • D3 Array utilities include d3.min, d3.max, d3.extent, d3.sum, d3.mean, d3.median and others
  • An Accessor function is a function that accesses the content of an object but does not modify that object
  • One way to adjust the SVG coordinate Space is to set the width and height to be that maximum and minimum of the X variables and Y variables
  • SVG Coordinate Space Margins are used in D3 examples to make sure that parts of the data visualization marks are not cut off because of the SVG Viewport edges

Resources:
Transcript:

Dynamic SVG Coordinate Space

SVG Coordinate Space Revisited

<svg> ... </svg>

The SVG element is commonly referred to as the SVG Viewport.

Things within the SVG Viewports dimension's are visible

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

<svg width="200" height="200">
    <circle cx="25" cy="25" r="25" />
</svg>

HIGHLIGHT SVG width in green

The SVG width and height are the width and height of the view port

This setup tells the browser to set aside an area of 200 pixels by 200 pixels in the document for SVG Graphics.

This way the browser knows how to to place the rest of the elements in the HTML document.

This setup also tells the browser that the interior of the SVG viewport is 200 units wide by 200 units tall.

Outside: 200 x 200 pixels

Inside : 200 x 200 units


Why the difference?

Two reasons -

One - SVG is based on vector graphics so it's not pixels inside

Two - Units depend on the graphic that you are creating.

<svg> ... </svg>


So for SVG

When we talk about the viewport and what is inside, we will be talking about units.

<svg width="200" height="200">

<svg width="400" height="600">

<svg width="100" height="100">

<svg width="960" height="500">

The width and height that we choose are completely under our control.

We can make it as big or small as we want.

There are two ways to think about how to choose the dimensions of the SVG Viewport.

One - is to let the data tell you how big to make it.

Two - is to choose hard numbers and to scale the data up or down accordingly.

In this video we look at way number one - letting the data tell us how big to make the SVG Viewport.



Basic D3 Array Utilities Revisited

Basic D3 Array Utilities

  • d3.min
  • d3.max
  • d3.extent
  • d3.sum
  • d3.mean
  • d3.median

These basic D3 Array utilities told us the min, max, extent, sum, mean and median of JavaScript Arrays.

Accessor Function

myData = [ { "x":05, "y":30   },{ "x": 75, "y":30  },
           { "x":75, "y":90   },{ "x":150, "y":90  },
           { "x":150, "y":150 },{ "x":190, "y":150 }];

function(d) { return d.x; }

An accessor function is a function that accesses the contents of an object but does not modify that object.

The anonymous function on the screen is an accessor function.

It can be applied to each JSON object in the myData array to access the contents of the "x" key or "y" key


Basic D3 Array Utilities

  • d3.min
  • d3.max
  • d3.extent
  • d3.sum
  • d3.mean
  • d3.median

myData = [ { "x":05, "y":30   },{ "x": 75, "y":30  },
           { "x":75, "y":90   },{ "x":150, "y":90  },
           { "x":150, "y":150 },{ "x":190, "y":150 }];

What we did not cover before was that you could pass an Associative Arrays to these functions as long as you provided an accessor function.

Which means that we can pass the myData array of JSON objects and it will give us the right answer.


Let's look at an examples of the d3.min, d3.max, and d3.extent in the JavaScript Console

First, we define the myData array which is full of JSON objects.

var myData = [ { "x":05, "y":30   },{ "x": 75, "y":30  },
               { "x":75, "y":90   },{ "x":150, "y":90  },
               { "x":150, "y":150 },{ "x":190, "y":150 }];

BROWSER - Cut in, when this is already typed and press enter.

BROWSER - Click into the first object in the array to see to see the X, Y and Object

BROWSER - HIGHLIGHT the x, y and proto object.

Each JSON object contains an X and Y coordinate.


Next, let's call the Basic D3 Array Utility d3.min on the myData array

Remember - for an Associative Array, we have to pass in an accessor function

d3.min(myData, function(d) { return d.x; });

As you can see, this returned the number 5

Which is the min x of all the JSON Objects in the myData Array.

One way to think about this is as follows:

One - D3 iterates through all of the JSON objects

Two - For each object, it pulls out the relevant data using the accessor function

Three - Each time it looks at a new object, it compares the new data to the running minimum

and Four - when it runs out of objects, it returns what was the minimum number at the end.


Next, let's call the Basic D3 Array Utility d3.Max on the myData array

Remember - for an Associative Array, we have to pass in an accessor function

This time, we want to look at the Y key.

d3.max(myData, function(d) { return d.y; });

As you can see, this returned the number 150

Which is the max y of all the JSON Objects in the myData Array.

One way to think about this is as follows:

One - D3 iterates through all of the JSON objects

Two - For each object, it pulls out the relevant data using the accessor function

Three - Each time it looks at a new object, it compares the new data to the running maximum

Four - when it runs out of objects, it returns what was the maximum number at the end.


Next, let's call the Basic D3 Array Utility d3.Extent on the myData array

Remember - for an Associative Array, we have to pass in an accessor function

This time, we want to look at the X key.

d3.extent(myData, function(d) { return d.x; });

As you can see, this returned the array containing the minimum 5 and the maximum 190

Which is the min and max x of all the JSON Objects in the myData Array.



Adjusting SVG Coordinate Space

<svg width="200" height="200">....</svg>

<svg width="400" height="600">....</svg>

<svg width="100" height="100">....</svg>

<svg width="960" height="500">....</svg>

One way to set the correct width and height of the SVG Coordinate Space is to set the width to the max x and the height to the max y.

We just saw how we could do this with with the D3 Array utilities.

myData = [....];

maxX = d3.max(myData, function(d) { return d.x; })

maxY = d3.max(myData, function(d) { return d.y; })

d3.select("body")
    .append("svg")
    .attr("width" , maxX)
    .attr("height", maxY);

Which means we could rewrite the D3 creation of the SVG Coordinate space as follows.

First, we define the myData array which is full of JSON objects.

var myData = [ { "x":05, "y":30   },{ "x": 75, "y":30  },
               { "x":75, "y":90   },{ "x":150, "y":90  },
               { "x":150, "y":150 },{ "x":190, "y":150 }];

BROWSER - Cut in, when this is already typed and press enter.


Each JSON object contains an X and Y coordinate.


Next we get the maxX

var maxX = d3.max(myData, function(d) { return d.x; });

maxX;

BROWSER - Cut in, when this is already typed and press enter.


This gives us the maxX variable which we will use for the width.

var maxY = d3.max(myData, function(d) { return d.y; });

maxY;

BROWSER - Cut in, when this is already typed and press enter.


This gives us the maxY variable which we will use for the height.

var svgViewport = d3.select("body").append("svg").attr("width", maxX).attr("height", maxY);

BROWSER - Cut in, when this is already typed and press enter.


This created the SVG Viewport that contains the exact dimensions we need according to the data.



SVG Coordinate Space Margins

https://d3js.org/

Basic Examples

If you look at the D3 website examples and look at the basic examples.

You often see the margins being defined as follows.

As well as the SVG Container being defined as follow.


Why margins?

The reason you apply margins is to leave room around the data points.

var myData = [ { "x":05, "y":30   },{ "x": 75, "y":30  },
               { "x":75, "y":90   },{ "x":150, "y":90  },
               { "x":150, "y":150 },{ "x":190, "y":150 }];

// maxX = 190

// maxY = 150

In this instance, the max X is 190 and max y is 150.

If we were drawing circles around each of these points

This would be the CX and CY of the circle.

If we had a radius of 25, we would only be able to see 1/4 of the circle.

Because the center of the circle would be the very lower right hand corner.

For this reason, margins are typically specified.


Let's look at what happens in the JavaScript Console.


First, we define the myData array which is full of JSON objects.

var myData = [ { "x":05, "y":30   },{ "x": 75, "y":30  },
               { "x":75, "y":90   },{ "x":150, "y":90  },
               { "x":150, "y":150 },{ "x":190, "y":150 }];

BROWSER - Cut in, when this is already typed and press enter.


Each JSON object contains an X and Y coordinate.

var maxX = d3.max(myData, function(d) { return d.x; });

var maxY = d3.max(myData, function(d) { return d.y; });

BROWSER - Cut in, when this is already typed and press enter.


Then, we define the maxX and maxY data from the objects.

var svgViewport = d3.select("body").append("svg").attr("width", maxX).attr("height", maxY);

BROWSER - Cut in, when this is already typed and press enter.


Next, we create the svgViewport based on the max x and max y data points.

var circles = svgViewport.selectAll("circle").data(myData).enter().append("circle");

BROWSER - Cut in, when this is already typed and press enter.


Then we select all the circle elements, bind the data, choose the enter selection and append circles

var circleAttributes = circles.attr("cx", function(d,i) { return d.x;})
    .attr("cy", function(d,i) { return d.y;})
    .attr("r",  "10");

BROWSER - Cut in, when this is already typed and press enter.

Finally, we add attributes to each circle.


As you can see, Some of the circles were cut off because we did not specify margins.

Which is why you need to specify margins when making data visualization.

<< Back To D3 Screencast and Written Tutorials Index