Archives

Month: October 2016

  • Sol LeWitt’s Wall Drawing 289 with D3.js Transitions


    Aren’t familiar with Sol LeWitt or his art? Read this.

    Wall Drawing 289: A 6-inch (15 cm) grid covering each of the four black walls. White lines to points on the grids. Fourth wall: twenty-four lines from the center, twelve lines from the midpoint of each of the sides, twelve lines from each corner. (The length of the lines and their placement are determined by the drafter.)

    Here is a gfycat preview:

    Open my D3 implementation of Wall Drawing 289 in a new window →

    It is also available as a block.

    Design Details

    • LeWitt’s instructions dictate that the lines are to go to a point on a 6-inch grid. I didn’t lay out a grid first, but I did round the random line ending points to they land on whole numbers.
    • I chose to conform this to the size of the viewer’s window and have each display randomly generated, so each viewer will have a unique experience.
    • Just as the size of the wall this piece was implemented on determined the density of the lines, the size of the window will determine the density. You can try out different densities by resizing the screen. The illustration will rebuild after you resize the window.
    • I tried drawing each line individually in time like I did with number 86, but it looked so much cooler with all lines coming in at one from their starting points. The viewer gets the understanding of where each line starts and the randomly-generated end points fulfill the requirement of the length and location of the lines being determined by the drafter.

    Technical Details

    • The midpoints are determined by the size of the window.
    • Each viewer gets a unique experience because the length of the lines is set at random on each page load.

    The underlying data set

    So much of implementing these drawings with D3.js rely on making a solid, usable data set to join elements with. (After all, D3 stands for data-driven-documents.) Creating these data sets is where I spend most of my time. Once I’ve created them, everything else follows pretty quickly. Here is the function I wrote to create the underlying data set on this piece:

    function getRandomArbitrary(min, max) {   return Math.round(Math.random() * (max - min) + min); }  function lineData() { 	var data = new Array(); 	var id = 1;	 	var ww = window.innerWidth; 	var wh = window.innerHeight; 	var numLines = 12; 	// iterate for cells/columns inside rows 		for (var center = 0; center < numLines * 2; center++) {	 				data.push({ 				id: id, 				class: "center", 				x1: ww/2, 				y1: wh/2, 				x2: getRandomArbitrary(0, ww), 				y2: getRandomArbitrary(0, wh) 			}) 			id++; 		} 				 		for (var topleft = 0; topleft < numLines; topleft++) {	 				data.push({ 				id: id, 				class: "topleft", 				x1: 0, 				y1: 0, 				x2: getRandomArbitrary(0, ww), 				y2: getRandomArbitrary(0, wh) 			}) 			id++; 		}  		for (var topright = 0; topright < numLines; topright++) {	 				data.push({ 				id: id, 				class: "topright", 				x1: ww, 				y1: 0, 				x2: getRandomArbitrary(0, ww), 				y2: getRandomArbitrary(0, wh) 			}) 			id++; 		}  		for (var bottomright = 0; bottomright < numLines; bottomright++) {		 				data.push({ 				id: id, 				class: "bottomright", 				x1: ww, 				y1: wh, 				x2: getRandomArbitrary(0, ww), 				y2: getRandomArbitrary(0, wh) 			}) 			id++; 		}  		for (var bottomleft = 0; bottomleft < numLines; bottomleft++) {		 				data.push({ 				id: id, 				class: "bottomleft", 				x1: 0, 				y1: wh, 				x2: getRandomArbitrary(0, ww), 				y2: getRandomArbitrary(0, wh) 			}) 			id++; 		}  		for (var middleleft = 0; middleleft < numLines; middleleft++) {		 				data.push({ 				id: id, 				class: "middleleft", 				x1: 0, 				y1: wh/2, 				x2: getRandomArbitrary(0, ww), 				y2: getRandomArbitrary(0, wh) 			}) 			id++; 		}  		for (var middleright = 0; middleright < numLines; middleright++) {		 				data.push({ 				id: id, 				class: "middleright", 				x1: ww, 				y1: wh/2, 				x2: getRandomArbitrary(0, ww), 				y2: getRandomArbitrary(0, wh) 			}) 			id++; 		}   		for (var middletop = 0; middletop < numLines; middletop++) {		 				data.push({ 				id: id, 				class: "middletop", 				x1: ww/2, 				y1: 0, 				x2: getRandomArbitrary(0, ww), 				y2: getRandomArbitrary(0, wh) 			}) 			id++; 		}  		for (var middlebottom = 0; middlebottom < numLines; middlebottom++) {		 				data.push({ 				id: id, 				class: "middlebottom", 				x1: ww/2, 				y1: wh, 				x2: getRandomArbitrary(0, ww), 				y2: getRandomArbitrary(0, wh) 			}) 			id++; 		} 	return data; } 

    Transition

    I handled the transition by first defining the lines as starting and ending at the same set of coordinates, then doing a delayed transition to their real end points:

    var line = svg.selectAll(".rand") 	.data(lineData) 	.enter().append('line') 	.attr("class", function(d) { return d.class; }) 	.attr("id", function(d) { return d.id; }) 	.attr("x1", function(d) { return d.x1; } ) 	.attr("y1", function(d) { return d.y1; }) 	.attr("x2", function(d) { return d.x1; } ) 	.attr("y2", function(d) { return d.y1; }).transition().duration(3000) 	.attr("x2", function(d) { return d.x2; }) 	.attr("y2", function(d) { return d.y2; });

    Rebuilding on screen resize

    When you resize the screen, the svg gets destroyed and then rebuilt based on the new screen size. New midpoints are calculated and new ending points for each other lines are calculated. Here is the function I use to handle that. It is the same thing I used on 86 and on my Jekyll posts heatmap calendar. I wrapped the D3 instructions in its own function, called that function on first load, then wrote a function to destroy the svg when the screen is resized and reexecute the D3 instructions after the screen resize ends. I’m sure it can be done with regular javascript, but jQuery makes this kind of thing fast and easy:

    // run on first load sol289();  $(window).resize(function() {     if(this.resizeTO) clearTimeout(this.resizeTO);     this.resizeTO = setTimeout(function() {         $(this).trigger('resizeEnd');     }, 500); });  //resize on resizeEnd function $(window).bind('resizeEnd', function() { 	 d3.selectAll("svg").remove(); 	 sol289(); });

    Want to dig in a little further? Check out my implementation and view source. All of the specs are there.

    Tools Used

    • D3.js – The D3.js library is well-suited to Sol LeWitt’s early works. D3’s foundational principle of joining data to elements is easy to apply to LeWitt’s symmetrical objects.
    • jQuery – I’m using jQuery to detect changes in the window size and trigger removing & rebuilding the visualization.

    Inspiration and References

    Detail shot of the version on display at MASSMoCA: Detail shot of the version on display at MASSMoCA:

  • Sol LeWitt’s Wall Drawing 86 with D3.js Transitions


    Aren’t familiar with Sol LeWitt or his art? Read this.

    Wall Drawing 86: Ten thousand lines about 10 inches (25 cm) long, covering the wall evenly.

    Here is a gfycat preview:

    Open my D3 implementation of Wall Drawing 86 in a new window →

    It is also available as a block.

    Design Details

    • LeWitt’s instructions dictate 10,000 10-inch lines on a wall. Since computer screens are much smaller, I chose 1,000 lines that are roughly 141 pixels long (100*sqrt(2)).
    • I chose to conform this to the size of the viewer’s window and have each display randomly generated, so each viewer will have a unique experience.
    • Just as the size of the wall this piece was implemented on determined the density of the lines, the size of the window will determine the density. You can try out different densities by resizing the screen. The illustration will rebuild after you resize the window.
    • LeWitt’s instructions indicate that the wall should be evenly covered. Due to randomly generating the starting and ending values of the points, I couldn’t figure out a way to have even distribution without having some lines go outside of the edges of the window. If I kept every point inside the window, a space around the edges emerges where the lines are not as evenly distributed. I decided it was better to have lines going over the edge than an uneven distribution.

    Technical Details

    Making equal length line segments

    Making equal length line segments turned out to be a little more difficult than I anticipated. Lines are drawn by picking two sets of (x,y) coordinates and connecting them. If you leave this 100% random, you’ll get lines of all different lengths and slopes. If you want lines of equal lengths and different slopes, however, you need to be a little more crafty.

    I came up with two ways of doing it: 1) Pick a random slope and fixed length, then solve a series of rearranged quadratic equations derived from the point-slope form of a line and the distance formulaArchived Link. 2) Derive the second set of coordinates based off of a fixed formula with the first coordinates. This will result in lines having all the same slope initially. Then apply a transform to rotate the lines about their midpoints by a random angle.

    Number two was faster and simpler for me to implement, so I went that route.

    The underlying data set

    So much of implementing these drawings with D3.js rely on making a solid, usable data set to join elements with. (After all, D3 stands for data-driven-documents.) Creating these data sets is where I spend most of my time. Once I’ve created them, everything else follows pretty quickly. Here is the function I wrote to create the underlying data set on this piece:

    function lineData() { 	function getRandomArbitrary(min, max) { 	  return Math.random() * (max - min) + min; 	} 	var data = new Array(); 	var id = 1;	 	var ww = window.innerWidth; // Width of the window viewing area 	var wh = window.innerHeight; // Height of the window viewing area 	// iterate for cells/columns inside rows 		for (var line = 0; line  1000; line++) {  // 1000 lines 			var x1 = getRandomArbitrary(-100, ww); // initial points can start 100px off the screen to make even distribution work 			var y1 = getRandomArbitrary(-100, wh);		 				data.push({ 				id: id, // For identification and debugging 				x1: x1, 				y1: y1, 				x2: x1 + 100, // Move 100 to the right 				y2: y1 + 100, // Move 100 up 				rotate: getRandomArbitrary(0, 360) // Pick a random angle between 0 and 360 			}) 			id++; // Increment the ID 		} 	return data; } 

    Rotation

    To make the rotation work without affecting the even distribution of the lines, I needed to rotate them around their midpoints. Otherwise they’d be rotated around (0,0), which puts lines out of the viewing area at large angles. I essentially used the midpoint formula to calculate the midpoints. I simplified since I know the length of each line. Here is the tranform attribute I applied:

    .attr("transform", function(d) { return "rotate(" + d.rotate + " " + (d.x1 + 50) + " " + (d.y1 + 50) + ")";})

    Transition

    I handled the transition by first defining the lines as starting and ending at the same set of coordinates, then doing a delayed transition to their real end points. I applied the rotation before the transition so that the lines would appear to grow, but not rotate. To create the effect of the lines being drawn one by one in real-time, I added a delay function with an index. With a 20 millisecond delay and 1000 lines, it takes about 20 seconds to complete:

    var line = svg.selectAll("line") 	.data(lineData) 	.enter().append('line') 	.attr("id", function(d) { return d.id; }) 	.attr("x1", function(d) { return d.x1; }) 	.attr("y1", function(d) { return d.y1; }) 	.attr("transform", function(d) { return "rotate(" + d.rotate + " " + (d.x1 + 50) + " " + (d.y1 + 50) + ")";}) 	.attr("x2", function(d) { return d.x1; }) 	.attr("y2", function(d) { return d.y1; }).transition().delay(function(d,i){ return 20*i; }).duration(750) 	.attr("x2", function(d) { return d.x2; }) 	.attr("y2", function(d) { return d.y2; });

    Want to dig in a little further? Check out my implementation and view source. All of the specs are there.

    Tools Used

    • D3.js – The D3.js library is well-suited to Sol LeWitt’s early works. D3’s foundational principle of joining data to elements is easy to apply to LeWitt’s symmetrical objects.
    • jQuery – I’m using jQuery to detect changes in the window size and trigger removing & rebuilding the visualization.

    Inspiration and References

    Detail shot of the version on display at MASSMoCA: Detail shot of the version on display at MASSMoCA:

  • Sol LeWitt’s Wall Drawing 87 with D3.js Transitions


    Aren’t familiar with Sol LeWitt or his art? Read this.

    Wall Drawing 87: A square divided horizontally and vertically into four equal parts, each with lines and colors in four directions superimposed progressively.

    Since this is so close to 56 (which I’ve already done), I wanted to add an additional element to challenge myself and learn something: Transitions. The difference between the two is the separate color for each line direction, which ended up lending itself to transitions nicely.

    Adding the color and transitions into this one made me change my mental model for how I’m building these implementations. I was able to complete the first three I picked (56, 11, and 391) with only four elements inside the SVG: One for each quadrant. This is because I was able to make a single pattern for each quadrant (even though it appears that there are four sets lines are going in different directions) and have the patterns match up with the other quadrants. Textures.js doesn’t support making line-based patterns with more than one line color, so I needed to find a different approach.

    The solution turned out to solve my mental block for both the colors and the transitions. I started to doodle this drawing in a journal and realized that I did each line direction one whole layer at a time, layering each one on top of the others. Yet, I had been trying to cram all four directions into a single layer here on the web. So, I modified my D3 code to join more elements with different classes to the same underlying grid array to simulate the effect of layering the different colors.

    Then, I added a transition() and a delay() to each “layer” so that the viewer can also experience and take notice of the intentional layering of this piece.

    There is definitely more I can do with transitions. This is just the beginning for me. I achieved what I wanted with this piece, so I’m going to move on to others and continue exploring and learning how to implement transitions.

    Here is an image preview. Click on it to see the D3.js version:

    Open my D3 implementation of Wall Drawing 87 in a new window →

    It is also available as a block.

    Design Details

    • While any interpretation of Sol LeWitt’s instructions is technically valid as long as each statement is accounted for, I feel a responsibility to make my implementation beautiful, clean, and symmetrical.
    • When he says “four directions”, the common interpretation is 0 degrees, 90 degrees, 45 degrees, and 135 degrees.
    • On a wall, the dimensions are dictated by the physical size of the wall itself. On the web, since windows change size so easily and the proportions of the art are constant, I chose to define a fixed size for this piece.

    Color Palette

    Unlike the earlier colored versions that used grey, yellow, red, and blue, this uses Sol Lewitt’s second color palette of choice: grey, yellow, tan, and reddish-brown.

    Concord

    cmyk:
    44 36 33 1 1.00
    rgba:
    124 124 124 1.00
    hex:
    #7C7C7C

    Download color

    Sweet Corn

    cmyk:
    3 4 45 0 1.00
    rgba:
    254 238 136 1.00
    hex:
    #FEEE88

    Download color

    Jaffa

    cmyk:
    2 48 67 1 1.00
    rgba:
    222 123 74 1.00
    hex:
    #DE7B4A

    Download color

    Hawaiian Tan

    cmyk:
    7 56 96 19 1.00
    rgba:
    159 82 25 1.00
    hex:
    #9F5219

    Download color

    Tools Used

    • D3.js – The D3.js library is well-suited to Sol LeWitt’s early works. D3’s foundational principle of joining data to elements is easy to apply to LeWitt’s symmetrical objects.
    • Textures.js – I’m using this library to quickly create the background patterns. It plays very well with D3.js, which is why I chose it. It is a great little library that is very easy to use. It has some limitations around the edges, but the alternative is writing my own SVG paths for the patterns, which I didn’t want to do at this time.

    Technical Details

    • I repurposed some of the data-generating code for the squares from my Let’s Make a Grid with D3.js post.
    • One svg element with two groups and 8 rect elements in each group.
    • Basic transition() and delay() functions applied to animate the layers.
    • Want to dig in a little further? Check out my implementation and view source. All of the D3 specs are there.

    Inspiration and References

    Detail shot of the version on display at MASSMoCA: Detail shot of the version on display at MASSMoCA:

    Wide shot of the version on display at MASSMoCA (Poor lighting): Wide shot of the version on display at MASSMoCA:

  • Praxis Data Workshop – Telling a Stronger Story with Data Visualization


    On October 13 I ran a data-related workshop for the Praxis community.

    I split the talk up into two parts:

    1. How you can apply the basic concepts of data analysis to your career, whether it be sales, marketing, shipping, coaching, cooking, management, etc. These techniques will help you tell a better story, be more convincing, and become more effective at your job.
    2. An introduction to visualizing data and information, including some tools, resources, and inspiration to get you started. If you are interested in data visualization, think of this as a jumping-off point.

    The Slides

    Praxis Data Workshop - Telling a Stronger Story with Data Visualization

    Download my slides without my talking notes ↓

    Download my slides with my talking notes ↓

    The Video

    Thanks to TK Coleman for asking me to do the worksop and for recording the video!

    Examples mentioned

    Resources mentioned

    Books Mentioned

    Tools

    • Excel – Basic, but a great first stop for exploring and sorting your data set.
    • Vega, Lyra, and Voyager – Open source data tools for exploration and visualization
    • Tableau Public – Free version of Tableau, one of the top, easy-to-use visualization software on the market
    • RAW – Makes using complex D3 chart types easy to use.
    • Carto – Free maps without needing coding knowledge!
    • Chart.js – Easy, pre-packaged interactive chart types. Need to know some JavaScript.
    • D3.js – One of the top DOM manipulation/data visualization libraries
    • Paper.js – An open source vector graphics scripting framework
    • R – Popular data science language
    • Python’s Pandas – Popular data science library for Python
    • Matplotlib – Popular graphing library for Python
    • Reporter app – Personal data collection app

    PDP ideas

    Here are a few ideas on how Praxis participants can incorporate data analysis and visualization into their PDPs (personal development plans):

    1. Read How To Measure Anything, Lean Analytics, or How to Lie with Statistics and write a review on both Amazon and your blog.
    2. Pick 1-2 metrics in your personal life and collect data on them for two weeks. After two weeks, write a blog post explaining some trends you see, explaining the outliers, and visualizing the data in at least two ways. A few ideas: Sleep time and quality, caffeine intake and focus, time spent on social media, counts of something you produce at work, pages of books read, how many times you say “thank you” to someone, how many blog posts you write, etc. Check Dear Data for ideas. Reporter app is useful for collection.
    3. Pick 1-2 metrics that your business partner is currently tracking. Analyze them and write up the results. Make a presentation for your managers.
    4. Find a data set of any size and write a blog post framing it in three different ways.
    5. Get sales or marketing data (or something that includes location data related to your business) from your business partner and map it with Carto. Make it private so you aren’t sharing private data. Write a blog post about what you found.
    6. Research 3 different chart types and write explanatory blog posts on how they are used and give some examples of what to visualize with them.
    7. Identify something you wanted to track but didn’t and find a proxy for it.
    8. Pick something that interests you and build a small visualization with Chart.js or D3.js. Write a blog post explaining what is interesting. Guide us through it.
    9. Dig in to an open data set, find some outliers, and frame some comparisons. Write it up in a blog post.
    10. Dig in to an open data set and make a visualization for a small, interesting facet of it. Write it up in a blog post.
    11. For sales people: Does one region do spectacularly well or spectacularly poorly? Dig in to why and write it up.
    12. For marketers: Are certain channels performing better than others? Dig in to why and write it up.
    13. Look into your business partner’s revenue over time. Do you find any interesting trends? Do some research and write them up.
    14. Come up with an idea on what your team can track over the next few months to improve your efficiency/deliverables. Pitch the team on what to do, why they need to do it, and how you will use the data at the end of the quarter.
  • Sol LeWitt’s Wall Drawing 391 with D3.js


    Aren’t familiar with Sol LeWitt or his art? Read this.

    Wall Drawing 391: Two-part drawing. The two walls are each divided horizontally and vertically into four equal parts. First wall: 12-inch (30 cm) bands of lines in four directions, one direction in each part, drawn in black India ink. Second wall: Same, but with four colors drawn in India ink and color ink washes.

    391 is one of the iconic images that people instantly recognize as a Sol LeWitt. After making the simple line drawings, I wanted to try something more comfortable and a little more complex. Now that I’ve created this, I could translate it into #419. Perhaps I will do this in the future.

    Here is an image preview. Click on it to see the D3.js version:

    Open my D3 implementation of Wall Drawing 391 in a new window →

    Design Decisions

    • While any interpretation of Sol LeWitt’s instructions is technically valid as long as each statement is accounted for, I feel a responsibility to make my implementation beautiful, clean, and symmetrical.
    • Besides for this being a commonly recognized piece where it would be noticeable that I deviated from the norm, when I made this I was still unsure of myself. I wanted to see if I could translate what I saw in person to D3.js as closely as possible. I think it turned out pretty well.
    • When Sol LeWitt says “four colors”, the regular interpretation is black/dark gray, yellow, red, orange. When he says “four directions”, the common interpretation is 0 degrees, 90 degrees, 45 degrees, and 135 degrees.
    • Sol LeWitt dictated a 12-inch bands. Since inches are fuzzy on the web and regular screens aren’t as wide as walls, I scaled things down and translated it into pixels. I kept with the spirit and chose a multiple of 12: 36 pixel bands.
    • On a wall, the dimensions are dictated by the physical size of the wall itself. On the web, since windows change size so easily and the proportions of the art are constant, I chose to define a fixed size for this piece.

    Color Palette

    Onyx

    cmyk:
    78 72 66 74 1.00
    rgba:
    17 17 17 1.00
    hex:
    #111111

    Download color

    Sunglow

    cmyk:
    1 14 75 1 1.00
    rgba:
    252 202 66 1.00
    hex:
    #FCCA42

    Download color

    Alizarin Crimson

    cmyk:
    1 87 61 1 1.00
    rgba:
    223 34 62 1.00
    hex:
    #DF223E

    Download color

    Navy Blue

    cmyk:
    71 41 0 0 1.00
    rgba:
    16 105 213 1.00
    hex:
    #1069D5

    Download color

    Tools Used

    • D3.js – The D3.js library is well-suited to Sol LeWitt’s early works. D3’s foundational principle of joining data to elements is easy to apply to LeWitt’s symmetrical objects.
    • Textures.js – I’m using this library to quickly create the background patterns. It plays very well with D3.js, which is why I chose it. It is a great little library that is very easy to use. It has some limitations around the edges, but the alternative is writing my own SVG paths for the patterns, which I didn’t want to do at this time.

    Technical Details

    • I repurposed some of the data-generating code for the squares from my Let’s Make a Grid with D3.js post.
    • This is two SVGs with two groups each (one for each row) and two rect elements in each group (one for each quadrant). The only difference between the left and right SVG squares is the color.
    • The stripes are singular path fills in each square. There is only one pattern per quadrant here because this piece has simple, non-overlapping colors.
    • Want to dig in a little further? Check out my implementation and view source. All of the D3 specs are there.

    What I learned

    • There are tradeoffs to using libraries to generate patters for you. At the width of the squares I’ve specified here, the size of the pattern should be sqrt(2) times the size of the vertical one. When I run those calculations and set the diagonal patterns as such, the right one lines up but the left one is shifted too far up. I ended up finding a middle ground, but the stroke size of the bottom ones aren’t exactly 36 pixels wide. They are 37 pixels wide. That is the price I pay for using a library. I’ll learn to write my own SVG patterns in the future.
    • Many interpretations of Sol LeWitt’s directions (including ones he oversaw the installation of) are very geometric and symmetrical.

    Inspiration and References

    Wide shot of the version on display at MASSMoCA: Wide shot of the version on display at MASSMoCA:

  • Sol LeWitt’s Wall Drawing 11 with D3.js


    Aren’t familiar with Sol LeWitt or his art? Read this.

    Wall Drawing 11: A wall divided horizontally and vertically into four equal parts. Within each part, three of the four kinds of lines are superimposed.

    Wall Drawing 11 is remarkably close to Wall Drawing 56, which is the first one I implemented. I discovered that with only a few changes (width, height, and pattern direction) I could turn my code for 56 into 11.

    Open my D3 implementation of Wall Drawing 11 in a new window →

    Design Decisions

    • While any interpretation of Sol LeWitt’s instructions is technically valid as long as each statement is accounted for, I feel a responsibility to make my implementation beautiful, clean, and symmetrical.
    • There are other valid layouts of this piece (the patterns could be in different directions as long as you use three), but I decided to implement the popularly known configuration currently on display at MASSMoCA. I will stray from this path later on in the project.
    • I reused most of the foundation I laid with Wall Drawing 56. I chose to change the dimensions to a rectangle to better fill the page and to differentiate it. A rectangle also stays closer to the version of 11 at MASSMoCA than a square.

    Tools Used

    • D3.js – The D3.js library is well-suited to Sol LeWitt’s early works. D3’s foundational principle of joining data to elements is easy to apply to LeWitt’s symmetrical objects.

    • Textures.js – I’m using this library to quickly create the background patterns. It plays very well with D3.js, which is why I chose it. It is a great little library that is very easy to use. It has some limitations around the edges, but the alternative is writing my own SVG paths for the patterns, which I didn’t want to do at this time.

    Technical Details

    • I reused most of the foundation I laid with Wall Drawing 56.
    • I changed the width, height, and starting point of each quadrant to make a rectangle instead of a square.
    • Want to dig in a little further? Check out my implementation and view source. All of the D3 specs are there.

    What I learned

    • I really got the hang of setting up patterns in multiple directions here and configuring them such that they line up to create a design where the edges meet.
    • Dimensions matter. I started out with this as a square, but I think it fits normal browser windows much better as a rectangle.
    • Reuse bits of code if you can!

    Inspiration and References

    Detail shot of the version on display at MASSMoCA: Detail shot of the version on display at MASSMoCA

    Wide shot of the version on display at MASSMoCA: Wide shot of the version on display at MASSMoCA:

  • Sol LeWitt’s Wall Drawing 56 with D3.js


    Aren’t familiar with Sol LeWitt or his art? Read this.

    Wall Drawing 56: A square is divided horizontally and vertically into four equal parts, each with lines in four directions superimposed progressively.

    Wall Drawing 56 was the first of Sol LeWitt’s wall drawings I tried to implement here on the web. I picked it for its simplicity: A square with four sets of patterns and two colors. I wasn’t sure exactly what interpreting and implementing these would entail, so I wanted something simple and recognizable at first.

    Open my D3 implementation of Wall Drawing 56 in a new window →

    Design Decisions

    • While any interpretation of Sol LeWitt’s instructions is technically valid as long as each statement is accounted for, I feel a responsibility to make my implementation beautiful, clean, and symmetrical.
    • There are other valid layouts of this piece (the patterns could be in a different order depending on where you chose to start), but I decided to implement the popularly known configuration currently on display at MASSMoCA. I will stray from this path later on in the project.
    • On a wall, the dimensions are dictated by the physical size of the wall itself. On the web, since windows change size so easily and the proportions of the art are constant, I chose to define a fixed size for this piece.

    Tools Used

    • D3.js – The D3.js library is well-suited to Sol LeWitt’s early works. D3’s foundational principle of joining data to elements is easy to apply to LeWitt’s symmetrical objects.

    • Textures.js – I’m using this library to quickly create the background patterns. It plays very well with D3.js, which is why I chose it. It is a great little library that is very easy to use. It has some limitations around the edges, but the alternative is writing my own SVG paths for the patterns, which I didn’t want to do at this time.

    Technical Details

    • I repurposed some of the data-generating code for the squares from my Let’s Make a Grid with D3.js post.
    • I had to do a lot of trial-and-error on the width, height, starting points for each quadrant, and pattern size to make sure the patterns turned out clean and symmetrical. If you dig into the javscript, you’ll see odd variable definitions.
    • This is one SVG with two groups (one for each row) and two rect elements in each group (one for each quadrant).
    • The lines/patterns are singular path fills in each square. There is only one pattern per quadrant here because this piece is in black and white.
    • Want to dig in a little further? Check out my implementation and view source. All of the D3 specs are there.

    What I learned

    • In this first implementation I was getting my feet wet with Textures.js. I got a solid understanding of how to define and create patterns with it.
    • When my first cut was pretty rough around the edges (literally, because the patterns had odd spacing), I noticed how precise and clean the other versions I’ve seen are. I now pay special attention to the fine details when evaluating these pieces.

    Inspiration and References

    Detail shot of the version on display at MASSMoCA: Detail shot of the version on display at MASSMoCA

    Wide shot of the version on display at MASSMoCA: Wide shot of the version on display at MASSMoCA: